From 0f599684c5baf1cdeb933dc4e20a626b6c940378 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 24 Feb 2016 21:26:16 +0000 Subject: [PATCH 001/227] Upload first port --- backup.bat | 31 + backup.lst | 36 + cl_dll/Android.mk | 106 + cl_dll/GameStudioModelRenderer.cpp | 123 + cl_dll/GameStudioModelRenderer.h | 26 + cl_dll/GameStudioModelRenderer_Sample.cpp | 992 +++++ cl_dll/GameStudioModelRenderer_Sample.h | 55 + cl_dll/MOTD.cpp | 165 + cl_dll/StudioModelRenderer.cpp | 1703 ++++++++ cl_dll/StudioModelRenderer.h | 189 + cl_dll/ammo.cpp | 1203 ++++++ cl_dll/ammo.h | 62 + cl_dll/ammo_secondary.cpp | 159 + cl_dll/ammohistory.cpp | 190 + cl_dll/ammohistory.h | 143 + cl_dll/battery.cpp | 138 + cl_dll/camera.h | 24 + cl_dll/cdll_int.cpp | 279 ++ cl_dll/cl_dll.dsp | 624 +++ cl_dll/cl_dll.h | 43 + cl_dll/cl_util.h | 162 + cl_dll/com_weapons.cpp | 277 ++ cl_dll/com_weapons.h | 48 + cl_dll/death.cpp | 303 ++ cl_dll/demo.cpp | 107 + cl_dll/demo.h | 27 + cl_dll/entity.cpp | 980 +++++ cl_dll/ev_common.cpp | 205 + cl_dll/ev_hldm.cpp | 1700 ++++++++ cl_dll/ev_hldm.h | 95 + cl_dll/events.cpp | 23 + cl_dll/eventscripts.h | 73 + cl_dll/flashlight.cpp | 149 + cl_dll/geiger.cpp | 184 + cl_dll/health.cpp | 472 ++ cl_dll/health.h | 127 + cl_dll/hl/hl_baseentity.cpp | 347 ++ cl_dll/hl/hl_events.cpp | 80 + cl_dll/hl/hl_objects.cpp | 90 + cl_dll/hl/hl_weapons.cpp | 1095 +++++ cl_dll/hud.cpp | 587 +++ cl_dll/hud.h | 701 +++ cl_dll/hud_iface.h | 25 + cl_dll/hud_msg.cpp | 120 + cl_dll/hud_redraw.cpp | 342 ++ cl_dll/hud_servers.cpp | 1230 ++++++ cl_dll/hud_servers.h | 41 + cl_dll/hud_servers_priv.h | 98 + cl_dll/hud_spectator.cpp | 1595 +++++++ cl_dll/hud_spectator.h | 132 + cl_dll/hud_update.cpp | 54 + cl_dll/in_camera.cpp | 620 +++ cl_dll/in_defs.h | 31 + cl_dll/input.cpp | 1006 +++++ cl_dll/input_xash3d.cpp | 268 ++ cl_dll/inputw32.cpp | 947 ++++ cl_dll/kbutton.h | 18 + cl_dll/menu.cpp | 186 + cl_dll/message.cpp | 536 +++ cl_dll/overview.cpp | 163 + cl_dll/overview.h | 31 + cl_dll/parsemsg.cpp | 166 + cl_dll/parsemsg.h | 40 + cl_dll/readme.txt | 107 + cl_dll/saytext.cpp | 312 ++ cl_dll/scoreboard.cpp | 603 +++ cl_dll/soundsystem.cpp | 162 + cl_dll/status_icons.cpp | 162 + cl_dll/statusbar.cpp | 265 ++ cl_dll/studio_util.cpp | 251 ++ cl_dll/studio_util.h | 40 + cl_dll/text_message.cpp | 209 + cl_dll/tf_defs.h | 1389 ++++++ cl_dll/train.cpp | 85 + cl_dll/tri.cpp | 128 + cl_dll/util.cpp | 133 + cl_dll/util_vector.h | 121 + cl_dll/view.cpp | 1693 ++++++++ cl_dll/view.h | 15 + cl_dll/wrect.h | 16 + common/beamdef.h | 60 + common/bspfile.h | 246 ++ common/cl_entity.h | 105 + common/com_model.h | 413 ++ common/con_nprint.h | 25 + common/const.h | 780 ++++ common/cvardef.h | 37 + common/demo_api.h | 27 + common/dlight.h | 31 + common/entity_state.h | 186 + common/entity_types.h | 25 + common/event_api.h | 54 + common/event_args.h | 47 + common/event_flags.h | 45 + common/gameinfo.h | 49 + common/hltv.h | 59 + common/ivoicetweak.h | 40 + common/lightstyle.h | 29 + common/mathlib.h | 95 + common/net_api.h | 97 + common/netadr.h | 37 + common/particledef.h | 54 + common/pmtrace.h | 41 + common/qfont.h | 38 + common/r_efx.h | 195 + common/r_studioint.h | 154 + common/ref_params.h | 90 + common/render_api.h | 261 ++ common/screenfade.h | 29 + common/studio_event.h | 27 + common/triangleapi.h | 62 + common/usercmd.h | 39 + common/wadfile.h | 79 + common/weaponinfo.h | 50 + common/wrect.h | 24 + debug.bat | 42 + dlls/AI_BaseNPC_Schedule.cpp | 1514 +++++++ dlls/Android.mk | 134 + dlls/Makefile | 186 + dlls/Wxdebug.cpp | 395 ++ dlls/activity.h | 109 + dlls/activitymap.h | 97 + dlls/aflock.cpp | 910 ++++ dlls/agrunt.cpp | 1186 +++++ dlls/airtank.cpp | 118 + dlls/animating.cpp | 318 ++ dlls/animation.cpp | 525 +++ dlls/animation.h | 47 + dlls/apache.cpp | 1050 +++++ dlls/barnacle.cpp | 449 ++ dlls/barney.cpp | 841 ++++ dlls/basemonster.h | 339 ++ dlls/bigmomma.cpp | 1251 ++++++ dlls/bloater.cpp | 219 + dlls/bmodels.cpp | 958 ++++ dlls/bullsquid.cpp | 1275 ++++++ dlls/buttons.cpp | 1276 ++++++ dlls/cbase.cpp | 774 ++++ dlls/cbase.h | 804 ++++ dlls/cdll_dll.h | 46 + dlls/client.cpp | 1804 ++++++++ dlls/client.h | 65 + dlls/combat.cpp | 1706 ++++++++ dlls/controller.cpp | 1427 ++++++ dlls/crossbow.cpp | 564 +++ dlls/crowbar.cpp | 318 ++ dlls/decals.h | 75 + dlls/defaultai.cpp | 1232 ++++++ dlls/defaultai.h | 98 + dlls/doors.cpp | 1079 +++++ dlls/doors.h | 33 + dlls/effects.cpp | 2268 ++++++++++ dlls/effects.h | 209 + dlls/egon.cpp | 568 +++ dlls/enginecallback.h | 158 + dlls/explode.cpp | 273 ++ dlls/explode.h | 32 + dlls/extdll.h | 88 + dlls/flyingmonster.cpp | 281 ++ dlls/flyingmonster.h | 53 + dlls/func_break.cpp | 1006 +++++ dlls/func_break.h | 74 + dlls/func_tank.cpp | 1039 +++++ dlls/game.cpp | 887 ++++ dlls/game.h | 45 + dlls/gamerules.cpp | 347 ++ dlls/gamerules.h | 360 ++ dlls/gargantua.cpp | 1368 ++++++ dlls/gauss.cpp | 621 +++ dlls/genericmonster.cpp | 140 + dlls/ggrenade.cpp | 488 +++ dlls/globals.cpp | 39 + dlls/glock.cpp | 274 ++ dlls/gman.cpp | 237 + dlls/h_ai.cpp | 199 + dlls/h_battery.cpp | 200 + dlls/h_cine.cpp | 241 ++ dlls/h_cycler.cpp | 471 ++ dlls/h_export.cpp | 69 + dlls/handgrenade.cpp | 233 + dlls/hassassin.cpp | 1015 +++++ dlls/headcrab.cpp | 555 +++ dlls/healthkit.cpp | 264 ++ dlls/hgrunt.cpp | 2517 +++++++++++ dlls/hl.def | 5 + dlls/hl.dsp | 747 ++++ dlls/hornet.cpp | 419 ++ dlls/hornet.h | 58 + dlls/hornetgun.cpp | 305 ++ dlls/houndeye.cpp | 1304 ++++++ dlls/ichthyosaur.cpp | 1108 +++++ dlls/islave.cpp | 866 ++++ dlls/items.cpp | 342 ++ dlls/items.h | 29 + dlls/leech.cpp | 723 ++++ dlls/lights.cpp | 199 + dlls/maprules.cpp | 918 ++++ dlls/maprules.h | 22 + dlls/monsterevent.h | 34 + dlls/monstermaker.cpp | 292 ++ dlls/monsters.cpp | 3448 +++++++++++++++ dlls/monsters.h | 183 + dlls/monsterstate.cpp | 234 + dlls/mortar.cpp | 323 ++ dlls/mp5.cpp | 385 ++ dlls/mpstubb.cpp | 264 ++ dlls/multiplay_gamerules.cpp | 1698 ++++++++ dlls/nihilanth.cpp | 1836 ++++++++ dlls/nodes.cpp | 3641 ++++++++++++++++ dlls/nodes.h | 374 ++ dlls/osprey.cpp | 805 ++++ dlls/pathcorner.cpp | 428 ++ dlls/physcallback.h | 33 + dlls/plane.cpp | 60 + dlls/plane.h | 43 + dlls/plats.cpp | 2285 ++++++++++ dlls/player.cpp | 4791 +++++++++++++++++++++ dlls/player.h | 324 ++ dlls/playermonster.cpp | 122 + dlls/prop.cpp | 1146 +++++ dlls/python.cpp | 320 ++ dlls/rat.cpp | 98 + dlls/roach.cpp | 460 ++ dlls/rpg.cpp | 618 +++ dlls/satchel.cpp | 494 +++ dlls/saverestore.h | 169 + dlls/schedule.cpp | 1514 +++++++ dlls/schedule.h | 290 ++ dlls/scientist.cpp | 1428 ++++++ dlls/scripted.cpp | 1260 ++++++ dlls/scripted.h | 107 + dlls/scriptevent.h | 29 + dlls/shotgun.cpp | 401 ++ dlls/singleplay_gamerules.cpp | 328 ++ dlls/skill.cpp | 47 + dlls/skill.h | 147 + dlls/sound.cpp | 1978 +++++++++ dlls/soundent.cpp | 379 ++ dlls/soundent.h | 95 + dlls/spectator.cpp | 149 + dlls/spectator.h | 27 + dlls/squad.h | 20 + dlls/squadmonster.cpp | 623 +++ dlls/squadmonster.h | 120 + dlls/squeakgrenade.cpp | 601 +++ dlls/stats.cpp | 156 + dlls/subs.cpp | 559 +++ dlls/talkmonster.cpp | 1472 +++++++ dlls/talkmonster.h | 183 + dlls/teamplay_gamerules.cpp | 630 +++ dlls/teamplay_gamerules.h | 57 + dlls/tempmonster.cpp | 117 + dlls/tentacle.cpp | 1044 +++++ dlls/trains.h | 127 + dlls/triggers.cpp | 2434 +++++++++++ dlls/tripmine.cpp | 526 +++ dlls/turret.cpp | 1305 ++++++ dlls/util.cpp | 2543 +++++++++++ dlls/util.h | 548 +++ dlls/vector.h | 112 + dlls/weapons.cpp | 1580 +++++++ dlls/weapons.h | 1015 +++++ dlls/world.cpp | 860 ++++ dlls/wxdebug.h | 137 + dlls/xen.cpp | 584 +++ dlls/zombie.cpp | 346 ++ engine/anorms.h | 177 + engine/cdll_exp.h | 69 + engine/cdll_int.h | 308 ++ engine/custom.h | 93 + engine/customentity.h | 39 + engine/edict.h | 42 + engine/eiface.h | 497 +++ engine/engine.dsp | 621 +++ engine/keydefs.h | 133 + engine/menu_int.h | 188 + engine/physint.h | 114 + engine/progdefs.h | 218 + engine/shake.h | 50 + engine/sprite.h | 102 + engine/studio.h | 369 ++ engine/warpsin.h | 53 + game_shared/bitvec.h | 179 + game_shared/vgui_checkbutton2.cpp | 197 + game_shared/vgui_checkbutton2.h | 101 + game_shared/vgui_defaultinputsignal.h | 39 + game_shared/vgui_grid.cpp | 398 ++ game_shared/vgui_grid.h | 122 + game_shared/vgui_helpers.cpp | 45 + game_shared/vgui_helpers.h | 31 + game_shared/vgui_listbox.cpp | 207 + game_shared/vgui_listbox.h | 115 + game_shared/vgui_loadtga.cpp | 93 + game_shared/vgui_loadtga.h | 22 + game_shared/vgui_scrollbar2.cpp | 310 ++ game_shared/vgui_scrollbar2.h | 62 + game_shared/vgui_slider2.cpp | 436 ++ game_shared/vgui_slider2.h | 67 + game_shared/voice_banmgr.cpp | 197 + game_shared/voice_banmgr.h | 57 + game_shared/voice_common.h | 24 + game_shared/voice_gamemgr.cpp | 274 ++ game_shared/voice_gamemgr.h | 79 + game_shared/voice_status.cpp | 874 ++++ game_shared/voice_status.h | 228 + game_shared/voice_vgui_tweakdlg.cpp | 289 ++ game_shared/voice_vgui_tweakdlg.h | 25 + gnu.txt | 621 +++ make_sdk.bat | 62 + pm_shared/pm_debug.c | 320 ++ pm_shared/pm_debug.h | 23 + pm_shared/pm_defs.h | 221 + pm_shared/pm_info.h | 20 + pm_shared/pm_materials.h | 32 + pm_shared/pm_math.c | 422 ++ pm_shared/pm_movevars.h | 54 + pm_shared/pm_shared.c | 3331 ++++++++++++++ pm_shared/pm_shared.h | 32 + release.bat | 42 + utils/makefont/CreateFont.bat | 2 + xash.dsw | 65 + xash_sdk.dsw | 65 + xash_sdk.lst | 22 + 323 files changed, 141685 insertions(+) create mode 100644 backup.bat create mode 100644 backup.lst create mode 100755 cl_dll/Android.mk create mode 100644 cl_dll/GameStudioModelRenderer.cpp create mode 100644 cl_dll/GameStudioModelRenderer.h create mode 100644 cl_dll/GameStudioModelRenderer_Sample.cpp create mode 100644 cl_dll/GameStudioModelRenderer_Sample.h create mode 100644 cl_dll/MOTD.cpp create mode 100644 cl_dll/StudioModelRenderer.cpp create mode 100644 cl_dll/StudioModelRenderer.h create mode 100644 cl_dll/ammo.cpp create mode 100644 cl_dll/ammo.h create mode 100644 cl_dll/ammo_secondary.cpp create mode 100644 cl_dll/ammohistory.cpp create mode 100644 cl_dll/ammohistory.h create mode 100644 cl_dll/battery.cpp create mode 100644 cl_dll/camera.h create mode 100644 cl_dll/cdll_int.cpp create mode 100644 cl_dll/cl_dll.dsp create mode 100644 cl_dll/cl_dll.h create mode 100644 cl_dll/cl_util.h create mode 100644 cl_dll/com_weapons.cpp create mode 100644 cl_dll/com_weapons.h create mode 100644 cl_dll/death.cpp create mode 100644 cl_dll/demo.cpp create mode 100644 cl_dll/demo.h create mode 100644 cl_dll/entity.cpp create mode 100644 cl_dll/ev_common.cpp create mode 100644 cl_dll/ev_hldm.cpp create mode 100644 cl_dll/ev_hldm.h create mode 100644 cl_dll/events.cpp create mode 100644 cl_dll/eventscripts.h create mode 100644 cl_dll/flashlight.cpp create mode 100644 cl_dll/geiger.cpp create mode 100644 cl_dll/health.cpp create mode 100644 cl_dll/health.h create mode 100644 cl_dll/hl/hl_baseentity.cpp create mode 100644 cl_dll/hl/hl_events.cpp create mode 100644 cl_dll/hl/hl_objects.cpp create mode 100644 cl_dll/hl/hl_weapons.cpp create mode 100644 cl_dll/hud.cpp create mode 100644 cl_dll/hud.h create mode 100644 cl_dll/hud_iface.h create mode 100644 cl_dll/hud_msg.cpp create mode 100644 cl_dll/hud_redraw.cpp create mode 100644 cl_dll/hud_servers.cpp create mode 100644 cl_dll/hud_servers.h create mode 100644 cl_dll/hud_servers_priv.h create mode 100644 cl_dll/hud_spectator.cpp create mode 100644 cl_dll/hud_spectator.h create mode 100644 cl_dll/hud_update.cpp create mode 100644 cl_dll/in_camera.cpp create mode 100644 cl_dll/in_defs.h create mode 100644 cl_dll/input.cpp create mode 100644 cl_dll/input_xash3d.cpp create mode 100644 cl_dll/inputw32.cpp create mode 100644 cl_dll/kbutton.h create mode 100644 cl_dll/menu.cpp create mode 100644 cl_dll/message.cpp create mode 100644 cl_dll/overview.cpp create mode 100644 cl_dll/overview.h create mode 100644 cl_dll/parsemsg.cpp create mode 100644 cl_dll/parsemsg.h create mode 100644 cl_dll/readme.txt create mode 100644 cl_dll/saytext.cpp create mode 100644 cl_dll/scoreboard.cpp create mode 100644 cl_dll/soundsystem.cpp create mode 100644 cl_dll/status_icons.cpp create mode 100644 cl_dll/statusbar.cpp create mode 100644 cl_dll/studio_util.cpp create mode 100644 cl_dll/studio_util.h create mode 100644 cl_dll/text_message.cpp create mode 100644 cl_dll/tf_defs.h create mode 100644 cl_dll/train.cpp create mode 100644 cl_dll/tri.cpp create mode 100644 cl_dll/util.cpp create mode 100644 cl_dll/util_vector.h create mode 100644 cl_dll/view.cpp create mode 100644 cl_dll/view.h create mode 100644 cl_dll/wrect.h create mode 100644 common/beamdef.h create mode 100644 common/bspfile.h create mode 100644 common/cl_entity.h create mode 100644 common/com_model.h create mode 100644 common/con_nprint.h create mode 100644 common/const.h create mode 100644 common/cvardef.h create mode 100644 common/demo_api.h create mode 100644 common/dlight.h create mode 100644 common/entity_state.h create mode 100644 common/entity_types.h create mode 100644 common/event_api.h create mode 100644 common/event_args.h create mode 100644 common/event_flags.h create mode 100644 common/gameinfo.h create mode 100644 common/hltv.h create mode 100644 common/ivoicetweak.h create mode 100644 common/lightstyle.h create mode 100644 common/mathlib.h create mode 100644 common/net_api.h create mode 100644 common/netadr.h create mode 100644 common/particledef.h create mode 100644 common/pmtrace.h create mode 100644 common/qfont.h create mode 100644 common/r_efx.h create mode 100644 common/r_studioint.h create mode 100644 common/ref_params.h create mode 100644 common/render_api.h create mode 100644 common/screenfade.h create mode 100644 common/studio_event.h create mode 100644 common/triangleapi.h create mode 100644 common/usercmd.h create mode 100644 common/wadfile.h create mode 100644 common/weaponinfo.h create mode 100644 common/wrect.h create mode 100644 debug.bat create mode 100644 dlls/AI_BaseNPC_Schedule.cpp create mode 100644 dlls/Android.mk create mode 100644 dlls/Makefile create mode 100644 dlls/Wxdebug.cpp create mode 100644 dlls/activity.h create mode 100644 dlls/activitymap.h create mode 100644 dlls/aflock.cpp create mode 100644 dlls/agrunt.cpp create mode 100644 dlls/airtank.cpp create mode 100644 dlls/animating.cpp create mode 100644 dlls/animation.cpp create mode 100644 dlls/animation.h create mode 100644 dlls/apache.cpp create mode 100644 dlls/barnacle.cpp create mode 100644 dlls/barney.cpp create mode 100644 dlls/basemonster.h create mode 100644 dlls/bigmomma.cpp create mode 100644 dlls/bloater.cpp create mode 100644 dlls/bmodels.cpp create mode 100644 dlls/bullsquid.cpp create mode 100644 dlls/buttons.cpp create mode 100644 dlls/cbase.cpp create mode 100644 dlls/cbase.h create mode 100644 dlls/cdll_dll.h create mode 100644 dlls/client.cpp create mode 100644 dlls/client.h create mode 100644 dlls/combat.cpp create mode 100644 dlls/controller.cpp create mode 100644 dlls/crossbow.cpp create mode 100644 dlls/crowbar.cpp create mode 100644 dlls/decals.h create mode 100644 dlls/defaultai.cpp create mode 100644 dlls/defaultai.h create mode 100644 dlls/doors.cpp create mode 100644 dlls/doors.h create mode 100644 dlls/effects.cpp create mode 100644 dlls/effects.h create mode 100644 dlls/egon.cpp create mode 100644 dlls/enginecallback.h create mode 100644 dlls/explode.cpp create mode 100644 dlls/explode.h create mode 100644 dlls/extdll.h create mode 100644 dlls/flyingmonster.cpp create mode 100644 dlls/flyingmonster.h create mode 100644 dlls/func_break.cpp create mode 100644 dlls/func_break.h create mode 100644 dlls/func_tank.cpp create mode 100644 dlls/game.cpp create mode 100644 dlls/game.h create mode 100644 dlls/gamerules.cpp create mode 100644 dlls/gamerules.h create mode 100644 dlls/gargantua.cpp create mode 100644 dlls/gauss.cpp create mode 100644 dlls/genericmonster.cpp create mode 100644 dlls/ggrenade.cpp create mode 100644 dlls/globals.cpp create mode 100644 dlls/glock.cpp create mode 100644 dlls/gman.cpp create mode 100644 dlls/h_ai.cpp create mode 100644 dlls/h_battery.cpp create mode 100644 dlls/h_cine.cpp create mode 100644 dlls/h_cycler.cpp create mode 100644 dlls/h_export.cpp create mode 100644 dlls/handgrenade.cpp create mode 100644 dlls/hassassin.cpp create mode 100644 dlls/headcrab.cpp create mode 100644 dlls/healthkit.cpp create mode 100644 dlls/hgrunt.cpp create mode 100644 dlls/hl.def create mode 100644 dlls/hl.dsp create mode 100644 dlls/hornet.cpp create mode 100644 dlls/hornet.h create mode 100644 dlls/hornetgun.cpp create mode 100644 dlls/houndeye.cpp create mode 100644 dlls/ichthyosaur.cpp create mode 100644 dlls/islave.cpp create mode 100644 dlls/items.cpp create mode 100644 dlls/items.h create mode 100644 dlls/leech.cpp create mode 100644 dlls/lights.cpp create mode 100644 dlls/maprules.cpp create mode 100644 dlls/maprules.h create mode 100644 dlls/monsterevent.h create mode 100644 dlls/monstermaker.cpp create mode 100644 dlls/monsters.cpp create mode 100644 dlls/monsters.h create mode 100644 dlls/monsterstate.cpp create mode 100644 dlls/mortar.cpp create mode 100644 dlls/mp5.cpp create mode 100644 dlls/mpstubb.cpp create mode 100644 dlls/multiplay_gamerules.cpp create mode 100644 dlls/nihilanth.cpp create mode 100644 dlls/nodes.cpp create mode 100644 dlls/nodes.h create mode 100644 dlls/osprey.cpp create mode 100644 dlls/pathcorner.cpp create mode 100644 dlls/physcallback.h create mode 100644 dlls/plane.cpp create mode 100644 dlls/plane.h create mode 100644 dlls/plats.cpp create mode 100644 dlls/player.cpp create mode 100644 dlls/player.h create mode 100644 dlls/playermonster.cpp create mode 100644 dlls/prop.cpp create mode 100644 dlls/python.cpp create mode 100644 dlls/rat.cpp create mode 100644 dlls/roach.cpp create mode 100644 dlls/rpg.cpp create mode 100644 dlls/satchel.cpp create mode 100644 dlls/saverestore.h create mode 100644 dlls/schedule.cpp create mode 100644 dlls/schedule.h create mode 100644 dlls/scientist.cpp create mode 100644 dlls/scripted.cpp create mode 100644 dlls/scripted.h create mode 100644 dlls/scriptevent.h create mode 100644 dlls/shotgun.cpp create mode 100644 dlls/singleplay_gamerules.cpp create mode 100644 dlls/skill.cpp create mode 100644 dlls/skill.h create mode 100644 dlls/sound.cpp create mode 100644 dlls/soundent.cpp create mode 100644 dlls/soundent.h create mode 100644 dlls/spectator.cpp create mode 100644 dlls/spectator.h create mode 100644 dlls/squad.h create mode 100644 dlls/squadmonster.cpp create mode 100644 dlls/squadmonster.h create mode 100644 dlls/squeakgrenade.cpp create mode 100644 dlls/stats.cpp create mode 100644 dlls/subs.cpp create mode 100644 dlls/talkmonster.cpp create mode 100644 dlls/talkmonster.h create mode 100644 dlls/teamplay_gamerules.cpp create mode 100644 dlls/teamplay_gamerules.h create mode 100644 dlls/tempmonster.cpp create mode 100644 dlls/tentacle.cpp create mode 100644 dlls/trains.h create mode 100644 dlls/triggers.cpp create mode 100644 dlls/tripmine.cpp create mode 100644 dlls/turret.cpp create mode 100644 dlls/util.cpp create mode 100644 dlls/util.h create mode 100644 dlls/vector.h create mode 100644 dlls/weapons.cpp create mode 100644 dlls/weapons.h create mode 100644 dlls/world.cpp create mode 100644 dlls/wxdebug.h create mode 100644 dlls/xen.cpp create mode 100644 dlls/zombie.cpp create mode 100644 engine/anorms.h create mode 100644 engine/cdll_exp.h create mode 100644 engine/cdll_int.h create mode 100644 engine/custom.h create mode 100644 engine/customentity.h create mode 100644 engine/edict.h create mode 100644 engine/eiface.h create mode 100644 engine/engine.dsp create mode 100644 engine/keydefs.h create mode 100644 engine/menu_int.h create mode 100644 engine/physint.h create mode 100644 engine/progdefs.h create mode 100644 engine/shake.h create mode 100644 engine/sprite.h create mode 100644 engine/studio.h create mode 100644 engine/warpsin.h create mode 100644 game_shared/bitvec.h create mode 100644 game_shared/vgui_checkbutton2.cpp create mode 100644 game_shared/vgui_checkbutton2.h create mode 100644 game_shared/vgui_defaultinputsignal.h create mode 100644 game_shared/vgui_grid.cpp create mode 100644 game_shared/vgui_grid.h create mode 100644 game_shared/vgui_helpers.cpp create mode 100644 game_shared/vgui_helpers.h create mode 100644 game_shared/vgui_listbox.cpp create mode 100644 game_shared/vgui_listbox.h create mode 100644 game_shared/vgui_loadtga.cpp create mode 100644 game_shared/vgui_loadtga.h create mode 100644 game_shared/vgui_scrollbar2.cpp create mode 100644 game_shared/vgui_scrollbar2.h create mode 100644 game_shared/vgui_slider2.cpp create mode 100644 game_shared/vgui_slider2.h create mode 100644 game_shared/voice_banmgr.cpp create mode 100644 game_shared/voice_banmgr.h create mode 100644 game_shared/voice_common.h create mode 100644 game_shared/voice_gamemgr.cpp create mode 100644 game_shared/voice_gamemgr.h create mode 100644 game_shared/voice_status.cpp create mode 100644 game_shared/voice_status.h create mode 100644 game_shared/voice_vgui_tweakdlg.cpp create mode 100644 game_shared/voice_vgui_tweakdlg.h create mode 100644 gnu.txt create mode 100644 make_sdk.bat create mode 100644 pm_shared/pm_debug.c create mode 100644 pm_shared/pm_debug.h create mode 100644 pm_shared/pm_defs.h create mode 100644 pm_shared/pm_info.h create mode 100644 pm_shared/pm_materials.h create mode 100644 pm_shared/pm_math.c create mode 100644 pm_shared/pm_movevars.h create mode 100644 pm_shared/pm_shared.c create mode 100644 pm_shared/pm_shared.h create mode 100644 release.bat create mode 100644 utils/makefont/CreateFont.bat create mode 100644 xash.dsw create mode 100644 xash_sdk.dsw create mode 100644 xash_sdk.lst diff --git a/backup.bat b/backup.bat new file mode 100644 index 00000000..7e780aa8 --- /dev/null +++ b/backup.bat @@ -0,0 +1,31 @@ +@echo off +color 4F +echo XashXT Group 2006 (C) +echo Prepare source for backup +echo. + +if exist backup.log del /f /q backup.log +if not exist D:\!backup/ mkdir D:\!backup\ +echo Prepare OK! +echo Please wait: backup in progress +C:\Progra~1\WinRar\rar a -agMMMYYYY-DD D:\!backup\.rar -dh -m5 @backup.lst >>backup.log +if errorlevel 1 goto error +if errorlevel 0 goto ok +:ok +cls +echo Source was sucessfully backuped +echo and stored in folder "backup" +echo Press any key for exit. :-) +if exist backup.log del /f /q backup.log +exit +:error +echo ****************************** +echo ***********Error!************* +echo ****************************** +echo **See backup.log for details** +echo ****************************** +echo ****************************** +echo. +echo press any key for exit :-( +pause>nul +exit diff --git a/backup.lst b/backup.lst new file mode 100644 index 00000000..628de079 --- /dev/null +++ b/backup.lst @@ -0,0 +1,36 @@ +//======================================================================= +// Copyright XashXT Group 2007 © +// list with backup directories +//======================================================================= + +// global stuff +xash.dsw +debug.bat +backup.lst +backup.bat +release.bat +change.log +make_sdk.bat +xash_sdk.lst + +cl_dll\ +cl_dll\hl\ +common\ +dlls\ +game_shared\ +game_launch\ +engine\ +engine\client\ +engine\client\vgui\ +engine\server\ +engine\common\ +engine\common\imagelib\ +engine\common\soundlib\ +pm_shared\ +mainui\ +mainui\legacy +utils\ +utils\makefont\ +utils\vgui\ +utils\vgui\include\ +utils\vgui\lib\win32_vc6\ \ No newline at end of file diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk new file mode 100755 index 00000000..83417047 --- /dev/null +++ b/cl_dll/Android.mk @@ -0,0 +1,106 @@ +#hlsdk-2.3 client port for android +#Copyright (c) mittorn + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := client +#ifeq ($(XASH_SDL),1) +#APP_PLATFORM := android-12 +#LOCAL_SHARED_LIBRARIES += SDL2 +#LOCAL_CFLAGS += -DXASH_SDL +#else +APP_PLATFORM := android-8 +#endif +LOCAL_CONLYFLAGS += -std=c99 + +include $(XASH3D_CONFIG) + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard) +LOCAL_MODULE_FILENAME = libclient_hardfp +endif + +LOCAL_CFLAGS += -fsigned-char -DCLIENT_DLL=1 + +SRCS= +SRCS_C= +SRCS+=../dlls/crossbow.cpp +SRCS+=../dlls/crowbar.cpp +SRCS+=../dlls/egon.cpp +SRCS+=./ev_hldm.cpp +SRCS+=../dlls/gauss.cpp +SRCS+=../dlls/handgrenade.cpp +SRCS+=./hl/hl_baseentity.cpp +SRCS+=./hl/hl_events.cpp +SRCS+=./hl/hl_objects.cpp +SRCS+=./hl/hl_weapons.cpp +SRCS+=../dlls/hornetgun.cpp +SRCS+=../dlls/mp5.cpp +SRCS+=../dlls/python.cpp +SRCS+=../dlls/rpg.cpp +SRCS+=../dlls/satchel.cpp +SRCS+=../dlls/shotgun.cpp +SRCS+=../dlls/squeakgrenade.cpp +SRCS+=../dlls/tripmine.cpp +SRCS+=../dlls/glock.cpp +#SRCS+=../game_shared/voice_banmgr.cpp +#SRCS+=../game_shared/voice_status.cpp +SRCS+=./ammo.cpp +SRCS+=./ammo_secondary.cpp +SRCS+=./ammohistory.cpp +SRCS+=./battery.cpp +SRCS+=./cdll_int.cpp +SRCS+=./com_weapons.cpp +SRCS+=./death.cpp +SRCS+=./demo.cpp +SRCS+=./entity.cpp +SRCS+=./ev_common.cpp +SRCS+=./events.cpp +SRCS+=./flashlight.cpp +SRCS+=./GameStudioModelRenderer.cpp +SRCS+=./geiger.cpp +SRCS+=./health.cpp +SRCS+=./hud.cpp +SRCS+=./hud_msg.cpp +SRCS+=./hud_redraw.cpp +#SRCS+=./hud_servers.cpp +SRCS+=./hud_spectator.cpp +SRCS+=./hud_update.cpp +SRCS+=./in_camera.cpp +SRCS+=./input.cpp +#SRCS+=./inputw32.cpp +SRCS+=./menu.cpp +SRCS+=./message.cpp +SRCS+=./overview.cpp +SRCS+=./parsemsg.cpp +SRCS_C+=../pm_shared/pm_debug.c +SRCS_C+=../pm_shared/pm_math.c +SRCS_C+=../pm_shared/pm_shared.c +SRCS+=./saytext.cpp +SRCS+=./status_icons.cpp +SRCS+=./statusbar.cpp +SRCS+=./studio_util.cpp +SRCS+=./StudioModelRenderer.cpp +SRCS+=./text_message.cpp +SRCS+=./train.cpp +SRCS+=./tri.cpp +SRCS+=./util.cpp +SRCS+=./view.cpp +SRCS+=./input_xash3d.cpp +SRCS+=./scoreboard.cpp +SRCS+=./MOTD.cpp +INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls +DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -fpermissive -w + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ + $(LOCAL_PATH)/../common \ + $(LOCAL_PATH)/../engine \ + $(LOCAL_PATH)/../game_shared \ + $(LOCAL_PATH)/../dlls \ + $(LOCAL_PATH)/../pm_shared +LOCAL_CFLAGS += $(DEFINES) $(INCLUDES) + +LOCAL_SRC_FILES := $(SRCS) $(SRCS_C) + +include $(BUILD_SHARED_LIBRARY) diff --git a/cl_dll/GameStudioModelRenderer.cpp b/cl_dll/GameStudioModelRenderer.cpp new file mode 100644 index 00000000..7d60d6ea --- /dev/null +++ b/cl_dll/GameStudioModelRenderer.cpp @@ -0,0 +1,123 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// +// Override the StudioModelRender virtual member functions here to implement custom bone +// setup, blending, etc. +// + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +#endif +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer.h b/cl_dll/GameStudioModelRenderer.h new file mode 100644 index 00000000..a9d2efff --- /dev/null +++ b/cl_dll/GameStudioModelRenderer.h @@ -0,0 +1,26 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); +}; + +#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/GameStudioModelRenderer_Sample.cpp b/cl_dll/GameStudioModelRenderer_Sample.cpp new file mode 100644 index 00000000..5ea50b51 --- /dev/null +++ b/cl_dll/GameStudioModelRenderer_Sample.cpp @@ -0,0 +1,992 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Predicted values saved off in hl_weapons.cpp +void Game_GetSequence( int *seq, int *gaitseq ); +void Game_GetOrientation( float *o, float *a ); + +float g_flStartScaleTime; +int iPrevRenderState; +int iRenderStateChanged; + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +typedef struct +{ + vec3_t origin; + vec3_t angles; + + vec3_t realangles; + + float animtime; + float frame; + int sequence; + int gaitsequence; + float framerate; + + int m_fSequenceLoops; + int m_fSequenceFinished; + + byte controller[ 4 ]; + byte blending[ 2 ]; + + latchedvars_t lv; +} client_anim_state_t; + +static client_anim_state_t g_state; +static client_anim_state_t g_clientstate; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ + // If you want to predict animations locally, set this to TRUE + // NOTE: The animation code is somewhat broken, but gives you a sense for how + // to do client side animation of the predicted player in a third person game. + m_bLocal = false; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CGameStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + // Use default bone setup for nonplayers + if ( !m_pCurrentEntity->player ) + { + CStudioModelRenderer::StudioSetupBones(); + return; + } + + // Bound sequence number. + if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) + { + f = m_pPlayerInfo->gaitframe; + } + else + { + f = StudioEstimateFrame( pseqdesc ); + } + + // This game knows how to do three way blending + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left anim + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right + if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) + { + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 0-127 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = ( s * 2.0 ); + } + else + { + + // Skip ahead to middle + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 127-255 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize interpolant + s /= 255.0; + + // Go to middle or right + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + // Spherically interpolate the bones + StudioSlerpBones( q, pos, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + } + + // Are we in the process of transitioning from one sequence to another. + if ( m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + // Blending value into last sequence + unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; + + // Point at previous sequenece + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + + // Know how to do three way blends + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left animation + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + if ( prevseqblending <= 127 ) + { + // Set up bones based on final frame of previous sequence + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = ( s * 2.0 ); + } + else + { + // Skip to middle blend + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize + s /= 255.0; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + // Interpolate bones + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + } + + // Now blend last frame of previous sequence with current sequence. + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + m_pCurrentEntity->latched.prevframe = f; + } + + // Now convert quaternions and bone positions into matrices + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + float flYaw; // view direction relative to movement + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + m_pCurrentEntity->angles[PITCH] = 0; + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + StudioEstimateGait( pplayer ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + + flYaw = fmod( flYaw, 360.0 ); + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + float maxyaw = 120.0; + + if (flYaw > maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; + blend_yaw = min( 255.0, blend_yaw ); + blend_yaw = max( 0.0, blend_yaw ); + + blend_yaw = 255.0 - blend_yaw; + + m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + { + m_pCurrentEntity->angles[YAW] += 360; + } + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // Calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; + } + + // Do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + { + m_pPlayerInfo->gaitframe += pseqdesc->numframes; + } +} + +/* +============================== +SavePlayerState + +For local player, in third person, we need to store real render data and then + setup for with fake/client side animation data +============================== +*/ +void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_state; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; +} + +void GetSequenceInfo( void *pmodel, client_anim_state_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, client_anim_state_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; +} + +float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) +{ + if (flInterval == 0.0) + { + flInterval = (gEngfuncs.GetClientTime() - st->animtime); + if (flInterval <= 0.001) + { + st->animtime = gEngfuncs.GetClientTime(); + return 0.0; + } + } + if (!st->animtime) + flInterval = 0.0; + + st->frame += flInterval * framerate * st->framerate; + st->animtime = gEngfuncs.GetClientTime(); + + if (st->frame < 0.0 || st->frame >= 256.0) + { + if ( st->m_fSequenceLoops ) + st->frame -= (int)(st->frame / 256.0) * 256.0; + else + st->frame = (st->frame < 0.0) ? 0 : 255; + st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents + } + + return flInterval; +} + +/* +============================== +SetupClientAnimation + +Called to set up local player's animation values +============================== +*/ +void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) +{ + static double oldtime; + double curtime, dt; + + client_anim_state_t *st; + float fr, gs; + + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + curtime = gEngfuncs.GetClientTime(); + dt = curtime - oldtime; + dt = min( 1.0, max( 0.0, dt ) ); + + oldtime = curtime; + st = &g_clientstate; + + st->framerate = 1.0; + + int oldseq = st->sequence; + Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); + Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); + st->realangles = st->angles; + + if ( st->sequence != oldseq ) + { + st->frame = 0.0; + st->lv.prevsequence = oldseq; + st->lv.sequencetime = st->animtime; + + memcpy( st->lv.prevseqblending, st->blending, 2 ); + memcpy( st->lv.prevcontroller, st->controller, 4 ); + } + + void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); + + GetSequenceInfo( pmodel, st, &fr, &gs ); + st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); + StudioFrameAdvance( st, fr, dt ); + +// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); + + ent->angles = st->realangles; + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +RestorePlayerState + +Called to restore original player state information +============================== +*/ +void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_clientstate; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; + + st = &g_state; + + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + ent->angles = st->realangles; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +StudioDrawPlayer + +============================== +*/ +int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + int iret = 0; + + bool isLocalPlayer = false; + + // Set up for client? + if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) + { + isLocalPlayer = true; + } + + if ( isLocalPlayer ) + { + // Store original data + SavePlayerState( pplayer ); + + // Copy in client side animation data + SetupClientAnimation( pplayer ); + } + + // Call real draw function + iret = _StudioDrawPlayer( flags, pplayer ); + + // Restore for client? + if ( isLocalPlayer ) + { + // Restore the original data for the player + RestorePlayerState( pplayer ); + } + + return iret; +} + +/* +==================== +_StudioDrawPlayer + +==================== +*/ +int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + /* + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + */ + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + if ( iRenderStateChanged ) + { + g_flStartScaleTime = m_clTime; + iRenderStateChanged = FALSE; + } + + // Make the Model continue to shrink + float flTimeDelta = m_clTime - g_flStartScaleTime; + if ( flTimeDelta > 0 ) + { + float flScale = 0.001; + // Goes almost all away + if ( flTimeDelta <= 2.0 ) + flScale = 1.0 - (flTimeDelta / 2.0); + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + transform[i][j] *= flScale; + } + } + } + break; + } +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +#define DLLEXPORT __declspec( dllexport ) +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer_Sample.h b/cl_dll/GameStudioModelRenderer_Sample.h new file mode 100644 index 00000000..bf5cc73f --- /dev/null +++ b/cl_dll/GameStudioModelRenderer_Sample.h @@ -0,0 +1,55 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + + // Player drawing code + virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); + virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + +private: + // For local player, in third person, we need to store real render data and then + // setup for with fake/client side animation data + void SavePlayerState( entity_state_t *pplayer ); + // Called to set up local player's animation values + void SetupClientAnimation( entity_state_t *pplayer ); + // Called to restore original player state information + void RestorePlayerState( entity_state_t *pplayer ); + +private: + // Private data + bool m_bLocal; +}; + +#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp new file mode 100644 index 00000000..94a06eea --- /dev/null +++ b/cl_dll/MOTD.cpp @@ -0,0 +1,165 @@ +/*** +* +* Copyright (c) 1999, 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. +* +****/ +// +// MOTD.cpp +// +// for displaying a server-sent message of the day +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "kbutton.h" +#include "triangleapi.h" +#include +#include + +DECLARE_MESSAGE( m_MOTD, MOTD ); + +int CHudMOTD :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( MOTD ); + + m_bShow = false; + + m_iFlags &= ~HUD_ACTIVE; // start out inactive + m_szMOTD[0] = 0; + + return 1; +} + +int CHudMOTD :: VidInit( void ) +{ + // Load sprites here + return 1; +} + +void CHudMOTD :: Reset( void ) +{ + m_iFlags &= ~HUD_ACTIVE; // start out inactive + m_szMOTD[0] = 0; + m_iLines = 0; + m_bShow = 0; +} + +#define LINE_HEIGHT 13 +#define ROW_GAP 13 +#define ROW_RANGE_MIN 30 +#define ROW_RANGE_MAX ( ScreenHeight - 100 ) +int CHudMOTD :: Draw( float fTime ) +{ + gHUD.m_iNoConsolePrint &= ~( 1 << 1 ); + if( !m_bShow ) + return 1; + gHUD.m_iNoConsolePrint |= 1 << 1; + bool bScroll; + // find the top of where the MOTD should be drawn, so the whole thing is centered in the screen + int ypos = (ScreenHeight - LINE_HEIGHT * m_iLines)/2; // shift it up slightly + char *ch = m_szMOTD; + int xpos = (ScreenWidth - gHUD.m_scrinfo.charWidths[ 'M' ] * m_iMaxLength) / 2; + if( xpos < 30 ) xpos = 30; + int xmax = xpos + gHUD.m_scrinfo.charWidths[ 'M' ] * m_iMaxLength; + int height = LINE_HEIGHT * m_iLines; + int ypos_r=ypos; + if( height > ROW_RANGE_MAX ) + { + ypos = ROW_RANGE_MIN + 7 + scroll; + if( ypos > ROW_RANGE_MIN + 4 ) + scroll-= (ypos - ( ROW_RANGE_MIN + 4))/3.0; + if( ypos + height < ROW_RANGE_MAX ) + scroll+= (ROW_RANGE_MAX - (ypos + height))/ 3.0; + ypos_r = ROW_RANGE_MIN; + height = ROW_RANGE_MAX; + } + int ymax = ypos + height; + if( xmax > ScreenWidth - 30 ) xmax = ScreenWidth - 30; + gHUD.DrawDarkRectangle(xpos-5, ypos_r - 5, xmax - xpos+10, height + 10); + while ( *ch ) + { + int line_length = 0; // count the length of the current line + for ( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) + line_length += gHUD.m_scrinfo.charWidths[ *next_line ]; + char *top = next_line; + if ( *top == '\n' ) + *top = 0; + else + top = NULL; + + // find where to start drawing the line + if( (ypos > ROW_RANGE_MIN) && (ypos + LINE_HEIGHT <= ypos_r + height) ) + gHUD.DrawHudString( xpos, ypos, xmax, ch, 255, 180, 0 ); + + ypos += LINE_HEIGHT; + + if ( top ) // restore + *top = '\n'; + ch = next_line; + if ( *ch == '\n' ) + ch++; + + if ( ypos > (ScreenHeight - 20) ) + break; // don't let it draw too low + } + + return 1; +} + +int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) +{ + if ( m_iFlags & HUD_ACTIVE ) + { + Reset(); // clear the current MOTD in prep for this one + } + + BEGIN_READ( pbuf, iSize ); + + int is_finished = READ_BYTE(); + strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) ); + + if ( is_finished ) + { + int length = 0; + + m_iMaxLength = 0; + m_iFlags |= HUD_ACTIVE; + + + for ( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD + { + if ( *sz == '\n' ) + { + m_iLines++; + if( length > m_iMaxLength ) + { + m_iMaxLength = length; + length = 0; + } + } + length++; + } + + m_iLines++; + if( length > m_iMaxLength ) + { + m_iMaxLength = length; + length = 0; + } + m_bShow = true; + } + + return 1; +} diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp new file mode 100644 index 00000000..e0845c29 --- /dev/null +++ b/cl_dll/StudioModelRenderer.cpp @@ -0,0 +1,1703 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// studio_model.cpp +// routines for setting up to draw 3DStudio models + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Global engine <-> studio model rendering code interface +engine_studio_api_t IEngineStudio; + +///////////////////// +// Implementation of CStudioModelRenderer.h +#define LEGS_BONES_COUNT 8 + +// enumerate all the bones that used for gait animation +const char *legs_bones[] = +{ + "Bip01" , + "Bip01 Pelvis" , + "Bip01 L Leg" , + "Bip01 L Leg1" , + "Bip01 L Foot" , + "Bip01 R Leg" , + "Bip01 R Leg1" , + "Bip01 R Foot" +}; + +/* +==================== +Init + +==================== +*/ +void CStudioModelRenderer::Init( void ) +{ + // Set up some variables shared with engine + m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); + m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); + m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); + + m_pChromeSprite = IEngineStudio.GetChromeSprite(); + + IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); + + // Get pointers to engine data structures + m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); + m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); + m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); + m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); +} + +/* +==================== +CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::CStudioModelRenderer( void ) +{ + m_fDoInterp = 1; + m_fGaitEstimation = 1; + m_pCurrentEntity = NULL; + m_pCvarHiModels = NULL; + m_pCvarDeveloper = NULL; + m_pCvarDrawEntities = NULL; + m_pChromeSprite = NULL; + m_pStudioModelCount = NULL; + m_pModelsDrawn = NULL; + m_protationmatrix = NULL; + m_paliastransform = NULL; + m_pbonetransform = NULL; + m_plighttransform = NULL; + m_pStudioHeader = NULL; + m_pBodyPart = NULL; + m_pSubModel = NULL; + m_pPlayerInfo = NULL; + m_pRenderModel = NULL; +} + +/* +==================== +~CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::~CStudioModelRenderer( void ) +{ +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) +{ + int i, j; + float value; + mstudiobonecontroller_t *pbonecontroller; + + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + if (i <= 3) + { + // check for 360% wrapping + if (pbonecontroller[j].type & STUDIO_RLOOP) + { + if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + int a, b; + a = (pcontroller1[j] + 128) % 256; + b = (pcontroller2[j] + 128) % 256; + value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + else + { + value = mouthopen / 64.0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Con_DPrintf("%d %f\n", mouthopen, value ); + } + switch(pbonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = value * (M_PI / 180.0); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + + +/* +==================== +StudioCalcBoneQuaterion + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j+3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j+3]; // default; + } + else + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k+1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k+2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid+2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + } + + if (pbone->bonecontroller[j+3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j+3]]; + angle2[j] += adj[pbone->bonecontroller[j+3]]; + } + } + + if (!VectorCompare( angle1, angle2 )) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q ); + } + else + { + AngleQuaternion( angle1, q ); + } +} + +/* +==================== +StudioCalcBonePosition + +==================== +*/ +void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) +{ + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + /* + if (i == 0 && j == 0) + Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + */ + + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if ( pbone->bonecontroller[j] != -1 && adj ) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* +==================== +StudioSlerpBones + +==================== +*/ +void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) +{ + int i; + vec4_t q3; + float s1; + + if (s < 0) s = 0; + else if (s > 1.0) s = 1.0; + + s1 = 1.0 - s; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* +==================== +StudioGetAnim + +==================== +*/ +mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) +{ + mstudioseqgroup_t *pseqgroup; + cache_user_t *paSequences; + + pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) + { + return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); + } + + paSequences = (cache_user_t *)m_pSubModel->submodels; + + if (paSequences == NULL) + { + paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! + m_pSubModel->submodels = (dmodel_t *)paSequences; + } + + if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) + { + gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); + IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); + } + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3); + if (*pBlend < pseqdesc->blendstart[0]) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0; + *pBlend = 0; + } + else if (*pBlend > pseqdesc->blendend[0]) + { + *pPitch -= pseqdesc->blendend[0] / 3.0; + *pBlend = 255; + } + else + { + if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error + *pBlend = 127; + else + *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0; + } +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) +{ + int i; + vec3_t angles; + vec3_t modelpos; + +// tweek model origin + //for (i = 0; i < 3; i++) + // modelpos[i] = m_pCurrentEntity->origin[i]; + + VectorCopy( m_pCurrentEntity->origin, modelpos ); + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; + angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; + angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; + + //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); + //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) + { + float f = 0; + float d; + + // don't do it if the goalstarttime hasn't updated in a while. + + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + + if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && + ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) + { + f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); + //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); + } + + if (m_fDoInterp) + { + // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set + f = f - 1.0; + } + else + { + f = 0; + } + + for (i = 0; i < 3; i++) + { + modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; + } + + // NOTE: Because multiplayer lag can be relatively large, we don't want to cap + // f at 1.5 anymore. + //if (f > -1.0 && f < 1.5) {} + +// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); + for (i = 0; i < 3; i++) + { + float ang1, ang2; + + ang1 = m_pCurrentEntity->angles[i]; + ang2 = m_pCurrentEntity->latched.prevangles[i]; + + d = ang1 - ang2; + if (d > 180) + { + d -= 360; + } + else if (d < -180) + { + d += 360; + } + + angles[i] += d * f; + } + //Con_DPrintf("%.3f \n", f ); + } + else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) + { + VectorCopy( m_pCurrentEntity->angles, angles ); + } + + //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); + //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); + + angles[PITCH] = -angles[PITCH]; + AngleMatrix (angles, (*m_protationmatrix)); + + if ( !IEngineStudio.IsHardware() ) + { + static float viewmatrix[3][4]; + + VectorCopy (m_vRight, viewmatrix[0]); + VectorCopy (m_vUp, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (m_vNormal, viewmatrix[2]); + + (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; + (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; + (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; + + ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); + + // do the scaling up of x and y to screen coordinates as part of the transform + // for the unclipped case (it would mess up clipping in the clipped case). + // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y + // correspondingly so the projected x and y come out right + // FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + (*m_paliastransform)[0][i] *= m_fSoftwareXScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[1][i] *= m_fSoftwareYScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); + + } + } + } + + (*m_protationmatrix)[0][3] = modelpos[0]; + (*m_protationmatrix)[1][3] = modelpos[1]; + (*m_protationmatrix)[2][3] = modelpos[2]; +} + + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float CStudioModelRenderer::StudioEstimateInterpolant( void ) +{ + float dadt = 1.0; + + if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) + { + dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; + if (dadt > 2.0) + { + dadt = 2.0; + } + } + return dadt; +} + +/* +==================== +StudioCalcRotations + +==================== +*/ +void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +{ + int i; + int frame; + mstudiobone_t *pbone; + + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; + + if (f > pseqdesc->numframes - 1) + { + f = 0; // bah, fix this bug with changing sequences too fast + } + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + else if ( f < -0.01 ) + { + f = -0.01; + } + + frame = (int)f; + + // Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + + // Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); + + // Con_DPrintf("frame %d %d\n", frame1, frame2 ); + + + dadt = StudioEstimateInterpolant( ); + s = (f - frame); + + // add in programtic controllers + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); + + for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + { + StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); + + StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + // if (0 && i == 0) + // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); + } + + if (pseqdesc->motiontype & STUDIO_X) + { + pos[pseqdesc->motionbone][0] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Y) + { + pos[pseqdesc->motionbone][1] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Z) + { + pos[pseqdesc->motionbone][2] = 0.0; + } + + s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; + + if (pseqdesc->motiontype & STUDIO_LX) + { + pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; + } + if (pseqdesc->motiontype & STUDIO_LY) + { + pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; + } + if (pseqdesc->motiontype & STUDIO_LZ) + { + pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; + } +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; + if ( scale > 2 ) // Don't blow up more than 200% + scale = 2; + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; + } + break; + + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if ( m_fDoInterp ) + { + if ( m_clTime < m_pCurrentEntity->curstate.animtime ) + { + dfdt = 0; + } + else + { + dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; + + } + } + else + { + dfdt = 0; + } + + if (pseqdesc->numframes <= 1) + { + f = 0; + } + else + { + f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; + } + + f += dfdt; + + if (pseqdesc->flags & STUDIO_LOOPING) + { + if (pseqdesc->numframes > 1) + { + f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + } + if (f < 0) + { + f += (pseqdesc->numframes - 1); + } + } + else + { + if (f >= pseqdesc->numframes - 1.001) + { + f = pseqdesc->numframes - 1.001; + } + if (f < 0.0) + { + f = 0.0; + } + } + return f; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + if (pseqdesc->numblends > 1) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + dadt = StudioEstimateInterpolant(); + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + + StudioSlerpBones( q, pos, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); + + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q, pos, q3, pos3, s ); + } + } + + if (m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + if (pseqdesc->numblends > 1) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; + StudioSlerpBones( q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + //Con_DPrintf("prevframe = %4.2f\n", f); + m_pCurrentEntity->latched.prevframe = f; + } + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) + { + if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) + { + m_pPlayerInfo->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for( int j = 0; j < LEGS_BONES_COUNT; j++ ) + { + if( !strcmp( pbones[i].name, legs_bones[j] )) + break; + } + + if( j == LEGS_BONES_COUNT ) + continue; // not used for legs + + memcpy( pos[i], pos2[i], sizeof( pos[i] )); + memcpy( q[i], q2[i], sizeof( q[i] )); + } + } + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + + +/* +==================== +StudioSaveBones + +==================== +*/ +void CStudioModelRenderer::StudioSaveBones( void ) +{ + int i; + + mstudiobone_t *pbones; + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + m_nCachedBones = m_pStudioHeader->numbones; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + strcpy( m_nCachedBoneNames[i], pbones[i].name ); + MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); + MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); + } +} + + +/* +==================== +StudioMergeBones + +==================== +*/ +void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) +{ + int i, j; + double f; + int do_hunt = true; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + float bonematrix[3][4]; + static vec4_t q[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pSubModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for (j = 0; j < m_nCachedBones; j++) + { + if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) + { + MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); + MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); + break; + } + } + if (j >= m_nCachedBones) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } + } +} + +/* +==================== +StudioDrawModel + +==================== +*/ +int CStudioModelRenderer::StudioDrawModel( int flags ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) + { + entity_state_t deadplayer; + + int result; + int save_interp; + + if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) + return 0; + + // get copy of player + deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; + + // clear weapon, movement state + deadplayer.number = m_pCurrentEntity->curstate.renderamt; + deadplayer.weaponmodel = 0; + deadplayer.gaitsequence = 0; + + deadplayer.movetype = MOVETYPE_NONE; + VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); + VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); + + save_interp = m_fDoInterp; + m_fDoInterp = 0; + + // draw as though it were a player + result = StudioDrawPlayer( flags, &deadplayer ); + + m_fDoInterp = save_interp; + return result; + } + + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + StudioSetUpTransform( 0 ); + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + { + StudioMergeBones( m_pRenderModel ); + } + else + { + StudioSetupBones( ); + } + StudioSaveBones( ); + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + // get remap colors + m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + } + + return 1; +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + int iBlend; + float flYaw; // view direction relative to movement + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); + + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + m_pCurrentEntity->curstate.blending[0] = iBlend; + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + StudioEstimateGait( pplayer ); + + // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if (flYaw < -180) + flYaw = flYaw + 360; + if (flYaw > 180) + flYaw = flYaw - 360; + + if (flYaw > 120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + // adjust torso + m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + m_pCurrentEntity->angles[YAW] += 360; + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + if (pplayer->gaitsequence >= m_pStudioHeader->numseq) + { + pplayer->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; + } + + // do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + m_pPlayerInfo->gaitframe += pseqdesc->numframes; +} + +/* +==================== +StudioDrawPlayer + +==================== +*/ +int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + + // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); + + // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +StudioCalcAttachments + +==================== +*/ +void CStudioModelRenderer::StudioCalcAttachments( void ) +{ + int i; + mstudioattachment_t *pattachment; + + if ( m_pStudioHeader->numattachments > 4 ) + { + gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); + exit( -1 ); + } + + // calculate attachment points + pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + for (i = 0; i < m_pStudioHeader->numattachments; i++) + { + VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); + } +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void CStudioModelRenderer::StudioRenderModel( void ) +{ + IEngineStudio.SetChromeOrigin(); + IEngineStudio.SetForceFaceFlags( 0 ); + + if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) + { + m_pCurrentEntity->curstate.renderfx = kRenderFxNone; + StudioRenderFinal( ); + + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + } + + IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); + + gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); + m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; + + StudioRenderFinal( ); + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + } + else + { + StudioRenderFinal( ); + } +} + +/* +==================== +StudioRenderFinal_Software + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Software( void ) +{ + int i; + + // Note, rendermode set here has effect in SW + IEngineStudio.SetupRenderer( 0 ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones( ); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls( ); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + IEngineStudio.StudioDrawPoints( ); + } + } + + if (m_pCvarDrawEntities->value == 4) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal_Hardware + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) +{ + int i; + int rendermode; + + rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; + IEngineStudio.SetupRenderer( rendermode ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones(); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls(); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + + if (m_fDoInterp) + { + // interpolation messes up bounding boxes. + m_pCurrentEntity->trivial_accept = 0; + } + + IEngineStudio.GL_SetRenderMode( rendermode ); + IEngineStudio.StudioDrawPoints(); + IEngineStudio.GL_StudioDrawShadow(); + } + } + + if ( m_pCvarDrawEntities->value == 4 ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal(void) +{ + if ( IEngineStudio.IsHardware() ) + { + StudioRenderFinal_Hardware(); + } + else + { + StudioRenderFinal_Software(); + } +} + diff --git a/cl_dll/StudioModelRenderer.h b/cl_dll/StudioModelRenderer.h new file mode 100644 index 00000000..51eaaa60 --- /dev/null +++ b/cl_dll/StudioModelRenderer.h @@ -0,0 +1,189 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( STUDIOMODELRENDERER_H ) +#define STUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CStudioModelRenderer + +==================== +*/ +class CStudioModelRenderer +{ +public: + // Construction/Destruction + CStudioModelRenderer( void ); + virtual ~CStudioModelRenderer( void ); + + // Initialization + virtual void Init( void ); + +public: + // Public Interfaces + virtual int StudioDrawModel ( int flags ); + virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); + +public: + // Local interfaces + // + + // Look up animation data for sequence + virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); + + // Interpolate model position and angles and set up matrices + virtual void StudioSetUpTransform (int trivial_accept); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Find final attachment points + virtual void StudioCalcAttachments ( void ); + + // Save bone matrices and names + virtual void StudioSaveBones( void ); + + // Merge cached bones with current bones for model + virtual void StudioMergeBones ( model_t *m_pSubModel ); + + // Determine interpolation fraction + virtual float StudioEstimateInterpolant( void ); + + // Determine current frame for rendering + virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + + // Spherical interpolation of bones + virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); + + // Compute bone adjustments ( bone controllers ) + virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); + + // Get bone quaternions + virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); + + // Get bone positions + virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); + + // Compute rotations + virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); + + // Send bones and verts to renderer + virtual void StudioRenderModel ( void ); + + // Finalize rendering + virtual void StudioRenderFinal (void); + + // GL&D3D vs. Software renderer finishing functions + virtual void StudioRenderFinal_Software ( void ); + virtual void StudioRenderFinal_Hardware ( void ); + + // Player specific data + // Determine pitch and blending amounts for players + virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + +public: + + // Client clock + double m_clTime; + // Old Client clock + double m_clOldTime; + + // Do interpolation? + int m_fDoInterp; + // Do gait estimation? + int m_fGaitEstimation; + + // Current render frame # + int m_nFrameCount; + + // Cvars that studio model code needs to reference + // + // Use high quality models? + cvar_t *m_pCvarHiModels; + // Developer debug output desired? + cvar_t *m_pCvarDeveloper; + // Draw entities bone hit boxes, etc? + cvar_t *m_pCvarDrawEntities; + + // The entity which we are currently rendering. + cl_entity_t *m_pCurrentEntity; + + // The model for the entity being rendered + model_t *m_pRenderModel; + + // Player info for current player, if drawing a player + player_info_t *m_pPlayerInfo; + + // The index of the player being drawn + int m_nPlayerIndex; + + // The player's gait movement + float m_flGaitMovement; + + // Pointer to header block for studio model data + studiohdr_t *m_pStudioHeader; + + // Pointers to current body part and submodel + mstudiobodyparts_t *m_pBodyPart; + mstudiomodel_t *m_pSubModel; + + // Palette substition for top and bottom of model + int m_nTopColor; + int m_nBottomColor; + + // + // Sprite model used for drawing studio model chrome + model_t *m_pChromeSprite; + + // Caching + // Number of bones in bone cache + int m_nCachedBones; + // Names of cached bones + char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; + // Cached bone & light transformation matrices + float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + + // Software renderer scale factors + float m_fSoftwareXScale, m_fSoftwareYScale; + + // Current view vectors and render origin + float m_vUp[ 3 ]; + float m_vRight[ 3 ]; + float m_vNormal[ 3 ]; + + float m_vRenderOrigin[ 3 ]; + + // Model render counters ( from engine ) + int *m_pStudioModelCount; + int *m_pModelsDrawn; + + // Matrices + // Model to world transformation + float (*m_protationmatrix)[ 3 ][ 4 ]; + // Model to view transformation + float (*m_paliastransform)[ 3 ][ 4 ]; + + // Concatenated bone and light transforms + float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; +}; + +#endif // STUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp new file mode 100644 index 00000000..48309bd3 --- /dev/null +++ b/cl_dll/ammo.cpp @@ -0,0 +1,1203 @@ +/*** +* +* 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. +* +****/ +// +// Ammo.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "pm_shared.h" + +#include +#include + +#include "ammohistory.h" + +WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise + // this points to the active weapon menu item +WEAPON *gpLastSel; // Last weapon menu selection + +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +WeaponsResource gWR; + +int g_weaponselect = 0; + +void WeaponsResource :: LoadAllWeaponSprites( void ) +{ + for (int i = 0; i < MAX_WEAPONS; i++) + { + if ( rgWeapons[i].iId ) + LoadWeaponSprites( &rgWeapons[i] ); + } +} + +int WeaponsResource :: CountAmmo( int iId ) +{ + if ( iId < 0 ) + return 0; + + return riAmmo[iId]; +} + +int WeaponsResource :: HasAmmo( WEAPON *p ) +{ + if ( !p ) + return FALSE; + + // weapons with no max ammo can always be selected + if ( p->iMax1 == -1 ) + return TRUE; + + return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) + || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); +} + + +void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) +{ + int i, iRes; + + if (ScreenWidth < 640) + iRes = 320; + else + iRes = 640; + + char sz[128]; + + if ( !pWeapon ) + return; + + memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); + pWeapon->hInactive = 0; + pWeapon->hActive = 0; + pWeapon->hAmmo = 0; + pWeapon->hAmmo2 = 0; + + sprintf(sz, "sprites/%s.txt", pWeapon->szName); + client_sprite_t *pList = SPR_GetList(sz, &i); + + if (!pList) + return; + + client_sprite_t *p; + + p = GetSpriteList( pList, "crosshair", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hCrosshair = SPR_Load(sz); + pWeapon->rcCrosshair = p->rc; + } + else + pWeapon->hCrosshair = NULL; + + p = GetSpriteList(pList, "autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAutoaim = SPR_Load(sz); + pWeapon->rcAutoaim = p->rc; + } + else + pWeapon->hAutoaim = 0; + + p = GetSpriteList( pList, "zoom", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedCrosshair = SPR_Load(sz); + pWeapon->rcZoomedCrosshair = p->rc; + } + else + { + pWeapon->hZoomedCrosshair = pWeapon->hCrosshair; //default to non-zoomed crosshair + pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; + } + + p = GetSpriteList(pList, "zoom_autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedAutoaim = SPR_Load(sz); + pWeapon->rcZoomedAutoaim = p->rc; + } + else + { + pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair; //default to zoomed crosshair + pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; + } + + p = GetSpriteList(pList, "weapon", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hInactive = SPR_Load(sz); + pWeapon->rcInactive = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hInactive = 0; + + p = GetSpriteList(pList, "weapon_s", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hActive = SPR_Load(sz); + pWeapon->rcActive = p->rc; + } + else + pWeapon->hActive = 0; + + p = GetSpriteList(pList, "ammo", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo = SPR_Load(sz); + pWeapon->rcAmmo = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo = 0; + + p = GetSpriteList(pList, "ammo2", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo2 = SPR_Load(sz); + pWeapon->rcAmmo2 = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo2 = 0; + +} + +// Returns the first weapon for a given slot. +WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) +{ + WEAPON *pret = NULL; + + for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) + { + if ( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] ) ) + { + pret = rgSlots[iSlot][i]; + break; + } + } + + return pret; +} + + +WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) +{ + if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) + return NULL; + + WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; + + if ( !p || !gWR.HasAmmo(p) ) + return GetNextActivePos( iSlot, iSlotPos + 1 ); + + return p; +} + + +int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height + +HSPRITE ghsprBuckets; // Sprite for top row of weapons menu + +DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip +DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type +DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count +DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record +DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record +DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE(m_Ammo, ItemPickup); + +DECLARE_COMMAND(m_Ammo, Slot1); +DECLARE_COMMAND(m_Ammo, Slot2); +DECLARE_COMMAND(m_Ammo, Slot3); +DECLARE_COMMAND(m_Ammo, Slot4); +DECLARE_COMMAND(m_Ammo, Slot5); +DECLARE_COMMAND(m_Ammo, Slot6); +DECLARE_COMMAND(m_Ammo, Slot7); +DECLARE_COMMAND(m_Ammo, Slot8); +DECLARE_COMMAND(m_Ammo, Slot9); +DECLARE_COMMAND(m_Ammo, Slot10); +DECLARE_COMMAND(m_Ammo, Close); +DECLARE_COMMAND(m_Ammo, NextWeapon); +DECLARE_COMMAND(m_Ammo, PrevWeapon); + +// width of ammo fonts +#define AMMO_SMALL_WIDTH 10 +#define AMMO_LARGE_WIDTH 20 + +#define HISTORY_DRAW_TIME "5" + +int CHudAmmo::Init(void) +{ + gHUD.AddHudElem(this); + + HOOK_MESSAGE(CurWeapon); + HOOK_MESSAGE(WeaponList); + HOOK_MESSAGE(AmmoPickup); + HOOK_MESSAGE(WeapPickup); + HOOK_MESSAGE(ItemPickup); + HOOK_MESSAGE(HideWeapon); + HOOK_MESSAGE(AmmoX); + + HOOK_COMMAND("slot1", Slot1); + HOOK_COMMAND("slot2", Slot2); + HOOK_COMMAND("slot3", Slot3); + HOOK_COMMAND("slot4", Slot4); + HOOK_COMMAND("slot5", Slot5); + HOOK_COMMAND("slot6", Slot6); + HOOK_COMMAND("slot7", Slot7); + HOOK_COMMAND("slot8", Slot8); + HOOK_COMMAND("slot9", Slot9); + HOOK_COMMAND("slot10", Slot10); + HOOK_COMMAND("cancelselect", Close); + HOOK_COMMAND("invnext", NextWeapon); + HOOK_COMMAND("invprev", PrevWeapon); + + Reset(); + + CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); + CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress + + m_iFlags |= HUD_ACTIVE; //!!! + + gWR.Init(); + gHR.Init(); + + return 1; +}; + +void CHudAmmo::Reset(void) +{ + m_fFade = 0; + m_iFlags |= HUD_ACTIVE; //!!! + + gpActiveSel = NULL; + gHUD.m_iHideHUDDisplay = 0; + + gWR.Reset(); + gHR.Reset(); + + // VidInit(); + +} + +int CHudAmmo::VidInit(void) +{ + // Load sprites for buckets (top row of weapon menu) + m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); + m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); + + ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); + giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; + giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; + + gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); + + // If we've already loaded weapons, let's get new sprites + gWR.LoadAllWeaponSprites(); + + if (ScreenWidth >= 640) + { + giABWidth = 20; + giABHeight = 4; + } + else + { + giABWidth = 10; + giABHeight = 2; + } + + return 1; +} + +// +// Think: +// Used for selection of weapon menu item. +// +void CHudAmmo::Think(void) +{ + if ( gHUD.m_fPlayerDead ) + return; + + if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) + { + gWR.iOldWeaponBits = gHUD.m_iWeaponBits; + + for (int i = MAX_WEAPONS-1; i > 0; i-- ) + { + WEAPON *p = gWR.GetWeapon(i); + + if ( p ) + { + if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) + gWR.PickupWeapon( p ); + else + gWR.DropWeapon( p ); + } + } + } + + if (!gpActiveSel) + return; + + // has the player selected one? + if (gHUD.m_iKeyBits & IN_ATTACK) + { + if (gpActiveSel != (WEAPON *)1) + { + ServerCmd(gpActiveSel->szName); + g_weaponselect = gpActiveSel->iId; + } + + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + gHUD.m_iKeyBits &= ~IN_ATTACK; + + PlaySound("common/wpn_select.wav", 1); + } + +} + +// +// Helper function to return a Ammo pointer from id +// + +HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iAmmoType == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo; + return &rgWeapons[i].hAmmo; + } + else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo2; + return &rgWeapons[i].hAmmo2; + } + } + + return NULL; +} + + +// Menu Selection Code + +void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) +{ + if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) + { // menu is overriding slot use commands + gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers + return; + } + + if ( iSlot > MAX_WEAPON_SLOTS ) + return; + + if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + return; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return; + + if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) + return; + + WEAPON *p = NULL; + bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; + + if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) + { + PlaySound( "common/wpn_hudon.wav", 1 ); + p = GetFirstPos( iSlot ); + + if ( p && fastSwitch ) // check for fast weapon switch mode + { + // if fast weapon switch is on, then weapons can be selected in a single keypress + // but only if there is only one item in the bucket + WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); + if ( !p2 ) + { // only one active item in bucket, so change directly to weapon + ServerCmd( p->szName ); + g_weaponselect = p->iId; + return; + } + } + } + else + { + PlaySound("common/wpn_moveselect.wav", 1); + if ( gpActiveSel ) + p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); + if ( !p ) + p = GetFirstPos( iSlot ); + } + + + if ( !p ) // no selection found + { + // just display the weapon list, unless fastswitch is on just ignore it + if ( !fastSwitch ) + gpActiveSel = (WEAPON *)1; + else + gpActiveSel = NULL; + } + else + gpActiveSel = p; +} + +//------------------------------------------------------------------------ +// Message Handlers +//------------------------------------------------------------------------ + +// +// AmmoX -- Update the count of a known type of ammo +// +int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + gWR.SetAmmo( iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + // Add ammo to the history + gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); + + return 1; +} + +int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + const char *szName = READ_STRING(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_ITEM, szName ); + + return 1; +} + + +int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + gHUD.m_iHideHUDDisplay = READ_BYTE(); + + if (gEngfuncs.IsSpectateOnly()) + return 1; + + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + { + static wrect_t nullrc; + gpActiveSel = NULL; + SetCrosshair( 0, nullrc, 0, 0, 0 ); + } + else + { + if ( m_pWeapon ) + SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); + } + + return 1; +} + +// +// CurWeapon: Update hud state with the current weapon and clip count. Ammo +// counts are updated with AmmoX. Server assures that the Weapon ammo type +// numbers match a real ammo type. +// +int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) +{ + static wrect_t nullrc; + int fOnTarget = FALSE; + + BEGIN_READ( pbuf, iSize ); + + int iState = READ_BYTE(); + int iId = READ_CHAR(); + int iClip = READ_CHAR(); + + // detect if we're also on target + if ( iState > 1 ) + { + fOnTarget = TRUE; + } + + if ( iId < 1 ) + { + SetCrosshair(0, nullrc, 0, 0, 0); + return 0; + } + + if ( g_iUser1 != OBS_IN_EYE ) + { + // Is player dead??? + if ((iId == -1) && (iClip == -1)) + { + gHUD.m_fPlayerDead = TRUE; + gpActiveSel = NULL; + return 1; + } + gHUD.m_fPlayerDead = FALSE; + } + + WEAPON *pWeapon = gWR.GetWeapon( iId ); + + if ( !pWeapon ) + return 0; + + if ( iClip < -1 ) + pWeapon->iClip = abs(iClip); + else + pWeapon->iClip = iClip; + + + if ( iState == 0 ) // we're not the current weapon, so update no more + return 1; + + m_pWeapon = pWeapon; + + if ( gHUD.m_iFOV >= 90 ) + { // normal crosshairs + if (fOnTarget && m_pWeapon->hAutoaim) + SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + } + else + { // zoomed crosshairs + if (fOnTarget && m_pWeapon->hZoomedAutoaim) + SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); + + } + + m_fFade = 200.0f; //!!! + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +// +// WeaponList -- Tells the hud about a new weapon type. +// +int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + WEAPON Weapon; + + strcpy( Weapon.szName, READ_STRING() ); + Weapon.iAmmoType = (int)READ_CHAR(); + + Weapon.iMax1 = READ_BYTE(); + if (Weapon.iMax1 == 255) + Weapon.iMax1 = -1; + + Weapon.iAmmo2Type = READ_CHAR(); + Weapon.iMax2 = READ_BYTE(); + if (Weapon.iMax2 == 255) + Weapon.iMax2 = -1; + + Weapon.iSlot = READ_CHAR(); + Weapon.iSlotPos = READ_CHAR(); + Weapon.iId = READ_CHAR(); + Weapon.iFlags = READ_BYTE(); + Weapon.iClip = 0; + + gWR.AddWeapon( &Weapon ); + + return 1; + +} + +//------------------------------------------------------------------------ +// Command Handlers +//------------------------------------------------------------------------ +// Slot button pressed +void CHudAmmo::SlotInput( int iSlot ) +{ + // Let the Viewport use it first, for menus +// if ( gViewPort && gViewPort->SlotInput( iSlot ) ) +// return; + + gWR.SelectSlot(iSlot, FALSE, 1); +} + +void CHudAmmo::UserCmd_Slot1(void) +{ + SlotInput( 0 ); +} + +void CHudAmmo::UserCmd_Slot2(void) +{ + SlotInput( 1 ); +} + +void CHudAmmo::UserCmd_Slot3(void) +{ + SlotInput( 2 ); +} + +void CHudAmmo::UserCmd_Slot4(void) +{ + SlotInput( 3 ); +} + +void CHudAmmo::UserCmd_Slot5(void) +{ + SlotInput( 4 ); +} + +void CHudAmmo::UserCmd_Slot6(void) +{ + SlotInput( 5 ); +} + +void CHudAmmo::UserCmd_Slot7(void) +{ + SlotInput( 6 ); +} + +void CHudAmmo::UserCmd_Slot8(void) +{ + SlotInput( 7 ); +} + +void CHudAmmo::UserCmd_Slot9(void) +{ + SlotInput( 8 ); +} + +void CHudAmmo::UserCmd_Slot10(void) +{ + SlotInput( 9 ); +} + +void CHudAmmo::UserCmd_Close(void) +{ + if (gpActiveSel) + { + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + PlaySound("common/wpn_hudoff.wav", 1); + } + else + ClientCmd("escape"); +} + + +// Selects the next item in the weapon menu +void CHudAmmo::UserCmd_NextWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = 0; + int slot = 0; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos + 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) + { + for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = 0; + } + + slot = 0; // start looking from the first slot again + } + + gpActiveSel = NULL; +} + +// Selects the previous item in the menu +void CHudAmmo::UserCmd_PrevWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = MAX_WEAPON_POSITIONS-1; + int slot = MAX_WEAPON_SLOTS-1; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos - 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot >= 0; slot-- ) + { + for ( ; pos >= 0; pos-- ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = MAX_WEAPON_POSITIONS-1; + } + + slot = MAX_WEAPON_SLOTS-1; + } + + gpActiveSel = NULL; +} + + + +//------------------------------------------------------------------------- +// Drawing code +//------------------------------------------------------------------------- + +int CHudAmmo::Draw(float flTime) +{ + int a, x, y, r, g, b; + int AmmoWidth; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // Draw Weapon Menu + DrawWList(flTime); + + // Draw ammo pickup history + gHR.DrawAmmoHistory( flTime ); + + if (!(m_iFlags & HUD_ACTIVE)) + return 0; + + if (!m_pWeapon) + return 0; + + WEAPON *pw = m_pWeapon; // shorthand + + // SPR_Draw Ammo + if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) + return 0; + + + int iFlags = DHN_DRAWZERO; // draw 0 values + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + a = (int) max( MIN_ALPHA, m_fFade ); + + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a ); + + // Does this weapon have a clip? + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; + + // Does weapon have any ammo at all? + if (m_pWeapon->iAmmoType > 0) + { + int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; + + if (pw->iClip >= 0) + { + // room for the number and the '|' and the current ammo + + x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); + + wrect_t rc; + rc.top = 0; + rc.left = 0; + rc.right = AmmoWidth; + rc.bottom = 100; + + int iBarWidth = AmmoWidth/10; + + x += AmmoWidth/2; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + // draw the | bar + FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); + + x += iBarWidth + AmmoWidth/2;; + + // GL Seems to need this + ScaleColors(r, g, b, a ); + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + + + } + else + { + // SPR_Draw a bullets only line + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + } + + // Draw the ammo Icon + int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; + SPR_Set(m_pWeapon->hAmmo, r, g, b); + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); + } + + // Does weapon have seconday ammo? + if (pw->iAmmo2Type > 0) + { + int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; + + // Do we have secondary ammo? + if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) + { + y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); + + // Draw the ammo Icon + SPR_Set(m_pWeapon->hAmmo2, r, g, b); + int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); + } + } + return 1; +} + + +// +// Draws the ammo bar on the hud +// +int DrawBar(int x, int y, int width, int height, float f) +{ + int r, g, b; + + if (f < 0) + f = 0; + if (f > 1) + f = 1; + + if (f) + { + int w = f * width; + + // Always show at least one pixel if we have ammo. + if (w <= 0) + w = 1; + UnpackRGB(r, g, b, RGB_GREENISH); + FillRGBA(x, y, w, height, r, g, b, 255); + x += w; + width -= w; + } + + UnpackRGB(r, g, b, RGB_YELLOWISH); + + FillRGBA(x, y, width, height, r, g, b, 128); + + return (x + width); +} + + + +void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) +{ + if ( !p ) + return; + + if (p->iAmmoType != -1) + { + if (!gWR.CountAmmo(p->iAmmoType)) + return; + + float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; + + x = DrawBar(x, y, width, height, f); + + + // Do we have secondary ammo too? + + if (p->iAmmo2Type != -1) + { + f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; + + x += 5; //!!! + + DrawBar(x, y, width, height, f); + } + } +} + + + + +// +// Draw Weapon Menu +// +int CHudAmmo::DrawWList(float flTime) +{ + int r,g,b,x,y,a,i; + + if ( !gpActiveSel ) + return 0; + + int iActiveSlot; + + if ( gpActiveSel == (WEAPON *)1 ) + iActiveSlot = -1; // current slot has no weapons + else + iActiveSlot = gpActiveSel->iSlot; + + x = 10; //!!! + y = 10; //!!! + + + // Ensure that there are available choices in the active slot + if ( iActiveSlot > 0 ) + { + if ( !gWR.GetFirstPos( iActiveSlot ) ) + { + gpActiveSel = (WEAPON *)1; + iActiveSlot = -1; + } + } + + // Draw top line + for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + int iWidth; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if ( iActiveSlot == i ) + a = 255; + else + a = 192; + + ScaleColors(r, g, b, 255); + SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); + + // make active slot wide enough to accomodate gun pictures + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos(iActiveSlot); + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + else + iWidth = giBucketWidth; + } + else + iWidth = giBucketWidth; + + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); + + x += iWidth + 5; + } + + + a = 128; //!!! + x = 10; + + // Draw all of the buckets + for (i = 0; i < MAX_WEAPON_SLOTS; i++) + { + y = giBucketHeight + 10; + + // If this is the active slot, draw the bigger pictures, + // otherwise just draw boxes + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos( i ); + int iWidth = giBucketWidth; + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + UnpackRGB( r,g,b, RGB_YELLOWISH ); + + // if active, then we must have ammo. + + if ( gpActiveSel == p ) + { + SPR_Set(p->hActive, r, g, b ); + SPR_DrawAdditive(0, x, y, &p->rcActive); + + SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); + } + else + { + // Draw Weapon if Red if no ammo + + if ( gWR.HasAmmo(p) ) + ScaleColors(r, g, b, 192); + else + { + UnpackRGB(r,g,b, RGB_REDISH); + ScaleColors(r, g, b, 128); + } + + SPR_Set( p->hInactive, r, g, b ); + SPR_DrawAdditive( 0, x, y, &p->rcInactive ); + } + + // Draw Ammo Bar + + DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); + + y += p->rcActive.bottom - p->rcActive.top + 5; + } + + x += iWidth + 5; + + } + else + { + // Draw Row of weapons. + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + WEAPON *p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + if ( gWR.HasAmmo(p) ) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + a = 128; + } + else + { + UnpackRGB(r,g,b, RGB_REDISH); + a = 96; + } + + FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); + + y += giBucketHeight + 5; + } + + x += giBucketWidth + 5; + } + } + + return 1; + +} + + +/* ================================= + GetSpriteList + +Finds and returns the matching +sprite name 'psz' and resolution 'iRes' +in the given sprite list 'pList' +iCount is the number of items in the pList +================================= */ +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) +{ + if (!pList) + return NULL; + + int i = iCount; + client_sprite_t *p = pList; + + while(i--) + { + if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) + return p; + p++; + } + + return NULL; +} diff --git a/cl_dll/ammo.h b/cl_dll/ammo.h new file mode 100644 index 00000000..ad730cc8 --- /dev/null +++ b/cl_dll/ammo.h @@ -0,0 +1,62 @@ +/*** +* +* 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 __AMMO_H__ +#define __AMMO_H__ + +#define MAX_WEAPON_NAME 128 + + +#define WEAPON_FLAGS_SELECTONEMPTY 1 + +#define WEAPON_IS_ONTARGET 0x40 + +struct WEAPON +{ + char szName[MAX_WEAPON_NAME]; + int iAmmoType; + int iAmmo2Type; + int iMax1; + int iMax2; + int iSlot; + int iSlotPos; + int iFlags; + int iId; + int iClip; + + int iCount; // # of itesm in plist + + HSPRITE hActive; + wrect_t rcActive; + HSPRITE hInactive; + wrect_t rcInactive; + HSPRITE hAmmo; + wrect_t rcAmmo; + HSPRITE hAmmo2; + wrect_t rcAmmo2; + HSPRITE hCrosshair; + wrect_t rcCrosshair; + HSPRITE hAutoaim; + wrect_t rcAutoaim; + HSPRITE hZoomedCrosshair; + wrect_t rcZoomedCrosshair; + HSPRITE hZoomedAutoaim; + wrect_t rcZoomedAutoaim; +}; + +typedef int AMMO; + + +#endif \ No newline at end of file diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp new file mode 100644 index 00000000..2ca07d2d --- /dev/null +++ b/cl_dll/ammo_secondary.cpp @@ -0,0 +1,159 @@ +/*** +* +* 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. +* +****/ +// +// ammo_secondary.cpp +// +// implementation of CHudAmmoSecondary class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); + +int CHudAmmoSecondary :: Init( void ) +{ + HOOK_MESSAGE( SecAmmoVal ); + HOOK_MESSAGE( SecAmmoIcon ); + + gHUD.AddHudElem(this); + m_HUD_ammoicon = 0; + + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + m_iAmmoAmounts[i] = -1; // -1 means don't draw this value + + Reset(); + + return 1; +} + +void CHudAmmoSecondary :: Reset( void ) +{ + m_fFade = 0; +} + +int CHudAmmoSecondary :: VidInit( void ) +{ + return 1; +} + +int CHudAmmoSecondary :: Draw(float flTime) +{ + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // draw secondary ammo icons above normal ammo readout + int a, x, y, r, g, b, AmmoWidth; + UnpackRGB( r, g, b, RGB_YELLOWISH ); + a = (int) max( MIN_ALPHA, m_fFade ); + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons + ScaleColors( r, g, b, a ); + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values + x = ScreenWidth - AmmoWidth; + + if ( m_HUD_ammoicon ) + { + // Draw the ammo icon + x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); + y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); + + SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); + } + else + { // move the cursor by the '0' char instead, since we don't have an icon to work with + x -= AmmoWidth; + y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); + } + + // draw the ammo counts, in reverse order, from right to left + for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) + { + if ( m_iAmmoAmounts[i] < 0 ) + continue; // negative ammo amounts imply that they shouldn't be drawn + + // half a char gap between the ammo number and the previous pic + x -= (AmmoWidth / 2); + + // draw the number, right-aligned + x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); + gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); + + if ( i != 0 ) + { + // draw the divider bar + x -= (AmmoWidth / 2); + FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); + } + } + + return 1; +} + +// Message handler for Secondary Ammo Value +// accepts one value: +// string: sprite name +int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); + + return 1; +} + +// Message handler for Secondary Ammo Icon +// Sets an ammo value +// takes two values: +// byte: ammo index +// byte: ammo value +int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + if ( index < 0 || index >= MAX_SEC_AMMO_VALUES ) + return 1; + + m_iAmmoAmounts[index] = READ_BYTE(); + m_iFlags |= HUD_ACTIVE; + + // check to see if there is anything left to draw + int count = 0; + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + { + count += max( 0, m_iAmmoAmounts[i] ); + } + + if ( count == 0 ) + { // the ammo fields are all empty, so turn off this hud area + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + + // make the icons light up + m_fFade = 200.0f; + + return 1; +} + + diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp new file mode 100644 index 00000000..bfe70058 --- /dev/null +++ b/cl_dll/ammohistory.cpp @@ -0,0 +1,190 @@ +/*** +* +* 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. +* +****/ +// +// ammohistory.cpp +// + + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +#include "ammohistory.h" + +HistoryResource gHR; + +#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) +#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) +#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) + +#define MAX_ITEM_NAME 32 +int HISTORY_DRAW_TIME = 5; + +// keep a list of items +struct ITEM_INFO +{ + char szName[MAX_ITEM_NAME]; + HSPRITE spr; + wrect_t rect; +}; + +void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) +{ + if ( iType == HISTSLOT_AMMO && !iCount ) + return; // no amount, so don't add + + if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) + { // the pic would have to be drawn too high + // so start from the bottom + iCurrentHistorySlot = 0; + } + + HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot + HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); + + freeslot->type = iType; + freeslot->iId = iId; + freeslot->iCount = iCount; + freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; +} + +void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) +{ + if ( iType != HISTSLOT_ITEM ) + return; + + if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) + { // the pic would have to be drawn too high + // so start from the bottom + iCurrentHistorySlot = 0; + } + + HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot + + // I am really unhappy with all the code in this file + + int i = gHUD.GetSpriteIndex( szName ); + if ( i == -1 ) + return; // unknown sprite name, don't add it to history + + freeslot->iId = i; + freeslot->type = iType; + freeslot->iCount = iCount; + + HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); + freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; +} + + +void HistoryResource :: CheckClearHistory( void ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + return; + } + + iCurrentHistorySlot = 0; +} + +// +// Draw Ammo pickup history +// +int HistoryResource :: DrawAmmoHistory( float flTime ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + { + rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); + + if ( rgAmmoHistory[i].DisplayTime <= flTime ) + { // pic drawing time has expired + memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); + CheckClearHistory(); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) + { + wrect_t rcPic; + HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); + + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + // Draw the pic + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - 24; + if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic + { // the dll has to make sure it has sent info the weapons you need + SPR_Set( *spr, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); + } + + // Draw the number + gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) + { + WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); + + if ( !weap ) + return 1; // we don't know about the weapon yet, so don't draw anything + + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if ( !gWR.HasAmmo( weap ) ) + UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red + + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left); + SPR_Set( weap->hInactive, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) + { + int r, g, b; + + if ( !rgAmmoHistory[i].iId ) + continue; // sprite not loaded + + wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); + + UnpackRGB(r,g,b, RGB_YELLOWISH); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - (rect.right - rect.left) - 10; + + SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rect ); + } + } + } + + + return 1; +} + + diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h new file mode 100644 index 00000000..74bf43f5 --- /dev/null +++ b/cl_dll/ammohistory.h @@ -0,0 +1,143 @@ +/*** +* +* 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. +* +****/ +// +// ammohistory.h +// + +// this is the max number of items in each bucket +#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS + +class WeaponsResource +{ +private: + // Information about weapons & ammo + WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array + + // counts of weapons * ammo + WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there + int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type + +public: + void Init( void ) + { + memset( rgWeapons, 0, sizeof rgWeapons ); + Reset(); + } + + void Reset( void ) + { + iOldWeaponBits = 0; + memset( rgSlots, 0, sizeof rgSlots ); + memset( riAmmo, 0, sizeof riAmmo ); + } + +///// WEAPON ///// + int iOldWeaponBits; + + WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; } + void AddWeapon( WEAPON *wp ) + { + rgWeapons[ wp->iId ] = *wp; + LoadWeaponSprites( &rgWeapons[ wp->iId ] ); + } + + void PickupWeapon( WEAPON *wp ) + { + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; + } + + void DropWeapon( WEAPON *wp ) + { + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; + } + + void DropAllWeapons( void ) + { + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iId ) + DropWeapon( &rgWeapons[i] ); + } + } + + WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; } + + void LoadWeaponSprites( WEAPON* wp ); + void LoadAllWeaponSprites( void ); + WEAPON* GetFirstPos( int iSlot ); + void SelectSlot( int iSlot, int fAdvance, int iDirection ); + WEAPON* GetNextActivePos( int iSlot, int iSlotPos ); + + int HasAmmo( WEAPON *p ); + +///// AMMO ///// + AMMO GetAmmo( int iId ) { return iId; } + + void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; } + + int CountAmmo( int iId ); + + HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); +}; + +extern WeaponsResource gWR; + + +#define MAX_HISTORY 12 +enum { + HISTSLOT_EMPTY, + HISTSLOT_AMMO, + HISTSLOT_WEAP, + HISTSLOT_ITEM, +}; + +class HistoryResource +{ +private: + struct HIST_ITEM { + int type; + float DisplayTime; // the time at which this item should be removed from the history + int iCount; + int iId; + }; + + HIST_ITEM rgAmmoHistory[MAX_HISTORY]; + +public: + + void Init( void ) + { + Reset(); + } + + void Reset( void ) + { + memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); + } + + int iHistoryGap; + int iCurrentHistorySlot; + + void AddToHistory( int iType, int iId, int iCount = 0 ); + void AddToHistory( int iType, const char *szName, int iCount = 0 ); + + void CheckClearHistory( void ); + int DrawAmmoHistory( float flTime ); +}; + +extern HistoryResource gHR; + + + diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp new file mode 100644 index 00000000..0ec45542 --- /dev/null +++ b/cl_dll/battery.cpp @@ -0,0 +1,138 @@ +/*** +* +* 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. +* +****/ +// +// battery.cpp +// +// implementation of CHudBattery class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE(m_Battery, Battery) + +int CHudBattery::Init(void) +{ + m_iBat = 0; + m_fFade = 0; + m_iFlags = 0; + + HOOK_MESSAGE(Battery); + + gHUD.AddHudElem(this); + + return 1; +}; + + +int CHudBattery::VidInit(void) +{ + int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); + int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); + + m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded + m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty ); + m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full ); + m_iHeight = m_prc2->bottom - m_prc1->top; + m_fFade = 0; + return 1; +}; + +int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + + BEGIN_READ( pbuf, iSize ); + int x = READ_SHORT(); + + if (x != m_iBat) + { + m_fFade = FADE_TIME; + m_iBat = x; + } + + return 1; +} + + +int CHudBattery::Draw(float flTime) +{ + if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + rc = *m_prc2; + rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + // Has health changed? Flash the health # + if (m_fFade) + { + if (m_fFade > FADE_TIME) + m_fFade = FADE_TIME; + + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = 128; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + ScaleColors(r, g, b, a ); + + int iOffset = (m_prc1->bottom - m_prc1->top)/6; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = ScreenWidth/5; + + // make sure we have the right sprite handles + if ( !m_hSprite1 ) + m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); + if ( !m_hSprite2 ) + m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); + + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); + + if (rc.bottom > rc.top) + { + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); + } + + x += (m_prc1->right - m_prc1->left); + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); + + return 1; +} \ No newline at end of file diff --git a/cl_dll/camera.h b/cl_dll/camera.h new file mode 100644 index 00000000..af1591d7 --- /dev/null +++ b/cl_dll/camera.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Camera.h -- defines and such for a 3rd person camera +// NOTE: must include quakedef.h first + +#ifndef _CAMERA_H_ +#define _CAMEA_H_ + +// pitch, yaw, dist +extern vec3_t cam_ofs; +// Using third person camera +extern int cam_thirdperson; + +void CAM_Init( void ); +void CAM_ClearStates( void ); +void CAM_StartMouseMove(void); +void CAM_EndMouseMove(void); + +#endif // _CAMERA_H_ diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp new file mode 100644 index 00000000..d7b50957 --- /dev/null +++ b/cl_dll/cdll_int.cpp @@ -0,0 +1,279 @@ +/*** +* +* 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.c +// +// this implementation handles the linking of the engine to the DLL +// + +#include "hud.h" +#include "cl_util.h" +#include "netadr.h" + +extern "C" +{ +#include "pm_shared.h" +} + +#include + +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +#endif + + +cl_enginefunc_t gEngfuncs; +CHud gHUD; + +void InitInput (void); +void EV_HookEvents( void ); +void IN_Commands( void ); + +/* +========================== + Initialize + +Called when the DLL is first loaded. +========================== +*/ +extern "C" +{ +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); +int DLLEXPORT HUD_VidInit( void ); +void DLLEXPORT HUD_Init( void ); +int DLLEXPORT HUD_Redraw( float flTime, int intermission ); +int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); +void DLLEXPORT HUD_Reset ( void ); +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ); +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ); +char DLLEXPORT HUD_PlayerMoveTexture( char *name ); +int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); +void DLLEXPORT HUD_Frame( double time ); +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking); +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ); +} + +/* +================================ +HUD_GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Normal player + mins = Vector(-16, -16, -36); + maxs = Vector(16, 16, 36); + iret = 1; + break; + case 1: // Crouched player + mins = Vector(-16, -16, -18 ); + maxs = Vector(16, 16, 18 ); + iret = 1; + break; + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +HUD_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 DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *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; +} + +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) +{ + PM_Init( ppmove ); +} + +char DLLEXPORT HUD_PlayerMoveTexture( char *name ) +{ + return PM_FindTextureType( name ); +} + +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) +{ + PM_Move( ppmove, server ); +} + +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) +{ + gEngfuncs = *pEnginefuncs; + + if (iVersion != CLDLL_INTERFACE_VERSION) + return 0; + + memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + + EV_HookEvents(); + + return 1; +} + + +/* +========================== + HUD_VidInit + +Called when the game initializes +and whenever the vid_mode is changed +so the HUD can reinitialize itself. +========================== +*/ + +int DLLEXPORT HUD_VidInit( void ) +{ + gHUD.VidInit(); + + return 1; +} + +/* +========================== + HUD_Init + +Called whenever the client connects +to a server. Reinitializes all +the hud variables. +========================== +*/ + +void DLLEXPORT HUD_Init( void ) +{ + InitInput(); + gHUD.Init(); +} + + +/* +========================== + HUD_Redraw + +called every screen frame to +redraw the HUD. +=========================== +*/ + +int DLLEXPORT HUD_Redraw( float time, int intermission ) +{ + gHUD.Redraw( time, intermission ); + + return 1; +} + + +/* +========================== + HUD_UpdateClientData + +called every time shared client +dll/engine data gets changed, +and gives the cdll a chance +to modify the data. + +returns 1 if anything has been changed, 0 otherwise. +========================== +*/ + +int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) +{ + IN_Commands(); + + return gHUD.UpdateClientData(pcldata, flTime ); +} + +/* +========================== + HUD_Reset + +Called at start and end of demos to restore to "non"HUD state. +========================== +*/ + +void DLLEXPORT HUD_Reset( void ) +{ + gHUD.VidInit(); +} + +/* +========================== +HUD_Frame + +Called by engine every frame that client .dll is loaded +========================== +*/ + +void DLLEXPORT HUD_Frame( double time ) +{ +} + + +/* +========================== +HUD_VoiceStatus + +Called when a player starts or stops talking. +========================== +*/ + +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +{ + +} + +/* +========================== +HUD_DirectorEvent + +Called when a director event message was received +========================== +*/ + +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) +{ + gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); +} + + diff --git a/cl_dll/cl_dll.dsp b/cl_dll/cl_dll.dsp new file mode 100644 index 00000000..6864326b --- /dev/null +++ b/cl_dll/cl_dll.dsp @@ -0,0 +1,624 @@ +# Microsoft Developer Studio Project File - Name="cl_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cl_dll - 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 "cl_dll.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 "cl_dll.mak" CFG="cl_dll - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cl_dll - 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 "..\temp\cl_dll\!release" +# PROP Intermediate_Dir "..\temp\cl_dll\!release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /YX /FD /c +# SUBTRACT CPP /Z +# 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 winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"..\temp\cl_dll\!release/client.dll" +# SUBTRACT LINK32 /map +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\cl_dll\!release +InputPath=\Xash3D\src_main\temp\cl_dll\!release\client.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\cl_dlls\client.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\temp\cl_dll\!debug" +# PROP Intermediate_Dir "..\temp\cl_dll\!debug" +# 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 /GR /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\vgui\include" /I "..\game_shared" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "CLIENT_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 /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 oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\temp\cl_dll\!debug/client.dll" +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\cl_dll\!debug +InputPath=\Xash3D\src_main\temp\cl_dll\!debug\client.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\cl_dlls\client.dll" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "cl_dll - Win32 Release" +# Name "cl_dll - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Group "hl" + +# PROP Default_Filter "*.CPP" +# Begin Source File + +SOURCE=..\dlls\crossbow.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\crowbar.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\egon.cpp +# End Source File +# Begin Source File + +SOURCE=.\ev_hldm.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\gauss.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\handgrenade.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_baseentity.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_events.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_objects.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_weapons.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\glock.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\hornetgun.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\mp5.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\python.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\rpg.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\satchel.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\shotgun.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\squeakgrenade.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\tripmine.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_scrollbar2.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_slider2.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_banmgr.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_status.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ammo.cpp +# End Source File +# Begin Source File + +SOURCE=.\ammo_secondary.cpp +# End Source File +# Begin Source File + +SOURCE=.\ammohistory.cpp +# End Source File +# Begin Source File + +SOURCE=.\battery.cpp +# End Source File +# Begin Source File + +SOURCE=.\cdll_int.cpp +# End Source File +# Begin Source File + +SOURCE=.\com_weapons.cpp +# End Source File +# Begin Source File + +SOURCE=.\death.cpp +# End Source File +# Begin Source File + +SOURCE=.\demo.cpp +# End Source File +# Begin Source File + +SOURCE=.\entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\ev_common.cpp +# End Source File +# Begin Source File + +SOURCE=.\events.cpp +# End Source File +# Begin Source File + +SOURCE=.\flashlight.cpp +# End Source File +# Begin Source File + +SOURCE=.\GameStudioModelRenderer.cpp +# End Source File +# Begin Source File + +SOURCE=.\geiger.cpp +# End Source File +# Begin Source File + +SOURCE=.\health.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud_msg.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud_redraw.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud_servers.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud_spectator.cpp +# End Source File +# Begin Source File + +SOURCE=.\hud_update.cpp +# End Source File +# Begin Source File + +SOURCE=.\in_camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\input.cpp +# End Source File +# Begin Source File + +SOURCE=.\inputw32.cpp +# End Source File +# Begin Source File + +SOURCE=.\menu.cpp +# End Source File +# Begin Source File + +SOURCE=.\message.cpp +# End Source File +# Begin Source File + +SOURCE=.\overview.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\parsemsg.cpp +# End Source File +# Begin Source File + +SOURCE=.\parsemsg.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_debug.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_math.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.c +# End Source File +# Begin Source File + +SOURCE=.\saytext.cpp +# End Source File +# Begin Source File + +SOURCE=.\status_icons.cpp +# End Source File +# Begin Source File + +SOURCE=.\statusbar.cpp +# End Source File +# Begin Source File + +SOURCE=.\studio_util.cpp +# End Source File +# Begin Source File + +SOURCE=.\StudioModelRenderer.cpp +# End Source File +# Begin Source File + +SOURCE=.\text_message.cpp +# End Source File +# Begin Source File + +SOURCE=.\train.cpp +# End Source File +# Begin Source File + +SOURCE=.\tri.cpp +# End Source File +# Begin Source File + +SOURCE=.\util.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_checkbutton2.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ClassMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ConsolePanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ControlConfigPanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_CustomObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_grid.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_helpers.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_listbox.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_loadtga.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_MOTDWindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_SpectatorPanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_teammenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\view.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\ammo.h +# End Source File +# Begin Source File + +SOURCE=.\ammohistory.h +# End Source File +# Begin Source File + +SOURCE=.\camera.h +# End Source File +# Begin Source File + +SOURCE=.\cl_dll.h +# End Source File +# Begin Source File + +SOURCE=.\com_weapons.h +# End Source File +# Begin Source File + +SOURCE=.\demo.h +# End Source File +# Begin Source File + +SOURCE=.\ev_hldm.h +# End Source File +# Begin Source File + +SOURCE=.\eventscripts.h +# End Source File +# Begin Source File + +SOURCE=.\GameStudioModelRenderer.h +# End Source File +# Begin Source File + +SOURCE=.\health.h +# End Source File +# Begin Source File + +SOURCE=.\hud.h +# End Source File +# Begin Source File + +SOURCE=.\hud_iface.h +# End Source File +# Begin Source File + +SOURCE=.\hud_servers.h +# End Source File +# Begin Source File + +SOURCE=.\hud_servers_priv.h +# End Source File +# Begin Source File + +SOURCE=.\hud_spectator.h +# End Source File +# Begin Source File + +SOURCE=.\in_defs.h +# End Source File +# Begin Source File + +SOURCE=..\common\itrackeruser.h +# End Source File +# Begin Source File + +SOURCE=.\kbutton.h +# End Source File +# Begin Source File + +SOURCE=.\overview.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=.\studio_util.h +# End Source File +# Begin Source File + +SOURCE=.\StudioModelRenderer.h +# End Source File +# Begin Source File + +SOURCE=.\util.h +# End Source File +# Begin Source File + +SOURCE=.\util_vector.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ConsolePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ControlConfigPanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_SpectatorPanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.h +# End Source File +# Begin Source File + +SOURCE=.\view.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_banmgr.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_status.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_vgui_tweakdlg.h +# End Source File +# Begin Source File + +SOURCE=.\wrect.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/cl_dll/cl_dll.h b/cl_dll/cl_dll.h new file mode 100644 index 00000000..99020179 --- /dev/null +++ b/cl_dll/cl_dll.h @@ -0,0 +1,43 @@ +/*** +* +* 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. +* +****/ +// +// cl_dll.h +// + +// 4-23-98 JOHN + +// +// This DLL is linked by the client when they first initialize. +// This DLL is responsible for the following tasks: +// - Loading the HUD graphics upon initialization +// - Drawing the HUD graphics every frame +// - Handling the custum HUD-update packets +// +typedef unsigned char byte; +typedef unsigned short word; +typedef float vec_t; +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); + +#include "util_vector.h" +#define EXPORT _declspec( dllexport ) + +#include "../engine/cdll_int.h" +#include "../dlls/cdll_dll.h" + + +#define _cdecl +#include + +extern cl_enginefunc_t gEngfuncs; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h new file mode 100644 index 00000000..e949e2c5 --- /dev/null +++ b/cl_dll/cl_util.h @@ -0,0 +1,162 @@ +/*** +* +* 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. +* +****/ +// +// cl_util.h +// + +#include "cvardef.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +// Macros to hook function calls into the HUD object + +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); + +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ + { \ + return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } + + +#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + gHUD.y.UserCmd_##x( ); \ + } + + +inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } +inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } +inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } + +#define SPR_Load (*gEngfuncs.pfnSPR_Load) +#define SPR_Set (*gEngfuncs.pfnSPR_Set) +#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) +#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) + +// SPR_Draw draws a the current sprite as solid +#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) +// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) +#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) +// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) +#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) + +// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. +#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) +// SPR_DisableScissor disables the clipping rect +#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) +// +#define FillRGBA (*gEngfuncs.pfnFillRGBA) + + +// ScreenHeight returns the height of the screen, in pixels +#define ScreenHeight (gHUD.m_scrinfo.iHeight) +// ScreenWidth returns the width of the screen, in pixels +#define ScreenWidth (gHUD.m_scrinfo.iWidth) + +// Use this to set any co-ords in 640x480 space +#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) +#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) + +// use this to project world coordinates to screen coordinates +#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f ) +#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f ) + +#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) +#define ServerCmd (*gEngfuncs.pfnServerCmd) +#define ClientCmd (*gEngfuncs.pfnClientCmd) +#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) +#define AngleVectors (*gEngfuncs.pfnAngleVectors) + + +// Gets the height & width of a sprite, at the specified frame +inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } +inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } + +inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } +inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) +{ + return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); +} + +inline int DrawConsoleString( int x, int y, const char *string ) +{ + return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); +} + +inline void GetConsoleStringSize( const char *string, int *width, int *height ) +{ + gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); +} + +inline int ConsoleStringLen( const char *string ) +{ + int _width, _height; + GetConsoleStringSize( string, &_width, &_height ); + return _width; +} + +inline void ConsolePrint( const char *string ) +{ + gEngfuncs.pfnConsolePrint( string ); +} + +inline void CenterPrint( const char *string ) +{ + gEngfuncs.pfnCenterPrint( string ); +} + +// returns the players name of entity no. +#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) + +// sound functions +inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } +inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) + +void ScaleColors( int &r, int &g, int &b, int a ); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#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];} +inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} +float Length(const float *v); +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); +void VectorScale (const float *in, float scale, float *out); +float VectorNormalize (float *v); +void VectorInverse ( float *v ); + +extern vec3_t vec3_origin; + +// disable 'possible loss of data converting float to int' warning message +#pragma warning( disable: 4244 ) +// disable 'truncation from 'const double' to 'float' warning message +#pragma warning( disable: 4305 ) + +inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ +{\ + r = (ulRGB & 0xFF0000) >>16;\ + g = (ulRGB & 0xFF00) >> 8;\ + b = ulRGB & 0xFF;\ +} + +HSPRITE LoadSprite(const char *pszName); diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp new file mode 100644 index 00000000..66b1c82d --- /dev/null +++ b/cl_dll/com_weapons.cpp @@ -0,0 +1,277 @@ +/*** +* +* 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. +* +****/ + +// Com_Weapons.cpp +// Shared weapons common/shared functions +#include +#include "hud.h" +#include "cl_util.h" +#include "com_weapons.h" + +#include "const.h" +#include "entity_state.h" +#include "r_efx.h" + +// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing +// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be +// updating state info, but not firing events +int g_runfuncs = 0; + +// During our weapon prediction processing, we'll need to reference some data that is part of +// the final state passed into the postthink functionality. We'll set this pointer and then +// reset it to NULL as appropriate +struct local_state_s *g_finalstate = NULL; + +/* +==================== +COM_Log + +Log debug messages to file ( appends ) +==================== +*/ +void COM_Log( char *pszFile, char *fmt, ...) +{ + va_list argptr; + char string[1024]; + FILE *fp; + char *pfilename; + + if ( !pszFile ) + { + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + fp = fopen( pfilename, "a+t"); + if (fp) + { + fprintf(fp, "%s", string); + fclose(fp); + } +} + +// remember the current animation for the view model, in case we get out of sync with +// server. +static int g_currentanim; + +/* +===================== +HUD_SendWeaponAnim + +Change weapon model animation +===================== +*/ +void HUD_SendWeaponAnim( int iAnim, int body, int force ) +{ + // Don't actually change it. + if ( !g_runfuncs && !force ) + return; + + g_currentanim = iAnim; + + // Tell animation system new info + gEngfuncs.pfnWeaponAnim( iAnim, body ); +} + +/* +===================== +HUD_GetWeaponAnim + +Retrieve current predicted weapon animation +===================== +*/ +int HUD_GetWeaponAnim( void ) +{ + return g_currentanim; +} + +/* +===================== +HUD_PlaySound + +Play a sound, if we are seeing this command for the first time +===================== +*/ +void HUD_PlaySound( char *sound, float volume ) +{ + if ( !g_runfuncs || !g_finalstate ) + return; + + gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); +} + +/* +===================== +HUD_PlaybackEvent + +Directly queue up an event on the client +===================== +*/ +void HUD_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 ) +{ + vec3_t org; + vec3_t ang; + + if ( !g_runfuncs || !g_finalstate ) + return; + + // Weapon prediction events are assumed to occur at the player's origin + org = g_finalstate->playerstate.origin; + ang = v_angles; + gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); +} + +/* +===================== +HUD_SetMaxSpeed + +===================== +*/ +void HUD_SetMaxSpeed( const edict_t *ed, float speed ) +{ +} + + +/* +===================== +UTIL_WeaponTimeBase + +Always 0.0 on client, even if not predicting weapons ( won't get called + in that case ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +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 = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +/* +====================== +stub_* + +stub functions for such things as precaching. So we don't have to modify weapons code that + is compiled into both game and client .dlls. +====================== +*/ +int stub_PrecacheModel ( char* s ) { return 0; } +int stub_PrecacheSound ( char* s ) { return 0; } +unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } +const char *stub_NameForFunction ( unsigned long function ) { return "func"; } +void stub_SetModel ( edict_t *e, const char *m ) {} diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h new file mode 100644 index 00000000..e2fd2749 --- /dev/null +++ b/cl_dll/com_weapons.h @@ -0,0 +1,48 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_weapons.h +// Shared weapons common function prototypes +#if !defined( COM_WEAPONSH ) +#define COM_WEAPONSH +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_iface.h" + +extern "C" +{ + void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +} + +void COM_Log( char *pszFile, char *fmt, ...); +int CL_IsDead( void ); + +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); + +int HUD_GetWeaponAnim( void ); +void HUD_SendWeaponAnim( int iAnim, int body, int force ); +void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaybackEvent( 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 ); +void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); +int stub_PrecacheModel( char* s ); +int stub_PrecacheSound( char* s ); +unsigned short stub_PrecacheEvent( int type, const char *s ); +const char *stub_NameForFunction ( unsigned long function ); +void stub_SetModel ( struct edict_s *e, const char *m ); + + +extern cvar_t *cl_lw; + +extern int g_runfuncs; +extern vec3_t v_angles; +extern float g_lastFOV; +extern struct local_state_s *g_finalstate; + +#endif \ No newline at end of file diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp new file mode 100644 index 00000000..bd940f86 --- /dev/null +++ b/cl_dll/death.cpp @@ -0,0 +1,303 @@ +/*** +* +* 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. +* +****/ +// +// death notice +// +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); + +struct DeathNoticeItem { + char szKiller[MAX_PLAYER_NAME_LENGTH*2]; + char szVictim[MAX_PLAYER_NAME_LENGTH*2]; + int iId; // the index number of the associated sprite + int iSuicide; + int iTeamKill; + int iNonPlayerKill; + float flDisplayTime; + float *KillerColor; + float *VictimColor; +}; + +#define MAX_DEATHNOTICES 4 +static int DEATHNOTICE_DISPLAY_TIME = 6; + +#define DEATHNOTICE_TOP 32 + +DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; + +float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; +float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; +float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; +float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; +float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; + +float *GetClientColor( int clientIndex ) +{ + switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) + { + case 1: return g_ColorBlue; + case 2: return g_ColorRed; + case 3: return g_ColorYellow; + case 4: return g_ColorGreen; + case 0: return g_ColorYellow; + + default : return g_ColorGrey; + } + + return NULL; +} + +int CHudDeathNotice :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( DeathMsg ); + + CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); + + return 1; +} + + +void CHudDeathNotice :: InitHUDData( void ) +{ + memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); +} + + +int CHudDeathNotice :: VidInit( void ) +{ + m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); + + return 1; +} + +int CHudDeathNotice :: Draw( float flTime ) +{ + int x, y, r, g, b; + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; // we've gone through them all + + if ( rgDeathNoticeList[i].flDisplayTime < flTime ) + { // display time has expired + // remove the current item from the list + memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); + i--; // continue on the next item; stop the counter getting incremented + continue; + } + + rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); + + // Only draw if the viewport will let me + // vgui dropped out + //if ( gViewPort && gViewPort->AllowedToPrintText() ) + { + // Draw the death notice + y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!! + + int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + if ( !rgDeathNoticeList[i].iSuicide ) + { + x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + + // Draw killers name + if ( rgDeathNoticeList[i].KillerColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + } + + r = 255; g = 80; b = 0; + if ( rgDeathNoticeList[i].iTeamKill ) + { + r = 10; g = 240; b = 10; // display it in sickly green + } + + // Draw death weapon + SPR_Set( gHUD.GetSprite(id), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); + + x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + // Draw victims name (if it was a player that was killed) + if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + { + if ( rgDeathNoticeList[i].VictimColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); + } + } + } + + return 1; +} + +// This message handler may be better off elsewhere +int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + BEGIN_READ( pbuf, iSize ); + + int killer = READ_BYTE(); + int victim = READ_BYTE(); + + char killedwith[32]; + strcpy( killedwith, "d_" ); + strncat( killedwith, READ_STRING(), 32 ); + + + gHUD.m_Spectator.DeathMessage(victim); + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; + } + if ( i == MAX_DEATHNOTICES ) + { // move the rest of the list forward to make room for this item + memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); + i = MAX_DEATHNOTICES - 1; + } + + //if (gViewPort) + // gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + // Get the Killer's name + char *killer_name = g_PlayerInfoList[ killer ].name; + if ( !killer_name ) + { + killer_name = ""; + rgDeathNoticeList[i].szKiller[0] = 0; + } + else + { + rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); + strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Get the Victim's name + char *victim_name = NULL; + // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) + if ( ((char)victim) != -1 ) + victim_name = g_PlayerInfoList[ victim ].name; + if ( !victim_name ) + { + victim_name = ""; + rgDeathNoticeList[i].szVictim[0] = 0; + } + else + { + rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); + strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Is it a non-player object kill? + if ( ((char)victim) == -1 ) + { + rgDeathNoticeList[i].iNonPlayerKill = TRUE; + + // Store the object's name in the Victim slot (skip the d_ bit) + strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); + } + else + { + if ( killer == victim || killer == 0 ) + rgDeathNoticeList[i].iSuicide = TRUE; + + if ( !strcmp( killedwith, "d_teammate" ) ) + rgDeathNoticeList[i].iTeamKill = TRUE; + } + + // Find the sprite in the list + int spr = gHUD.GetSpriteIndex( killedwith ); + + rgDeathNoticeList[i].iId = spr; + + DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); + rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; + + if (rgDeathNoticeList[i].iNonPlayerKill) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed a " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + ConsolePrint( "\n" ); + } + else + { + // record the death notice in the console + if ( rgDeathNoticeList[i].iSuicide ) + { + ConsolePrint( rgDeathNoticeList[i].szVictim ); + + if ( !strcmp( killedwith, "d_world" ) ) + { + ConsolePrint( " died" ); + } + else + { + ConsolePrint( " killed self" ); + } + } + else if ( rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed his teammate " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + else + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + + if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( " with " ); + + // replace the code names with the 'real' names + if ( !strcmp( killedwith+2, "egon" ) ) + strcpy( killedwith, "d_gluon gun" ); + if ( !strcmp( killedwith+2, "gauss" ) ) + strcpy( killedwith, "d_tau cannon" ); + + ConsolePrint( killedwith+2 ); // skip over the "d_" part + } + + ConsolePrint( "\n" ); + } + + return 1; +} + + + + diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp new file mode 100644 index 00000000..88e7f66f --- /dev/null +++ b/cl_dll/demo.cpp @@ -0,0 +1,107 @@ +/*** +* +* 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 "hud.h" +#include "cl_util.h" +#include "demo.h" +#include "demo_api.h" +#include + +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +#endif + +int g_demosniper = 0; +int g_demosniperdamage = 0; +float g_demosniperorg[3]; +float g_demosniperangles[3]; +float g_demozoom; + +// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. + +extern "C" +{ + void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ); +} + +/* +===================== +Demo_WriteBuffer + +Write some data to the demo stream +===================== +*/ +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) +{ + int pos = 0; + unsigned char buf[ 32 * 1024 ]; + *( int * )&buf[pos] = type; + pos+=sizeof( int ); + + memcpy( &buf[pos], buffer, size ); + + // Write full buffer out + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); +} + +/* +===================== +Demo_ReadBuffer + +Engine wants us to parse some data from the demo stream +===================== +*/ +void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) +{ + int type; + int i = 0; + + type = *( int * )buffer; + i += sizeof( int ); + switch ( type ) + { + case TYPE_SNIPERDOT: + g_demosniper = *(int * )&buffer[ i ]; + i += sizeof( int ); + + if ( g_demosniper ) + { + g_demosniperdamage = *( int * )&buffer[ i ]; + i += sizeof( int ); + + g_demosniperangles[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + } + break; + case TYPE_ZOOM: + g_demozoom = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + default: + gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); + break; + } +} \ No newline at end of file diff --git a/cl_dll/demo.h b/cl_dll/demo.h new file mode 100644 index 00000000..c5a5057b --- /dev/null +++ b/cl_dll/demo.h @@ -0,0 +1,27 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( DEMOH ) +#define DEMOH +#pragma once + +// Types of demo messages we can write/parse +enum +{ + TYPE_SNIPERDOT = 0, + TYPE_ZOOM +}; + +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); + +extern int g_demosniper; +extern int g_demosniperdamage; +extern float g_demosniperorg[3]; +extern float g_demosniperangles[3]; +extern float g_demozoom; + +#endif \ No newline at end of file diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp new file mode 100644 index 00000000..ad4a8411 --- /dev/null +++ b/cl_dll/entity.cpp @@ -0,0 +1,980 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Client side entity management functions + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_types.h" +#include "studio_event.h" // def. of mstudioevent_t +#include "r_efx.h" +#include "event_api.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "pm_shared.h" + +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +#endif + + +void Game_AddObjects( void ); + +extern vec3_t v_origin; + +int g_iAlive = 1; + +extern "C" +{ + int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void DLLEXPORT HUD_CreateEntities( void ); + void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); + void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); + void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); + void DLLEXPORT HUD_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 ); + void DLLEXPORT HUD_TempEntUpdate( 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 ) ); + struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index ); +} + +/* +======================== +HUD_AddEntity + Return 0 to filter entity from visible list for rendering +======================== +*/ +int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) +{ + switch ( type ) + { + case ET_NORMAL: + case ET_PLAYER: + case ET_BEAM: + case ET_TEMPENTITY: + case ET_FRAGMENTED: + default: + break; + } + // each frame every entity passes this function, so the overview hooks it to filter the overview entities + // in spectator mode: + // each frame every entity passes this function, so the overview hooks + // it to filter the overview entities + + if ( g_iUser1 ) + { + gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && + ent->index == g_iUser2 ) + return 0; // don't draw the player we are following in eye + + } + + return 1; +} + +/* +========================= +HUD_TxferLocalOverrides + +The server sends us our origin with extra precision as part of the clientdata structure, not during the normal +playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate +structure, we need to copy them into the state structure at this point. +========================= +*/ +void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) +{ + VectorCopy( client->origin, state->origin ); + + // Spectator + state->iuser1 = client->iuser1; + state->iuser2 = client->iuser2; + + // Duck prevention + state->iuser3 = client->iuser3; + + // Fire prevention + state->iuser4 = client->iuser4; +} + +/* +========================= +HUD_ProcessPlayerState + +We have received entity_state_t for this player over the network. We need to copy appropriate fields to the +playerstate structure +========================= +*/ +void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) +{ + // Copy in network data + VectorCopy( src->origin, dst->origin ); + VectorCopy( src->angles, dst->angles ); + + VectorCopy( src->velocity, dst->velocity ); + + dst->frame = src->frame; + dst->modelindex = src->modelindex; + dst->skin = src->skin; + dst->effects = src->effects; + dst->weaponmodel = src->weaponmodel; + dst->movetype = src->movetype; + dst->sequence = src->sequence; + dst->animtime = src->animtime; + + dst->solid = src->solid; + + dst->rendermode = src->rendermode; + dst->renderamt = src->renderamt; + dst->rendercolor.r = src->rendercolor.r; + dst->rendercolor.g = src->rendercolor.g; + dst->rendercolor.b = src->rendercolor.b; + dst->renderfx = src->renderfx; + + dst->framerate = src->framerate; + dst->body = src->body; + + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + + VectorCopy( src->basevelocity, dst->basevelocity ); + + dst->friction = src->friction; + dst->gravity = src->gravity; + dst->gaitsequence = src->gaitsequence; + dst->spectator = src->spectator; + dst->usehull = src->usehull; + dst->playerclass = src->playerclass; + dst->team = src->team; + dst->colormap = src->colormap; + + // Save off some data so other areas of the Client DLL can get to it + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index + if ( dst->number == player->index ) + { + g_iPlayerClass = dst->playerclass; + g_iTeamNumber = dst->team; + + g_iUser1 = src->iuser1; + g_iUser2 = src->iuser2; + g_iUser3 = src->iuser3; + } +} + +/* +========================= +HUD_TxferPredictionData + +Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in + from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's + up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server + update is occupying. +========================= +*/ +void DLLEXPORT HUD_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 ) +{ + ps->oldbuttons = pps->oldbuttons; + ps->flFallVelocity = pps->flFallVelocity; + ps->iStepLeft = pps->iStepLeft; + ps->playerclass = pps->playerclass; + + pcd->viewmodel = ppcd->viewmodel; + pcd->m_iId = ppcd->m_iId; + pcd->ammo_shells = ppcd->ammo_shells; + pcd->ammo_nails = ppcd->ammo_nails; + pcd->ammo_cells = ppcd->ammo_cells; + pcd->ammo_rockets = ppcd->ammo_rockets; + pcd->m_flNextAttack = ppcd->m_flNextAttack; + pcd->fov = ppcd->fov; + pcd->weaponanim = ppcd->weaponanim; + pcd->tfstate = ppcd->tfstate; + pcd->maxspeed = ppcd->maxspeed; + + pcd->deadflag = ppcd->deadflag; + + // Spectating or not dead == get control over view angles. + g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; + + // Spectator + pcd->iuser1 = ppcd->iuser1; + pcd->iuser2 = ppcd->iuser2; + + // Duck prevention + pcd->iuser3 = ppcd->iuser3; + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in specator mode we tell the engine who we want to spectate and how + // iuser3 is not used for duck prevention (since the spectator can't duck at all) + pcd->iuser1 = g_iUser1; // observer mode + pcd->iuser2 = g_iUser2; // first target + pcd->iuser3 = g_iUser3; // second target + + } + + // Fire prevention + pcd->iuser4 = ppcd->iuser4; + + pcd->fuser2 = ppcd->fuser2; + pcd->fuser3 = ppcd->fuser3; + + VectorCopy( ppcd->vuser1, pcd->vuser1 ); + VectorCopy( ppcd->vuser2, pcd->vuser2 ); + VectorCopy( ppcd->vuser3, pcd->vuser3 ); + VectorCopy( ppcd->vuser4, pcd->vuser4 ); + + memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); +} + +/* +//#define TEST_IT +#if defined( TEST_IT ) + +cl_entity_t mymodel[9]; + +void MoveModel( void ) +{ + cl_entity_t *player; + int i, j; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + // Don't draw over ourself... + if ( ( i == 1 ) && ( j == 1 ) ) + continue; + + mymodel[ i * 3 + j ] = *player; + + mymodel[ i * 3 + j ].player = 0; + + mymodel[ i * 3 + j ].model = mod; + mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + + // Move it out a bit + mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + } + } + +} + +#endif + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern int hitent; + +cl_entity_t hit; + +void TraceModel( void ) +{ + cl_entity_t *ent; + + if ( hitent <= 0 ) + return; + + // Load it up with some bogus data + ent = gEngfuncs.GetEntityByIndex( hitent ); + if ( !ent ) + return; + + hit = *ent; + //hit.curstate.rendermode = kRenderTransTexture; + //hit.curstate.renderfx = kRenderFxGlowShell; + //hit.curstate.renderamt = 100; + + hit.origin[2] += 40; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); +} + +#endif +*/ + +/* +void ParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + particle->org[ i ] += particle->vel[ i ] * frametime; + } +} + +cvar_t *color = NULL; +void Particles( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 2.0 ) + return; + + if ( !color ) + { + color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); + } + + lasttime = curtime; + + // Create a few particles + particle_t *p; + int i, j; + + for ( i = 0; i < 1000; i++ ) + { + int r, g, b; + p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; + p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + } + + if ( color ) + { + sscanf( color->string, "%i %i %i", &r, &g, &b ); + } + else + { + r = 192; + g = 0; + b = 0; + } + + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 3.0; + } +} +*/ + +/* +void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + } +} + +void TempEnts( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + lasttime = curtime; + + TEMPENTITY *p; + int i, j; + struct model_s *mod; + vec3_t origin; + int index; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); + + for ( i = 0; i < 100; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + origin[ j ] = v_origin[ j ]; + if ( j != 2 ) + { + origin[ j ] += 75; + } + } + + p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->entity.curstate.origin[ j ] = origin[ j ]; + + // Store velocity in baseline origin + p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + } + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 10.0; + } +} +*/ + +#if defined( BEAM_TEST ) +// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Room for 1 beam ( 0 can't be used ) +static cl_entity_t beams[ 2 ]; + +void BeamEndModel( void ) +{ + cl_entity_t *player, *model; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + if ( !mod ) + return; + + // Slot 1 + model = &beams[ 1 ]; + + *model = *player; + model->player = 0; + model->model = mod; + model->curstate.modelindex = modelindex; + + // Move it out a bit + model->origin[0] = player->origin[0] - 100; + model->origin[1] = player->origin[1]; + + model->attachment[0] = model->origin; + model->attachment[1] = model->origin; + model->attachment[2] = model->origin; + model->attachment[3] = model->origin; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); +} + +void Beams( void ) +{ + static float lasttime; + float curtime; + struct model_s *mod; + int index; + + BeamEndModel(); + + curtime = gEngfuncs.GetClientTime(); + float end[ 3 ]; + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); + if ( !mod ) + return; + + lasttime = curtime; + + end [ 0 ] = v_origin.x + 100; + end [ 1 ] = v_origin.y + 100; + end [ 2 ] = v_origin.z; + + BEAM *p1; + p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, + 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); +} +#endif + +/* +========================= +HUD_CreateEntities + +Gives us a chance to add additional entities to the render this frame +========================= +*/ +void DLLEXPORT HUD_CreateEntities( void ) +{ + // e.g., create a persistent cl_entity_t somewhere. + // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) + // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list +/* +#if defined( TEST_IT ) + MoveModel(); +#endif + +#if defined( TRACE_TEST ) + TraceModel(); +#endif +*/ +/* + Particles(); +*/ +/* + TempEnts(); +*/ + +#if defined( BEAM_TEST ) + Beams(); +#endif + + // Add in any game specific objects + Game_AddObjects(); +} + +/* +========================= +HUD_StudioEvent + +The entity's studio model description indicated an event was +fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) +========================= +*/ +void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) +{ + switch( event->event ) + { + case 5001: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + break; + case 5011: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + break; + case 5021: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + break; + case 5031: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + break; + case 5002: + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + break; + // Client side sound + case 5004: + gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); + break; + default: + break; + } +} + +/* +================= +CL_UpdateTEnts + +Simulation and cleanup of temporary entities +================= +*/ +void DLLEXPORT HUD_TempEntUpdate ( + double frametime, // Simulation time + double client_time, // Absolute time on client + double cl_gravity, // True gravity on client + TEMPENTITY **ppTempEntFree, // List of freed temporary ents + TEMPENTITY **ppTempEntActive, // List + int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), + void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) +{ + static int gTempEntFrame = 0; + int i; + TEMPENTITY *pTemp, *pnext, *pprev; + float freq, gravity, gravitySlow, life, fastFreq; + + // Nothing to simulate + if ( !*ppTempEntActive ) + return; + + // in order to have tents collide with players, we have to run the player prediction code so + // that the client has the player list. We run this code once when we detect any COLLIDEALL + // tent, then set this BOOL to true so the code doesn't get run again if there's more than + // one COLLIDEALL ent for this update. (often are). + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); + + // !!!BUGBUG -- This needs to be time based + gTempEntFrame = (gTempEntFrame+1) & 31; + + pTemp = *ppTempEntActive; + + // !!! Don't simulate while paused.... This is sort of a hack, revisit. + if ( frametime <= 0 ) + { + while ( pTemp ) + { + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + Callback_AddVisibleEntity( &pTemp->entity ); + } + pTemp = pTemp->next; + } + goto finish; + } + + pprev = NULL; + freq = client_time * 0.01; + fastFreq = client_time * 5.5; + gravity = -frametime * cl_gravity; + gravitySlow = gravity * 0.5; + + while ( pTemp ) + { + int active; + + active = 1; + + life = pTemp->die - client_time; + pnext = pTemp->next; + if ( life < 0 ) + { + if ( pTemp->flags & FTENT_FADEOUT ) + { + if (pTemp->entity.curstate.rendermode == kRenderNormal) + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); + if ( pTemp->entity.curstate.renderamt <= 0 ) + active = 0; + + } + else + active = 0; + } + if ( !active ) // Kill it + { + pTemp->next = *ppTempEntFree; + *ppTempEntFree = pTemp; + if ( !pprev ) // Deleting at head of list + *ppTempEntActive = pnext; + else + pprev->next = pnext; + } + else + { + pprev = pTemp; + + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Adjust speed if it's time + // Scale is next think time + if ( client_time > pTemp->entity.baseline.scale ) + { + // Show Sparks + gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); + + // Reduce life + pTemp->entity.baseline.framerate -= 0.1; + + if ( pTemp->entity.baseline.framerate <= 0.0 ) + { + pTemp->die = client_time; + } + else + { + // So it will die no matter what + pTemp->die = client_time + 0.5; + + // Next think + pTemp->entity.baseline.scale = client_time + 0.1; + } + } + } + else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + { + cl_entity_t *pClient; + + pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); + + VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); + } + else if ( pTemp->flags & FTENT_SINEWAVE ) + { + pTemp->x += pTemp->entity.baseline.origin[0] * frametime; + pTemp->y += pTemp->entity.baseline.origin[1] * frametime; + + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else if ( pTemp->flags & FTENT_SPIRAL ) + { + float s, c; + s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); + + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + + else + { + for ( i = 0; i < 3; i++ ) + pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; + } + + if ( pTemp->flags & FTENT_SPRANIMATE ) + { + pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + + if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + { + // this animating sprite isn't set to loop, so destroy it. + pTemp->die = client_time; + pTemp = pnext; + continue; + } + } + } + else if ( pTemp->flags & FTENT_SPRCYCLE ) + { + pTemp->entity.curstate.frame += frametime * 10; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + } + } +// Experiment +#if 0 + if ( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); +#endif + + if ( pTemp->flags & FTENT_ROTATE ) + { + pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; + pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; + pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; + + VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); + } + + if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + { + vec3_t traceNormal; + float traceFraction = 1; + + if ( pTemp->flags & FTENT_COLLIDEALL ) + { + pmtrace_t pmtrace; + physent_t *pe; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); + + + if ( pmtrace.fraction != 1 ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); + + if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + } + else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + { + pmtrace_t pmtrace; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + + if ( pmtrace.fraction != 1 ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Chop spark speeds a bit more + // + VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); + + if ( Length( pTemp->entity.baseline.origin ) < 10 ) + { + pTemp->entity.baseline.framerate = 0.0; + } + } + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + + if ( traceFraction != 1 ) // Decent collision now, and damping works + { + float proj, damp; + + // Place at contact point + VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + // Damp velocity + damp = pTemp->bounceFactor; + if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + { + damp *= 0.5; + if ( traceNormal[2] > 0.9 ) // Hit floor? + { + if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + { + damp = 0; // Stop + pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->entity.angles[0] = 0; + pTemp->entity.angles[2] = 0; + } + } + } + + if (pTemp->hitSound) + { + Callback_TempEntPlaySound(pTemp, damp); + } + + if (pTemp->flags & FTENT_COLLIDEKILL) + { + // die on impact + pTemp->flags &= ~FTENT_FADEOUT; + pTemp->die = client_time; + } + else + { + // Reflect velocity + if ( damp != 0 ) + { + proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); + VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + // Reflect rotation (fake) + + pTemp->entity.angles[1] = -pTemp->entity.angles[1]; + } + + if ( damp != 1 ) + { + + VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); + VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); + } + } + } + } + + + if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + { + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); + VectorCopy (pTemp->entity.origin, dl->origin); + dl->radius = 60; + dl->color.r = 255; + dl->color.g = 120; + dl->color.b = 0; + dl->die = client_time + 0.01; + } + + if ( pTemp->flags & FTENT_SMOKETRAIL ) + { + gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + } + + if ( pTemp->flags & FTENT_GRAVITY ) + pTemp->entity.baseline.origin[2] += gravity; + else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + pTemp->entity.baseline.origin[2] += gravitySlow; + + if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + { + if ( pTemp->callback ) + { + ( *pTemp->callback )( pTemp, frametime, client_time ); + } + } + + // Cull to PVS (not frustum cull, just PVS) + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + { + if ( !(pTemp->flags & FTENT_PERSIST) ) + { + pTemp->die = client_time; // If we can't draw it this frame, just dump it. + pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die + } + } + } + } + pTemp = pnext; + } + +finish: + // Restore state info + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +================= +HUD_GetUserEntity + +If you specify negative numbers for beam start and end point entities, then + the engine will call back into this function requesting a pointer to a cl_entity_t + object that describes the entity to attach the beam onto. + +Indices must start at 1, not zero. +================= +*/ +cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) +{ +#if defined( BEAM_TEST ) + // None by default, you would return a valic pointer if you create a client side + // beam and attach it to a client side entity. + if ( index > 0 && index <= 1 ) + { + return &beams[ index ]; + } + else + { + return NULL; + } +#else + return NULL; +#endif +} + diff --git a/cl_dll/ev_common.cpp b/cl_dll/ev_common.cpp new file mode 100644 index 00000000..224633dd --- /dev/null +++ b/cl_dll/ev_common.cpp @@ -0,0 +1,205 @@ +/*** +* +* 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. +* +****/ +// shared event functions +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "r_efx.h" + +#include "eventscripts.h" +#include "event_api.h" +#include "pm_shared.h" + +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) ) +/* +================= +GetEntity + +Return's the requested cl_entity_t +================= +*/ +struct cl_entity_s *GetEntity( int idx ) +{ + return gEngfuncs.GetEntityByIndex( idx ); +} + +/* +================= +GetViewEntity + +Return's the current weapon/view model +================= +*/ +struct cl_entity_s *GetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +/* +================= +EV_CreateTracer + +Creates a tracer effect +================= +*/ +void EV_CreateTracer( float *start, float *end ) +{ + gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); +} + +/* +================= +EV_IsPlayer + +Is the entity's index in the player range? +================= +*/ +qboolean EV_IsPlayer( int idx ) +{ + if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + return true; + + return false; +} + +/* +================= +EV_IsLocal + +Is the entity == the local player +================= +*/ +qboolean EV_IsLocal( int idx ) +{ + // check if we are in some way in first person spec mode + if ( IS_FIRSTPERSON_SPEC ) + return (g_iUser2 == idx); + else + return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; +} + +/* +================= +EV_GetGunPosition + +Figure out the height of the gun +================= +*/ +void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) +{ + int idx; + vec3_t view_ofs; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + // in spec mode use entity viewheigh, not own + if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) + { + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + VectorAdd( origin, view_ofs, pos ); +} + +/* +================= +EV_EjectBrass + +Bullet shell casings +================= +*/ +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) +{ + vec3_t endpos; + VectorClear( endpos ); + endpos[1] = rotation; + gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); +} + +/* +================= +EV_GetDefaultShellInfo + +Determine where to eject shells from +================= +*/ +void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) +{ + int i; + vec3_t view_ofs; + float fR, fU; + + int idx; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + fR = gEngfuncs.pfnRandomFloat( 50, 70 ); + fU = gEngfuncs.pfnRandomFloat( 100, 150 ); + + for ( i = 0; i < 3; i++ ) + { + ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + } +} + +/* +================= +EV_MuzzleFlash + +Flag weapon/view model for muzzle flash +================= +*/ +void EV_MuzzleFlash( void ) +{ + // Add muzzle flash to current weapon model + cl_entity_t *ent = GetViewEntity(); + if ( !ent ) + { + return; + } + + // Or in the muzzle flash + ent->curstate.effects |= EF_MUZZLEFLASH; +} \ No newline at end of file diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp new file mode 100644 index 00000000..82818295 --- /dev/null +++ b/cl_dll/ev_hldm.cpp @@ -0,0 +1,1700 @@ +/*** +* +* 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 "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" + +#include "eventscripts.h" +#include "ev_hldm.h" + +#include "r_efx.h" +#include "event_api.h" +#include "event_args.h" +#include "in_defs.h" + +#include + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +static int tracerCount[ 32 ]; + +extern "C" char PM_FindTextureType( char *name ); + +void V_PunchAxis( int axis, float punch ); +void VectorAngles( const float *forward, float *angles ); + +extern cvar_t *cl_lw; + +extern "C" +{ + +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +// 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 EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType ) +{ + // hit the world, try to play sound based on texture material type + char chTextureType = CHAR_TEX_CONCRETE; + float fvol; + float fvolbar; + char *rgsz[4]; + int cnt; + float fattn = ATTN_NORM; + int entity; + char *pTextureName; + char texname[ 64 ]; + char szbuffer[ 64 ]; + + entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); + + // FIXME check if playtexture sounds movevar is set + // + + chTextureType = 0; + + // Player + if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + { + // hit body + chTextureType = CHAR_TEX_FLESH; + } + else if ( entity == 0 ) + { + // get texture from entity or world (world is ent(0)) + pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); + + if ( pTextureName ) + { + strcpy( texname, pTextureName ); + pTextureName = texname; + + // 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; + + // get texture type + chTextureType = PM_FindTextureType( 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; + } + + // play material hit sound + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); + return fvolbar; +} + +char *EV_HLDM_DamageDecal( physent_t *pe ) +{ + static char decalname[ 32 ]; + int idx; + + if ( pe->classnumber == 1 ) + { + idx = gEngfuncs.pfnRandomLong( 0, 2 ); + sprintf( decalname, "{break%i", idx + 1 ); + } + else if ( pe->rendermode != kRenderNormal ) + { + sprintf( decalname, "{bproof1" ); + } + else + { + idx = gEngfuncs.pfnRandomLong( 0, 4 ); + sprintf( decalname, "{shot%i", idx + 1 ); + } + return decalname; +} + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) +{ + int iRand; + physent_t *pe; + + gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); + + iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); + if ( iRand < (0x7fff/2) )// not every bullet makes a sound. + { + switch( iRand % 5) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + // Only decal brush models such as the world etc. + if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) + { + if ( CVAR_GET_FLOAT( "r_decals" ) ) + { + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); + } + } +} + +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) +{ + physent_t *pe; + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + if ( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) + { + 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 + EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) ); + break; + } + } +} + +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) +{ + int tracer = 0; + int i; + qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; + + if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) + { + vec3_t vecTracerSrc; + + if ( player ) + { + vec3_t offset( 0, 0, -4 ); + + // adjust tracer position for player + for ( i = 0; i < 3; i++ ) + { + vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + } + } + else + { + VectorCopy( vecSrc, vecTracerSrc ); + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = 1; + + switch( iBulletType ) + { + case BULLET_PLAYER_MP5: + case BULLET_MONSTER_MP5: + case BULLET_MONSTER_9MM: + case BULLET_MONSTER_12MM: + default: + EV_CreateTracer( vecTracerSrc, end ); + break; + } + } + + return tracer; +} + + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. +================ +*/ +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) +{ + int i; + pmtrace_t tr; + int iShot; + int tracer; + + for ( iShot = 1; iShot <= cShots; iShot++ ) + { + vec3_t vecDir, vecEnd; + + float x, y, z; + //We randomize for the Shotgun. + if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) + { + do { + x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + z = x*x+y*y; + } while (z > 1); + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + }//But other guns already have their spread randomized in the synched spread. + else + { + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + } + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); + + // do damage, paint decals + if ( tr.fraction != 1.0 ) + { + switch(iBulletType) + { + default: + case BULLET_PLAYER_9MM: + + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + case BULLET_PLAYER_MP5: + + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + case BULLET_PLAYER_BUCKSHOT: + + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + case BULLET_PLAYER_357: + + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } +} + +//====================== +// GLOCK START +//====================== +void EV_FireGlock1( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int empty; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + empty = args->bparam1; + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); + + V_PunchAxis( 0, -2.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2 ); +} + +void EV_FireGlock2( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); + + V_PunchAxis( 0, -2.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + +} +//====================== +// GLOCK END +//====================== + +//====================== +// SHOTGUN START +//====================== +void EV_FireShotGunDouble( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + int j; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); + V_PunchAxis( 0, -10.0 ); + } + + for ( j = 0; j < 2; j++ ) + { + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + } +} + +void EV_FireShotGunSingle( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); + + V_PunchAxis( 0, -5.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + } +} +//====================== +// SHOTGUN END +//====================== + +//====================== +// MP5 START +//====================== +void EV_FireMP5( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); + + V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + } +} + +// We only predict the animation and sound +// The grenade is still launched from the server. +void EV_FireMP52( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); + V_PunchAxis( 0, -10 ); + } + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + } +} +//====================== +// MP5 END +//====================== + +//====================== +// PHYTON START +// ( .357 ) +//====================== +void EV_FirePython( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + if ( EV_IsLocal( idx ) ) + { + // Python uses different body in multiplayer versus single player + int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; + + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); + + V_PunchAxis( 0, -10.0 ); + } + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); +} +//====================== +// PHYTON END +// ( .357 ) +//====================== + +//====================== +// GAUSS START +//====================== +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +void EV_SpinGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int iSoundState = 0; + + int pitch; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + pitch = args->iparam1; + + iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); +} + +/* +============================== +EV_StopPreviousGauss + +============================== +*/ +void EV_StopPreviousGauss( int idx ) +{ + // Make sure we don't have a gauss spin event in the queue for this guy + gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); +} + +extern float g_flApplyVel; + +void EV_FireGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + float flDamage = args->fparam1; + int primaryfire = args->bparam1; + + int m_fPrimaryFire = args->bparam1; + int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + vec3_t vecSrc; + vec3_t vecDest; + edict_t *pentIgnore; + pmtrace_t tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + physent_t *pEntity; + int m_iBeam, m_iGlow, m_iBalls; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + if ( args->bparam2 ) + { + EV_StopPreviousGauss( idx ); + return; + } + +// Con_Printf( "Firing gauss with %f\n", flDamage ); + EV_GetGunPosition( args, vecSrc, origin ); + + m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); + m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); + + AngleVectors( angles, forward, right, up ); + + VectorMA( vecSrc, 8192, forward, vecDest ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); + + if ( m_fPrimaryFire == false ) + g_flApplyVel = flDamage; + + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + while (flDamage > 10 && nMaxHits > 0) + { + nMaxHits--; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( tr.allsolid ) + break; + + if (fFirstBeam) + { + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + } + fFirstBeam = 0; + + gEngfuncs.pEfxAPI->R_BeamEntPoint( + idx | 0x1000, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + else + { + gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + + pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + if ( pEntity == NULL ) + break; + + if ( pEntity->solid == SOLID_BSP ) + { + float n; + + pentIgnore = NULL; + + n = -DotProduct( tr.plane.normal, forward ); + + if (n < 0.5) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + vec3_t r; + + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); + + flMaxFrac = flMaxFrac - tr.fraction; + + VectorCopy( r, forward ); + + VectorMA( tr.endpos, 8.0, forward, vecSrc ); + VectorMA( vecSrc, 8192.0, forward, vecDest ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); + + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + + // lose energy + if ( n == 0 ) + { + n = 0.1; + } + + flDamage = flDamage * (1 - n); + + } + else + { + // tunnel + EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // 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 ) + { + vec3_t start; + + VectorMA( tr.endpos, 8.0, forward, start ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); + + if ( !beam_tr.allsolid ) + { + vec3_t delta; + float n; + + // trace backwards to find exit point + + gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); + + VectorSubtract( beam_tr.endpos, tr.endpos, delta ); + + n = Length( delta ); + + if (n < flDamage) + { + if (n == 0) + n = 1; + flDamage -= n; + + // absorption balls + { + vec3_t fwd; + VectorSubtract( tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + } + + //////////////////////////////////// WHAT TO DO HERE + // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // balls + { + vec3_t fwd; + VectorSubtract( beam_tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + 255, 40 ); + } + + VectorAdd( beam_tr.endpos, forward, vecSrc ); + } + } + else + { + flDamage = 0; + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } + else + { + if ( m_fPrimaryFire ) + { + // slug doesn't punch through ever with primary + // fire, so leave a little glowy bit and make some balls + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); + + { + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 200 ); + } + } + + flDamage = 0; + } + } + } + else + { + VectorAdd( tr.endpos, forward, vecSrc ); + } + } +} +//====================== +// GAUSS END +//====================== + +//====================== +// CROWBAR START +//====================== + +enum crowbar_e { + CROWBAR_IDLE = 0, + CROWBAR_DRAW, + CROWBAR_HOLSTER, + CROWBAR_ATTACK1HIT, + CROWBAR_ATTACK1MISS, + CROWBAR_ATTACK2MISS, + CROWBAR_ATTACK2HIT, + CROWBAR_ATTACK3MISS, + CROWBAR_ATTACK3HIT +}; + +int g_iSwing; + +//Only predict the miss sounds, hit sounds are still played +//server side, so players don't get the wrong idea. +void EV_Crowbar( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + //Play Swing sound + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); + + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); + + switch( (g_iSwing++) % 3 ) + { + case 0: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; + case 1: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; + case 2: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; + } + } +} +//====================== +// CROWBAR END +//====================== + +//====================== +// CROSSBOW START +//====================== +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 +}; + +//===================== +// EV_BoltCallback +// This function is used to correct the origin and angles +// of the bolt, so it looks like it's stuck on the wall. +//===================== +void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + ent->entity.origin = ent->entity.baseline.vuser1; + ent->entity.angles = ent->entity.baseline.vuser2; +} + +void EV_FireCrossbow2( event_args_t *args ) +{ + vec3_t vecSrc, vecEnd; + vec3_t up, right, forward; + pmtrace_t tr; + + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorMA( vecSrc, 8192, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + } + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + //We hit something + if ( tr.fraction < 1.0 ) + { + physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + + //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). + if ( pe->solid != SOLID_BSP ) + { + switch( gEngfuncs.pfnRandomLong(0,1) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. + else if ( pe->rendermode == kRenderNormal ) + { + gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); + + //Not underwater, do some sparks... + if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) + gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); + + vec3_t vBoltAngles; + int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); + + VectorAngles( forward, vBoltAngles ); + + TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); + + if ( bolt ) + { + bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. + bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit + bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward! + bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall) + } + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +//TODO: Fully predict the fliying bolt. +void EV_FireCrossbow( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + + V_PunchAxis( 0, -2.0 ); + } +} +//====================== +// CROSSBOW END +//====================== + +//====================== +// RPG START +//====================== +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 +}; + +void EV_FireRpg( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); + + V_PunchAxis( 0, -5.0 ); + } +} +//====================== +// RPG END +//====================== + +//====================== +// EGON END +//====================== +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 +}; + +int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; +int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; + +enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; +enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + +#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 ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +BEAM *pBeam; +BEAM *pBeam2; + +void EV_EgonFire( event_args_t *args ) +{ + int idx, iFireState, iFireMode; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + iFireState = args->iparam1; + iFireMode = args->iparam2; + int iStartup = args->bparam1; + + + if ( iStartup ) + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); + } + else + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); + } + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); + + if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. + { + vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; + pmtrace_t tr; + + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); + + if ( pl ) + { + VectorCopy( gHUD.m_vecAngles, angles ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, pl->origin ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); + + float r = 50.0f; + float g = 50.0f; + float b = 125.0f; + + if ( IEngineStudio.IsHardware() ) + { + r /= 100.0f; + g /= 100.0f; + } + + + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); + + if ( pBeam ) + pBeam->flags |= ( FBEAM_SINENOISE ); + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); + } + } +} + +void EV_EgonStop( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy ( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); + + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); + + if ( EV_IsLocal( idx ) ) + { + if ( pBeam ) + { + pBeam->die = 0.0; + pBeam = NULL; + } + + + if ( pBeam2 ) + { + pBeam2->die = 0.0; + pBeam2 = NULL; + } + } +} +//====================== +// EGON END +//====================== + +//====================== +// HORNET START +//====================== +enum hgun_e { + HGUN_IDLE1 = 0, + HGUN_FIDGETSWAY, + HGUN_FIDGETSHAKE, + HGUN_DOWN, + HGUN_UP, + HGUN_SHOOT +}; + +void EV_HornetGunFire( event_args_t *args ) +{ + int idx, iFireMode; + vec3_t origin, angles, vecSrc, forward, right, up; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + iFireMode = args->iparam1; + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); + gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); + } + + switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; + } +} +//====================== +// HORNET END +//====================== + +//====================== +// TRIPMINE START +//====================== +enum tripmine_e { + TRIPMINE_IDLE1 = 0, + TRIPMINE_IDLE2, + TRIPMINE_ARM1, + TRIPMINE_ARM2, + TRIPMINE_FIDGET, + TRIPMINE_HOLSTER, + TRIPMINE_DRAW, + TRIPMINE_WORLD, + TRIPMINE_GROUND, +}; + +//We only check if it's possible to put a trip mine +//and if it is, then we play the animation. Server still places it. +void EV_TripmineFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + + vecSrc = vecSrc + view_ofs; + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); + + //Hit something solid + if ( tr.fraction < 1.0 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// TRIPMINE END +//====================== + +//====================== +// SQUEAK START +//====================== +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) + +void EV_SnarkFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + if ( args->ducking ) + vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); + + //Find space to drop the thing. + if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// SQUEAK END +//====================== + +void EV_TrainPitchAdjust( event_args_t *args ) +{ + int idx; + vec3_t origin; + + unsigned short us_params; + int noise; + float m_flVolume; + int pitch; + int stop; + + char sz[ 256 ]; + + idx = args->entindex; + + VectorCopy( args->origin, origin ); + + us_params = (unsigned short)args->iparam1; + stop = args->bparam1; + + m_flVolume = (float)(us_params & 0x003f)/40.0; + noise = (int)(((us_params) >> 12 ) & 0x0007); + pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); + + switch ( noise ) + { + case 1: strcpy( sz, "plats/ttrain1.wav"); break; + case 2: strcpy( sz, "plats/ttrain2.wav"); break; + case 3: strcpy( sz, "plats/ttrain3.wav"); break; + case 4: strcpy( sz, "plats/ttrain4.wav"); break; + case 5: strcpy( sz, "plats/ttrain6.wav"); break; + case 6: strcpy( sz, "plats/ttrain7.wav"); break; + default: + // no sound + strcpy( sz, "" ); + return; + } + + if ( stop ) + { + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); + } + else + { + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + } +} + +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) +{ + return 0; +} \ No newline at end of file diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h new file mode 100644 index 00000000..567e6877 --- /dev/null +++ b/cl_dll/ev_hldm.h @@ -0,0 +1,95 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( EV_HLDMH ) +#define EV_HLDMH + +// bullet types +typedef enum +{ + BULLET_NONE = 0, + BULLET_PLAYER_9MM, // glock + BULLET_PLAYER_MP5, // mp5 + BULLET_PLAYER_357, // python + BULLET_PLAYER_BUCKSHOT, // shotgun + BULLET_PLAYER_CROWBAR, // crowbar swipe + + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, +} Bullet; + +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 +}; + +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 +}; + +enum mp5_e +{ + MP5_LONGIDLE = 0, + MP5_IDLE1, + MP5_LAUNCH, + MP5_RELOAD, + MP5_DEPLOY, + MP5_FIRE1, + MP5_FIRE2, + MP5_FIRE3, +}; + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +#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 +}; + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); + +#endif // EV_HLDMH \ No newline at end of file diff --git a/cl_dll/events.cpp b/cl_dll/events.cpp new file mode 100644 index 00000000..65c842bc --- /dev/null +++ b/cl_dll/events.cpp @@ -0,0 +1,23 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" + +void Game_HookEvents( void ); + +/* +=================== +EV_HookEvents + +See if game specific code wants to hook any events. +=================== +*/ +void EV_HookEvents( void ) +{ + Game_HookEvents(); +} \ No newline at end of file diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h new file mode 100644 index 00000000..e8b145be --- /dev/null +++ b/cl_dll/eventscripts.h @@ -0,0 +1,73 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// eventscripts.h +#if !defined ( EVENTSCRIPTSH ) +#define EVENTSCRIPTSH + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 +#define VEC_DUCK_VIEW 12 + +#define FTENT_FADEOUT 0x00000080 + +#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. + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#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) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// Some of these are HL/TFC specific? +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); +void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); +void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); +qboolean EV_IsLocal( int idx ); +qboolean EV_IsPlayer( int idx ); +void EV_CreateTracer( float *start, float *end ); + +struct cl_entity_s *GetEntity( int idx ); +struct cl_entity_s *GetViewEntity( void ); +void EV_MuzzleFlash( void ); + +#endif // EVENTSCRIPTSH diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp new file mode 100644 index 00000000..dab2421b --- /dev/null +++ b/cl_dll/flashlight.cpp @@ -0,0 +1,149 @@ +/*** +* +* 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. +* +****/ +// +// flashlight.cpp +// +// implementation of CHudFlashlight class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + + +DECLARE_MESSAGE(m_Flash, FlashBat) +DECLARE_MESSAGE(m_Flash, Flashlight) + +#define BAT_NAME "sprites/%d_Flashlight.spr" + +int CHudFlashlight::Init(void) +{ + m_fFade = 0; + m_fOn = 0; + + HOOK_MESSAGE(Flashlight); + HOOK_MESSAGE(FlashBat); + + m_iFlags |= HUD_ACTIVE; + + gHUD.AddHudElem(this); + + return 1; +}; + +void CHudFlashlight::Reset(void) +{ + m_fFade = 0; + m_fOn = 0; +} + +int CHudFlashlight::VidInit(void) +{ + int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); + int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); + int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); + + m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); + m_hSprite2 = gHUD.GetSprite(HUD_flash_full); + m_hBeam = gHUD.GetSprite(HUD_flash_beam); + m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); + m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); + m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); + m_iWidth = m_prc2->right - m_prc2->left; + + return 1; +}; + +int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) +{ + + + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) +{ + + BEGIN_READ( pbuf, iSize ); + m_fOn = READ_BYTE(); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight::Draw(float flTime) +{ + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if (m_fOn) + a = 225; + else + a = MIN_ALPHA; + + if (m_flBat < 0.20) + UnpackRGB(r,g,b, RGB_REDISH); + else + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a); + + y = (m_prc1->bottom - m_prc2->top)/2; + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + + // Draw the flashlight casing + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prc1); + + if ( m_fOn ) + { // draw the flashlight beam + x = ScreenWidth - m_iWidth/2; + + SPR_Set( m_hBeam, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prcBeam ); + } + + // draw the flashlight energy level + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + int iOffset = m_iWidth * (1.0 - m_flBat); + if (iOffset < m_iWidth) + { + rc = *m_prc2; + rc.left += iOffset; + + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x + iOffset, y, &rc); + } + + + return 1; +} \ No newline at end of file diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp new file mode 100644 index 00000000..6f5f984f --- /dev/null +++ b/cl_dll/geiger.cpp @@ -0,0 +1,184 @@ +/*** +* +* 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. +* +****/ +// +// Geiger.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include + +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Geiger, Geiger ) + +int CHudGeiger::Init(void) +{ + HOOK_MESSAGE( Geiger ); + + m_iGeigerRange = 0; + m_iFlags = 0; + + gHUD.AddHudElem(this); + + srand( (unsigned)time( NULL ) ); + + return 1; +}; + +int CHudGeiger::VidInit(void) +{ + return 1; +}; + +int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) +{ + + BEGIN_READ( pbuf, iSize ); + + // update geiger data + m_iGeigerRange = READ_BYTE(); + m_iGeigerRange = m_iGeigerRange << 2; + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +int CHudGeiger::Draw (float flTime) +{ + int pct; + float flvol; + int rg[3]; + int i; + + if (m_iGeigerRange < 1000 && m_iGeigerRange > 0) + { + // peicewise linear is better than continuous formula for this + if (m_iGeigerRange > 800) + { + pct = 0; //Con_Printf ( "range > 800\n"); + } + else if (m_iGeigerRange > 600) + { + pct = 2; + flvol = 0.4; //Con_Printf ( "range > 600\n"); + rg[0] = 1; + rg[1] = 1; + i = 2; + } + else if (m_iGeigerRange > 500) + { + pct = 4; + flvol = 0.5; //Con_Printf ( "range > 500\n"); + rg[0] = 1; + rg[1] = 2; + i = 2; + } + else if (m_iGeigerRange > 400) + { + pct = 8; + flvol = 0.6; //Con_Printf ( "range > 400\n"); + rg[0] = 1; + rg[1] = 2; + rg[2] = 3; + i = 3; + } + else if (m_iGeigerRange > 300) + { + pct = 8; + flvol = 0.7; //Con_Printf ( "range > 300\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 200) + { + pct = 28; + flvol = 0.78; //Con_Printf ( "range > 200\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 150) + { + pct = 40; + flvol = 0.80; //Con_Printf ( "range > 150\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 100) + { + pct = 60; + flvol = 0.85; //Con_Printf ( "range > 100\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 75) + { + pct = 80; + flvol = 0.9; //Con_Printf ( "range > 75\n"); + //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; + rg[0] = 4; + rg[1] = 5; + rg[2] = 6; + i = 3; + } + else if (m_iGeigerRange > 50) + { + pct = 90; + flvol = 0.95; //Con_Printf ( "range > 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + else + { + pct = 95; + flvol = 1.0; //Con_Printf ( "range < 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + + flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); + + if ((rand() & 127) < pct || (rand() & 127) < pct) + { + //S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100); + char sz[256]; + + int j = rand() & 1; + if (i > 2) + j += rand() & 1; + + sprintf(sz, "player/geiger%d.wav", j + 1); + PlaySound(sz, flvol); + + } + } + + return 1; +} diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp new file mode 100644 index 00000000..da664720 --- /dev/null +++ b/cl_dll/health.cpp @@ -0,0 +1,472 @@ +/*** +* +* 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. +* +****/ +// +// Health.cpp +// +// implementation of CHudHealth class +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include + + +DECLARE_MESSAGE(m_Health, Health ) +DECLARE_MESSAGE(m_Health, Damage ) + +#define PAIN_NAME "sprites/%d_pain.spr" +#define DAMAGE_NAME "sprites/%d_dmg.spr" + +int giDmgHeight, giDmgWidth; + +int giDmgFlags[NUM_DMG_TYPES] = +{ + DMG_POISON, + DMG_ACID, + DMG_FREEZE|DMG_SLOWFREEZE, + DMG_DROWN, + DMG_BURN|DMG_SLOWBURN, + DMG_NERVEGAS, + DMG_RADIATION, + DMG_SHOCK, + DMG_CALTROP, + DMG_TRANQ, + DMG_CONCUSS, + DMG_HALLUC +}; + +int CHudHealth::Init(void) +{ + HOOK_MESSAGE(Health); + HOOK_MESSAGE(Damage); + m_iHealth = 100; + m_fFade = 0; + m_iFlags = 0; + m_bitsDamage = 0; + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + giDmgHeight = 0; + giDmgWidth = 0; + + memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); + + + gHUD.AddHudElem(this); + return 1; +} + +void CHudHealth::Reset( void ) +{ + // make sure the pain compass is cleared when the player respawns + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + + + // force all the flashing damage icons to expire + m_bitsDamage = 0; + for ( int i = 0; i < NUM_DMG_TYPES; i++ ) + { + m_dmg[i].fExpire = 0; + } +} + +int CHudHealth::VidInit(void) +{ + m_hSprite = 0; + + m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; + m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); + + giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; + giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; + return 1; +} + +int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) +{ + // TODO: update local health data + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + + m_iFlags |= HUD_ACTIVE; + + // Only update the fade if we've changed health + if (x != m_iHealth) + { + m_fFade = FADE_TIME; + m_iHealth = x; + } + + return 1; +} + + +int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int armor = READ_BYTE(); // armor + int damageTaken = READ_BYTE(); // health + long bitsDamage = READ_LONG(); // damage bits + + vec3_t vecFrom; + + for ( int i = 0 ; i < 3 ; i++) + vecFrom[i] = READ_COORD(); + + UpdateTiles(gHUD.m_flTime, bitsDamage); + + // Actually took damage? + if ( damageTaken > 0 || armor > 0 ) + CalcDamageDirection(vecFrom); + + return 1; +} + + +// Returns back a color from the +// Green <-> Yellow <-> Red ramp +void CHudHealth::GetPainColor( int &r, int &g, int &b ) +{ + int iHealth = m_iHealth; + + if (iHealth > 25) + iHealth -= 25; + else if ( iHealth < 0 ) + iHealth = 0; +#if 0 + g = iHealth * 255 / 100; + r = 255 - g; + b = 0; +#else + if (m_iHealth > 25) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + } + else + { + r = 250; + g = 0; + b = 0; + } +#endif +} + +int CHudHealth::Draw(float flTime) +{ + int r, g, b; + int a = 0, x, y; + int HealthWidth; + + if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) + return 1; + + if ( !m_hSprite ) + m_hSprite = LoadSprite(PAIN_NAME); + + // Has health changed? Flash the health # + if (m_fFade) + { + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = MIN_ALPHA; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + // If health is getting low, make it bright red + if (m_iHealth <= 15) + a = 255; + + GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // Only draw health if we have the suit. + if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) + { + HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = CrossWidth /2; + + SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); + + x = CrossWidth + HealthWidth / 2; + + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + + x += HealthWidth/2; + + int iHeight = gHUD.m_iFontHeight; + int iWidth = HealthWidth/10; + FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); + } + + DrawDamage(flTime); + return DrawPain(flTime); +} + +void CHudHealth::CalcDamageDirection(vec3_t vecFrom) +{ + vec3_t forward, right, up; + float side, front; + vec3_t vecOrigin, vecAngles; + + if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + return; + } + + + memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); + memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); + + + VectorSubtract (vecFrom, vecOrigin, vecFrom); + + float flDistToTarget = vecFrom.Length(); + + vecFrom = vecFrom.Normalize(); + AngleVectors (vecAngles, forward, right, up); + + front = DotProduct (vecFrom, right); + side = DotProduct (vecFrom, forward); + + if (flDistToTarget <= 50) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; + } + else + { + if (side > 0) + { + if (side > 0.3) + m_fAttackFront = max(m_fAttackFront, side); + } + else + { + float f = fabs(side); + if (f > 0.3) + m_fAttackRear = max(m_fAttackRear, f); + } + + if (front > 0) + { + if (front > 0.3) + m_fAttackRight = max(m_fAttackRight, front); + } + else + { + float f = fabs(front); + if (f > 0.3) + m_fAttackLeft = max(m_fAttackLeft, f); + } + } +} + +int CHudHealth::DrawPain(float flTime) +{ + if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) + return 1; + + int r, g, b; + int x, y, a, shade; + + // TODO: get the shift value of the health + a = 255; // max brightness until then + + float fFade = gHUD.m_flTimeDelta * 2; + + // SPR_Draw top + if (m_fAttackFront > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackFront, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; + SPR_DrawAdditive(0, x, y, NULL); + m_fAttackFront = max( 0, m_fAttackFront - fFade ); + } else + m_fAttackFront = 0; + + if (m_fAttackRight > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRight, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; + SPR_DrawAdditive(1, x, y, NULL); + m_fAttackRight = max( 0, m_fAttackRight - fFade ); + } else + m_fAttackRight = 0; + + if (m_fAttackRear > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRear, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; + y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; + SPR_DrawAdditive(2, x, y, NULL); + m_fAttackRear = max( 0, m_fAttackRear - fFade ); + } else + m_fAttackRear = 0; + + if (m_fAttackLeft > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackLeft, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; + y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; + SPR_DrawAdditive(3, x, y, NULL); + + m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); + } else + m_fAttackLeft = 0; + + return 1; +} + +int CHudHealth::DrawDamage(float flTime) +{ + int r, g, b, a; + DAMAGE_IMAGE *pdmg; + + if (!m_bitsDamage) + return 1; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + a = (int)( fabs(sin(flTime*2)) * 256.0); + + ScaleColors(r, g, b, a); + + // Draw all the items + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg = &m_dmg[i]; + SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); + SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); + } + } + + + // check for bits that should be expired + for ( i = 0; i < NUM_DMG_TYPES; i++ ) + { + DAMAGE_IMAGE *pdmg = &m_dmg[i]; + + if ( m_bitsDamage & giDmgFlags[i] ) + { + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); + + if ( pdmg->fExpire <= flTime // when the time has expired + && a < 40 ) // and the flash is at the low point of the cycle + { + pdmg->fExpire = 0; + + int y = pdmg->y; + pdmg->x = pdmg->y = 0; + + // move everyone above down + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + pdmg = &m_dmg[j]; + if ((pdmg->y) && (pdmg->y < y)) + pdmg->y += giDmgHeight; + + } + + m_bitsDamage &= ~giDmgFlags[i]; // clear the bits + } + } + } + + return 1; +} + + +void CHudHealth::UpdateTiles(float flTime, long bitsDamage) +{ + DAMAGE_IMAGE *pdmg; + + // Which types are new? + long bitsOn = ~m_bitsDamage & bitsDamage; + + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + pdmg = &m_dmg[i]; + + // Is this one already on? + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration + if (!pdmg->fBaseline) + pdmg->fBaseline = flTime; + } + + // Are we just turning it on? + if (bitsOn & giDmgFlags[i]) + { + // put this one at the bottom + pdmg->x = giDmgWidth/8; + pdmg->y = ScreenHeight - giDmgHeight * 2; + pdmg->fExpire=flTime + DMG_IMAGE_LIFE; + + // move everyone else up + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + if (j == i) + continue; + + pdmg = &m_dmg[j]; + if (pdmg->y) + pdmg->y -= giDmgHeight; + + } + pdmg = &m_dmg[i]; + } + } + + // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) + m_bitsDamage |= bitsDamage; +} diff --git a/cl_dll/health.h b/cl_dll/health.h new file mode 100644 index 00000000..41717e78 --- /dev/null +++ b/cl_dll/health.h @@ -0,0 +1,127 @@ +/*** +* +* 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 DMG_IMAGE_LIFE 2 // seconds that image is up + +#define DMG_IMAGE_POISON 0 +#define DMG_IMAGE_ACID 1 +#define DMG_IMAGE_COLD 2 +#define DMG_IMAGE_DROWN 3 +#define DMG_IMAGE_BURN 4 +#define DMG_IMAGE_NERVE 5 +#define DMG_IMAGE_RAD 6 +#define DMG_IMAGE_SHOCK 7 +//tf defines +#define DMG_IMAGE_CALTROP 8 +#define DMG_IMAGE_TRANQ 9 +#define DMG_IMAGE_CONCUSS 10 +#define DMG_IMAGE_HALLUC 11 +#define NUM_DMG_TYPES 12 +// 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. + + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#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) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// TF Healing Additions for TakeHealth +#define DMG_IGNORE_MAXHEALTH DMG_IGNITE +// TF Redefines since we never use the originals +#define DMG_NAIL DMG_SLASH +#define DMG_NOT_SELF DMG_FREEZE + + +#define DMG_TRANQ DMG_MORTAR +#define DMG_CONCUSS DMG_SONIC + + + +typedef struct +{ + float fExpire; + float fBaseline; + int x, y; +} DAMAGE_IMAGE; + +// +//----------------------------------------------------- +// +class CHudHealth: public CHudBase +{ +public: + virtual int Init( void ); + virtual int VidInit( void ); + virtual int Draw(float fTime); + virtual void Reset( void ); + int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); + int m_iHealth; + int m_HUD_dmg_bio; + int m_HUD_cross; + float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; + void GetPainColor( int &r, int &g, int &b ); + float m_fFade; + +private: + HSPRITE m_hSprite; + HSPRITE m_hDamage; + + DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; + int m_bitsDamage; + int DrawPain(float fTime); + int DrawDamage(float fTime); + void CalcDamageDirection(vec3_t vecFrom); + void UpdateTiles(float fTime, long bits); +}; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp new file mode 100644 index 00000000..547d5532 --- /dev/null +++ b/cl_dll/hl/hl_baseentity.cpp @@ -0,0 +1,347 @@ +/*** +* +* 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. +* +****/ + +/* +========================== +This file contains "stubs" of class member implementations so that we can predict certain + weapons client side. From time to time you might find that you need to implement part of the + these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and + add in the functionality you need. +========================== +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "skill.h" + +// Globals used by game logic +const Vector g_vecZero = Vector( 0, 0, 0 ); +int gmsgWeapPickup = 0; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } + +// CBaseEntity Stubs +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } +int CBaseEntity::Save( CSave &save ) { return 1; } +int CBaseEntity::Restore( CRestore &restore ) { return 1; } +void CBaseEntity::SetObjectCollisionBox( void ) { } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity :: MakeDormant( void ) { } +int CBaseEntity :: IsDormant( void ) { return 0; } +BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::SUB_Remove( void ) { } + +// CBaseDelay Stubs +void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +int CBaseDelay::Restore( class CRestore & ) { return 1; } +int CBaseDelay::Save( class CSave & ) { return 1; } + +// CBaseAnimating Stubs +int CBaseAnimating::Restore( class CRestore & ) { return 1; } +int CBaseAnimating::Save( class CSave & ) { return 1; } + +// DEBUG Stubs +edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } +void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } + +// UTIL_* Stubs +void UTIL_PrecacheOther( const char *szClassname ) { } +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_MakeVectors( const Vector &vecAngles ) { } +BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } +void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } +void UTIL_LogPrintf(char *,...) { } +void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } + +// CBaseToggle Stubs +int CBaseToggle::Restore( class CRestore & ) { return 1; } +int CBaseToggle::Save( class CSave & ) { return 1; } +void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } + +// CGrenade Stubs +void CGrenade::BounceSound( void ) { } +void CGrenade::Explode( Vector, Vector ) { } +void CGrenade::Explode( TraceResult *, int ) { } +void CGrenade::Killed( entvars_t *, int ) { } +void CGrenade::Spawn( void ) { } +CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } +CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } +void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } + +void UTIL_Remove( CBaseEntity *pEntity ){ } +struct skilldata_t gSkillData; +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } +CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} + +Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } +CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } +void CBeam::PointEntInit( const Vector &start, int endIndex ) { } +CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } +void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } + + +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } +void CBaseMonster :: Eat ( float flFullDuration ) { } +BOOL CBaseMonster :: FShouldEat ( void ) { return TRUE; } +void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBaseMonster :: BarnacleVictimReleased ( void ) { } +void CBaseMonster :: Listen ( void ) { } +float CBaseMonster :: FLSoundVolume ( CSound *pSound ) { return 0.0; } +BOOL CBaseMonster :: FValidateHintType ( short sHint ) { return FALSE; } +void CBaseMonster :: Look ( int iDistance ) { } +int CBaseMonster :: ISoundMask ( void ) { return 0; } +CSound* CBaseMonster :: PBestSound ( void ) { return NULL; } +CSound* CBaseMonster :: PBestScent ( void ) { return NULL; } +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } +void CBaseMonster :: MonsterThink ( void ) { } +void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } +int CBaseMonster :: IgnoreConditions ( void ) { return 0; } +void CBaseMonster :: RouteClear ( void ) { } +void CBaseMonster :: RouteNew ( void ) { } +BOOL CBaseMonster :: FRouteClear ( void ) { return FALSE; } +BOOL CBaseMonster :: FRefreshRoute ( void ) { return 0; } +BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +int ShouldSimplify( int routeType ) { return TRUE; } +void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) { } +BOOL CBaseMonster :: FBecomeProne ( void ) { return TRUE; } +BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; } +void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) { } +BOOL CBaseMonster :: FCanCheckAttacks ( void ) { return FALSE; } +int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) { return 0; } +void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } +BOOL CBaseMonster :: PopEnemy( ) { return FALSE; } +void CBaseMonster :: SetActivity ( Activity NewActivity ) { } +void CBaseMonster :: SetSequenceByName ( char *szSequence ) { } +int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } +float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } +void CBaseMonster :: AdvanceRoute ( float distance ) { } +int CBaseMonster :: RouteClassify( int iMoveFlag ) { return 0; } +BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } +void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) { } +BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } +void CBaseMonster :: Move ( float flInterval ) { } +BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } +void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { } +void CBaseMonster :: MonsterInit ( void ) { } +void CBaseMonster :: MonsterInitThink ( void ) { } +void CBaseMonster :: StartMonster ( void ) { } +void CBaseMonster :: MovementComplete( void ) { } +int CBaseMonster::TaskIsRunning( void ) { return 0; } +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } +BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::FlYawDiff ( void ) { return 0.0; } +float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } +float CBaseMonster::VecToYaw ( Vector vecDir ) { return 0.0; } +int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } +void CBaseMonster :: SetEyePosition ( void ) { } +int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } +void CBaseAnimating :: ResetSequenceInfo ( ) { } +BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } +void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { } +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating :: InitBoneControllers ( void ) { } +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } +Vector CBaseMonster :: GetGunPosition( void ) { return g_vecZero; } +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { return TRUE; } +int CBaseMonster :: FindHintNode ( void ) { return NO_NODE; } +void CBaseMonster::ReportAIState( void ) { } +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } +int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } +BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } +Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } +BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; } +BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; } +void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } +void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } +void CBaseMonster::SentenceStop( void ) { } +void CBaseMonster::CorpseFallThink( void ) { } +void CBaseMonster :: MonsterInitDead( void ) { } +BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; } +BOOL CBaseMonster :: GetEnemy ( void ) { return FALSE; } +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::FadeMonster( void ) { } +void CBaseMonster :: GibMonster( void ) { } +BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } +MONSTERSTATE CBaseMonster :: GetIdealState ( void ) { return MONSTERSTATE_ALERT; } +Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { return NULL; } +Schedule_t *CBaseMonster :: GetSchedule ( void ) { return NULL; } +void CBaseMonster :: RunTask ( Task_t *pTask ) { } +void CBaseMonster :: StartTask ( Task_t *pTask ) { } +Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { return NULL;} +void CBaseMonster::BecomeDead( void ) {} +void CBaseMonster :: RunAI ( void ) {} +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +int CBaseMonster::Restore( class CRestore & ) { return 1; } +int CBaseMonster::Save( class CSave & ) { return 1; } + +int TrainSpeed(int iSpeed, int iMax) { return 0; } +void CBasePlayer :: DeathSound( void ) { } +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBasePlayer::PackDeadPlayerItems( void ) { } +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } +void CBasePlayer::WaterMove() { } +BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } +void CBasePlayer::PlayerDeathThink(void) { } +void CBasePlayer::StartDeathCam( void ) { } +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } +void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::Jump() { } +void CBasePlayer::Duck( ) { } +int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer::PreThink(void) { } +void CBasePlayer::CheckTimeBasedDamage() { } +void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::CheckSuitUpdate() { } +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } +void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::PostThink() { } +void CBasePlayer :: Precache( void ) { } +int CBasePlayer::Save( CSave &save ) { return 0; } +void CBasePlayer::RenewItems(void) { } +int CBasePlayer::Restore( CRestore &restore ) { return 0; } +void CBasePlayer::SelectNextItem( int iItem ) { } +BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } +void CBasePlayer::SelectPrevItem( int iItem ) { } +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } +BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } +void CBasePlayer :: FlashlightTurnOn( void ) { } +void CBasePlayer :: FlashlightTurnOff( void ) { } +void CBasePlayer :: ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands( ) { } +void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +void CBasePlayer::ItemPreFrame() { } +void CBasePlayer::ItemPostFrame() { } +int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } +int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +void CBasePlayer::SendAmmoUpdate(void) { } +void CBasePlayer :: UpdateClientData( void ) { } +BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBasePlayer :: BarnacleVictimReleased ( void ) { } +int CBasePlayer :: Illumination( void ) { return 0; } +void CBasePlayer :: EnableControl(BOOL fControl) { } +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer :: ResetAutoaim( ) { } +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +const char *CBasePlayer::TeamID( void ) { return ""; } +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } + +void ClearMultiDamage(void) { } +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } +void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } +int CBasePlayerItem::Restore( class CRestore & ) { return 1; } +int CBasePlayerItem::Save( class CSave & ) { return 1; } +int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } +int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +void CBasePlayerItem :: SetObjectCollisionBox( void ) { } +void CBasePlayerItem :: FallInit( void ) { } +void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::Materialize( void ) { } +void CBasePlayerItem::AttemptToMaterialize( void ) { } +void CBasePlayerItem :: CheckRespawn ( void ) { } +CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerItem::DestroyItem( void ) { } +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } +void CBasePlayerItem::Drop( void ) { } +void CBasePlayerItem::Kill( void ) { } +void CBasePlayerItem::Holster( int skiplocal ) { } +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +void CBasePlayerAmmo::Spawn( void ) { } +CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } +void CBasePlayerAmmo::Materialize( void ) { } +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +void CBasePlayerWeapon::RetireWeapon( void ) { } +void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} +void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} \ No newline at end of file diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp new file mode 100644 index 00000000..5ad4459e --- /dev/null +++ b/cl_dll/hl/hl_events.cpp @@ -0,0 +1,80 @@ +/*** +* +* 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 "../hud.h" +#include "../cl_util.h" +#include "event_api.h" + +extern "C" +{ +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +/* +====================== +Game_HookEvents + +Associate script file name with callback functions. Callback's must be extern "C" so + the engine doesn't get confused about name mangling stuff. Note that the format is + always the same. Of course, a clever mod team could actually embed parameters, behavior + into the actual .sc files and create a .sc file parser and hook their functionality through + that.. i.e., a scripting system. + +That was what we were going to do, but we ran out of time...oh well. +====================== +*/ +void Game_HookEvents( void ) +{ + gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); + gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); + gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); + gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); + gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); + gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); + gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); + gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); + gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); + gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); + gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); + gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); + gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); + gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); + gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); + gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); + gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); + gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); +} diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp new file mode 100644 index 00000000..e95dfae7 --- /dev/null +++ b/cl_dll/hl/hl_objects.cpp @@ -0,0 +1,90 @@ +/*** +* +* 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 "../hud.h" +#include "../cl_util.h" +#include "../demo.h" + +#include "demo_api.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "pm_defs.h" +#include "event_api.h" +#include "entity_types.h" +#include "r_efx.h" + +extern BEAM *pBeam; +extern BEAM *pBeam2; +void HUD_GetLastOrg( float *org ); + +void UpdateBeams ( void ) +{ + vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; + vec3_t view_ofs; + pmtrace_t tr; + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + int idx = pthisplayer->index; + + // Get our exact viewangles from engine + gEngfuncs.GetViewAngles( (float *)angles ); + + // Determine our last predicted origin + HUD_GetLastOrg( (float *)&origin ); + + AngleVectors( angles, forward, right, up ); + + VectorCopy( origin, vecSrc ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( pBeam ) + { + pBeam->target = tr.endpos; + pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } + + if ( pBeam2 ) + { + pBeam2->target = tr.endpos; + pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } +} + +/* +===================== +Game_AddObjects + +Add game specific, client-side objects here +===================== +*/ +void Game_AddObjects( void ) +{ + if ( pBeam && pBeam2 ) + UpdateBeams(); +} diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp new file mode 100644 index 00000000..820e49ff --- /dev/null +++ b/cl_dll/hl/hl_weapons.cpp @@ -0,0 +1,1095 @@ +/*** +* +* 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 "usercmd.h" +#include "entity_state.h" +#include "demo_api.h" +#include "pm_defs.h" +#include "event_api.h" +#include "r_efx.h" + +#include "../hud_iface.h" +#include "../com_weapons.h" +#include "../demo.h" + +extern globalvars_t *gpGlobals; +extern int g_iUser1; + +// Pool of client side entities/entvars_t +static entvars_t ev[ 32 ]; +static int num_ents = 0; + +// The entity we'll use to represent the local client +static CBasePlayer player; + +// Local version of game .dll global variables ( time, etc. ) +static globalvars_t Globals; + +static CBasePlayerWeapon *g_pWpns[ 32 ]; + +float g_flApplyVel = 0.0; +int g_irunninggausspred = 0; + +vec3_t previousorigin; + +// HLDM Weapon placeholder entities. +CGlock g_Glock; +CCrowbar g_Crowbar; +CPython g_Python; +CMP5 g_Mp5; +CCrossbow g_Crossbow; +CShotgun g_Shotgun; +CRpg g_Rpg; +CGauss g_Gauss; +CEgon g_Egon; +CHgun g_HGun; +CHandGrenade g_HandGren; +CSatchel g_Satchel; +CTripmine g_Tripmine; +CSqueak g_Snark; + + +/* +====================== +AlertMessage + +Print debug messages to console +====================== +*/ +void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, szFmt); + vsprintf (string, szFmt,argptr); + va_end (argptr); + + gEngfuncs.Con_Printf( "cl: " ); + gEngfuncs.Con_Printf( string ); +} + +//Returns if it's multiplayer. +//Mostly used by the client side weapons. +bool bIsMultiplayer ( void ) +{ + return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; +} +//Just loads a v_ model. +void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) +{ + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); +} + +/* +===================== +HUD_PrepEntity + +Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then +we set up the m_pPlayer field. +===================== +*/ +void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) +{ + memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); + pEntity->pev = &ev[ num_ents++ ]; + + pEntity->Precache(); + pEntity->Spawn(); + + if ( pWeaponOwner ) + { + ItemInfo info; + + ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; + + ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); + + g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; + } +} + +/* +===================== +CBaseEntity :: Killed + +If weapons code "kills" an entity, just set its effects to EF_NODRAW +===================== +*/ +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->effects |= EF_NODRAW; +} + +/* +===================== +CBasePlayerWeapon :: DefaultReload +===================== +*/ +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(), body ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: CanDeploy +===================== +*/ +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; +} + +/* +===================== +CBasePlayerWeapon :: DefaultDeploy + +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +{ + if ( !CanDeploy() ) + return FALSE; + + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); + + SendWeaponAnim( iAnim, skiplocal, body ); + + g_irunninggausspred = false; + m_pPlayer->m_flNextAttack = 0.5; + m_flTimeWeaponIdle = 1.0; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: PlayEmptySound + +===================== +*/ +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { + HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +/* +===================== +CBasePlayerWeapon :: ResetEmptySound + +===================== +*/ +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +/* +===================== +CBasePlayerWeapon::Holster + +Put away weapon +===================== +*/ +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + g_irunninggausspred = false; + m_pPlayer->pev->viewmodel = 0; +} + +/* +===================== +CBasePlayerWeapon::SendWeaponAnim + +Animate weapon model +===================== +*/ +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) +{ + m_pPlayer->pev->weaponanim = iAnim; + + HUD_SendWeaponAnim( iAnim, body, 0 ); +} + +/* +===================== +CBaseEntity::FireBulletsPlayer + +Only produces random numbers to match the server ones. +===================== +*/ +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 ) +{ + float x, y, z; + + for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + { + if ( pevAttacker == NULL ) + { + // get circular gaussian spread + 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); + } + else + { + //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; + } + + } + + return Vector ( x * vecSpread.x, y * vecSpread.y, 0.0 ); +} + +/* +===================== +CBasePlayerWeapon::ItemPostFrame + +Handles weapon firing, reloading, etc. +===================== +*/ +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + { +#if 0 // FIXME, need ammo on client to make this work right + // 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; +#else + m_iClip += 10; +#endif + m_fInReload = FALSE; + } + + if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) + { + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + { + m_fFireOnEmpty = TRUE; + } + + SecondaryAttack(); + m_pPlayer->pev->button &= ~IN_ATTACK2; + } + else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) + { + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + 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; + + // 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 < 0.0 ) + { + Reload(); + return; + } + + WeaponIdle( ); + return; + } + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +/* +===================== +CBasePlayer::SelectItem + + Switch weapons +===================== +*/ +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + if (!pItem) + return; + + + if (pItem == m_pActiveItem) + return; + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + } +} + +/* +===================== +CBasePlayer::SelectLastItem + +===================== +*/ +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + return; + } + + if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + { + return; + } + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + CBasePlayerItem *pTemp = m_pActiveItem; + m_pActiveItem = m_pLastItem; + m_pLastItem = pTemp; + m_pActiveItem->Deploy( ); +} + +/* +===================== +CBasePlayer::Killed + +===================== +*/ +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); + + g_irunninggausspred = false; +} + +/* +===================== +CBasePlayer::Spawn + +===================== +*/ +void CBasePlayer::Spawn( void ) +{ + if (m_pActiveItem) + m_pActiveItem->Deploy( ); + + g_irunninggausspred = false; +} + +/* +===================== +UTIL_TraceLine + +Don't actually trace, but act like the trace didn't hit anything. +===================== +*/ +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + memset( ptr, 0, sizeof( *ptr ) ); + ptr->flFraction = 1.0; +} + +/* +===================== +UTIL_ParticleBox + +For debugging, draw a box around a player made out of particles +===================== +*/ +void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + int i; + vec3_t mmin, mmax; + + for ( i = 0; i < 3; i++ ) + { + mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; + mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + } + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); +} + +/* +===================== +UTIL_ParticleBoxes + +For debugging, draw boxes for other collidable players +===================== +*/ +void UTIL_ParticleBoxes( void ) +{ + int idx; + physent_t *pe; + cl_entity_t *player; + vec3_t mins, maxs; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + player = gEngfuncs.GetLocalPlayer(); + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); + + for ( idx = 1; idx < 100; idx++ ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); + if ( !pe ) + break; + + if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + { + mins = pe->origin + pe->mins; + maxs = pe->origin + pe->maxs; + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +===================== +UTIL_ParticleLine + +For debugging, draw a line made out of particles +===================== +*/ +void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); +} + +/* +===================== +CBasePlayerWeapon::PrintState + +For debugging, print out state variables to log file +===================== +*/ +void CBasePlayerWeapon::PrintState( void ) +{ + COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); + COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%i ", m_iClip ); +} + +/* +===================== +HUD_InitClientWeapons + +Set up weapons, player and functions needed to run weapons code client-side. +===================== +*/ +void HUD_InitClientWeapons( void ) +{ + static int initialized = 0; + if ( initialized ) + return; + + initialized = 1; + + // Set up pointer ( dummy object ) + gpGlobals = &Globals; + + // Fill in current time ( probably not needed ) + gpGlobals->time = gEngfuncs.GetClientTime(); + + // Fake functions + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; + + // Handled locally + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; + + // Pass through to engine + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + + // Allocate a slot for the local player + HUD_PrepEntity( &player , NULL ); + + // Allocate slot(s) for each weapon that we are going to be predicting + HUD_PrepEntity( &g_Glock , &player ); + HUD_PrepEntity( &g_Crowbar , &player ); + HUD_PrepEntity( &g_Python , &player ); + HUD_PrepEntity( &g_Mp5 , &player ); + HUD_PrepEntity( &g_Crossbow , &player ); + HUD_PrepEntity( &g_Shotgun , &player ); + HUD_PrepEntity( &g_Rpg , &player ); + HUD_PrepEntity( &g_Gauss , &player ); + HUD_PrepEntity( &g_Egon , &player ); + HUD_PrepEntity( &g_HGun , &player ); + HUD_PrepEntity( &g_HandGren , &player ); + HUD_PrepEntity( &g_Satchel , &player ); + HUD_PrepEntity( &g_Tripmine , &player ); + HUD_PrepEntity( &g_Snark , &player ); +} + +/* +===================== +HUD_GetLastOrg + +Retruns the last position that we stored for egon beam endpoint. +===================== +*/ +void HUD_GetLastOrg( float *org ) +{ + int i; + + // Return last origin + for ( i = 0; i < 3; i++ ) + { + org[i] = previousorigin[i]; + } +} + +/* +===================== +HUD_SetLastOrg + +Remember our exact predicted origin so we can draw the egon to the right position. +===================== +*/ +void HUD_SetLastOrg( void ) +{ + int i; + + // Offset final origin by view_offset + for ( i = 0; i < 3; i++ ) + { + previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; + } +} + +/* +===================== +HUD_WeaponsPostThink + +Run Weapon firing code on client +===================== +*/ +void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) +{ + int i; + int buttonsChanged; + CBasePlayerWeapon *pWeapon = NULL; + CBasePlayerWeapon *pCurrent; + weapon_data_t nulldata, *pfrom, *pto; + static int lasthealth; + + memset( &nulldata, 0, sizeof( nulldata ) ); + + HUD_InitClientWeapons(); + + // Get current clock + gpGlobals->time = time; + + // Fill in data based on selected weapon + // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? + switch ( from->client.m_iId ) + { + case WEAPON_CROWBAR: + pWeapon = &g_Crowbar; + break; + + case WEAPON_GLOCK: + pWeapon = &g_Glock; + break; + + case WEAPON_PYTHON: + pWeapon = &g_Python; + break; + + case WEAPON_MP5: + pWeapon = &g_Mp5; + break; + + case WEAPON_CROSSBOW: + pWeapon = &g_Crossbow; + break; + + case WEAPON_SHOTGUN: + pWeapon = &g_Shotgun; + break; + + case WEAPON_RPG: + pWeapon = &g_Rpg; + break; + + case WEAPON_GAUSS: + pWeapon = &g_Gauss; + break; + + case WEAPON_EGON: + pWeapon = &g_Egon; + break; + + case WEAPON_HORNETGUN: + pWeapon = &g_HGun; + break; + + case WEAPON_HANDGRENADE: + pWeapon = &g_HandGren; + break; + + case WEAPON_SATCHEL: + pWeapon = &g_Satchel; + break; + + case WEAPON_TRIPMINE: + pWeapon = &g_Tripmine; + break; + + case WEAPON_SNARK: + pWeapon = &g_Snark; + break; + } + + // Store pointer to our destination entity_state_t so we can get our origin, etc. from it + // for setting up events on the client + g_finalstate = to; + + // If we are running events/etc. go ahead and see if we + // managed to die between last frame and this one + // If so, run the appropriate player killed or spawn function + if ( g_runfuncs ) + { + if ( to->client.health <= 0 && lasthealth > 0 ) + { + player.Killed( NULL, 0 ); + + } + else if ( to->client.health > 0 && lasthealth <= 0 ) + { + player.Spawn(); + } + + lasthealth = to->client.health; + } + + // We are not predicting the current weapon, just bow out here. + if ( !pWeapon ) + return; + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + if ( !pCurrent ) + { + continue; + } + + pfrom = &from->weapondata[ i ]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; +// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; + pCurrent->m_iClip = pfrom->m_iClip; + pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; + pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + pCurrent->pev->fuser1 = pfrom->fuser1; + pCurrent->m_flStartThrow = pfrom->fuser2; + pCurrent->m_flReleaseThrow = pfrom->fuser3; + pCurrent->m_chargeReady = pfrom->iuser1; + pCurrent->m_fInAttack = pfrom->iuser2; + pCurrent->m_fireState = pfrom->iuser3; + + pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; + pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; + player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; + player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; + } + + // For random weapon events, use this seed to seed random # generator + player.random_seed = random_seed; + + // Get old buttons from previous state. + player.m_afButtonLast = from->playerstate.oldbuttons; + + // Which buttsons chave changed + buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // The changed ones still down are "pressed" + player.m_afButtonPressed = buttonsChanged & cmd->buttons; + // The ones not down are "released" + player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + + // Set player variables that weapons code might check/alter + player.pev->button = cmd->buttons; + + player.pev->velocity = from->client.velocity; + player.pev->flags = from->client.flags; + + player.pev->deadflag = from->client.deadflag; + player.pev->waterlevel = from->client.waterlevel; + player.pev->maxspeed = from->client.maxspeed; + player.pev->fov = from->client.fov; + player.pev->weaponanim = from->client.weaponanim; + player.pev->viewmodel = from->client.viewmodel; + player.m_flNextAttack = from->client.m_flNextAttack; + player.m_flNextAmmoBurn = from->client.fuser2; + player.m_flAmmoStartCharge = from->client.fuser3; + + //Stores all our ammo info, so the client side weapons can use them. + player.ammo_9mm = (int)from->client.vuser1[0]; + player.ammo_357 = (int)from->client.vuser1[1]; + player.ammo_argrens = (int)from->client.vuser1[2]; + player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... + player.ammo_buckshot = (int)from->client.ammo_shells; + player.ammo_uranium = (int)from->client.ammo_cells; + player.ammo_hornets = (int)from->client.vuser2[0]; + player.ammo_rockets = (int)from->client.ammo_rockets; + + + // Point to current weapon object + if ( from->client.m_iId ) + { + player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + } + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; + ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; + } + + // Don't go firing anything if we have died. + // Or if we don't have a weapon model deployed + if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && + !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) + { + if ( player.m_flNextAttack <= 0 ) + { + pWeapon->ItemPostFrame(); + } + } + + // Assume that we are not going to switch weapons + to->client.m_iId = from->client.m_iId; + + // Now see if we issued a changeweapon command ( and we're not dead ) + if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + { + // Switched to a different weapon? + if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + { + CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; + if ( pNew && ( pNew != pWeapon ) ) + { + // Put away old weapon + if (player.m_pActiveItem) + player.m_pActiveItem->Holster( ); + + player.m_pLastItem = player.m_pActiveItem; + player.m_pActiveItem = pNew; + + // Deploy new weapon + if (player.m_pActiveItem) + { + player.m_pActiveItem->Deploy( ); + } + + // Update weapon id so we can predict things correctly. + to->client.m_iId = cmd->weaponselect; + } + } + } + + // Copy in results of prediction code + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + to->client.fuser2 = player.m_flNextAmmoBurn; + to->client.fuser3 = player.m_flAmmoStartCharge; + to->client.maxspeed = player.pev->maxspeed; + + //HL Weapons + to->client.vuser1[0] = player.ammo_9mm; + to->client.vuser1[1] = player.ammo_357; + to->client.vuser1[2] = player.ammo_argrens; + + to->client.ammo_nails = player.ammo_bolts; + to->client.ammo_shells = player.ammo_buckshot; + to->client.ammo_cells = player.ammo_uranium; + to->client.vuser2[0] = player.ammo_hornets; + to->client.ammo_rockets = player.ammo_rockets; + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; + from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; + } + + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) + { + int body = 2; + + //Pop the model to body 0. + if ( pWeapon == &g_Tripmine ) + body = 0; + + //Show laser sight/scope combo + if ( pWeapon == &g_Python && bIsMultiplayer() ) + body = 1; + + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); + } + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + + pto = &to->weapondata[ i ]; + + if ( !pCurrent ) + { + memset( pto, 0, sizeof( weapon_data_t ) ); + continue; + } + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; +// pto->m_flPumpTime = pCurrent->m_flPumpTime; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; + pto->fuser1 = pCurrent->pev->fuser1; + pto->fuser2 = pCurrent->m_flStartThrow; + pto->fuser3 = pCurrent->m_flReleaseThrow; + pto->iuser1 = pCurrent->m_chargeReady; + pto->iuser2 = pCurrent->m_fInAttack; + pto->iuser3 = pCurrent->m_fireState; + + // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + pto->fuser1 -= cmd->msec / 1000.0; + + to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; + to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; + to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; + to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; + +/* if ( pto->m_flPumpTime != -9999 ) + { + pto->m_flPumpTime -= cmd->msec / 1000.0; + if ( pto->m_flPumpTime < -0.001 ) + pto->m_flPumpTime = -0.001; + }*/ + + if ( pto->m_fNextAimBonus < -1.0 ) + { + pto->m_fNextAimBonus = -1.0; + } + + if ( pto->m_flNextPrimaryAttack < -1.0 ) + { + pto->m_flNextPrimaryAttack = -1.0; + } + + if ( pto->m_flNextSecondaryAttack < -0.001 ) + { + pto->m_flNextSecondaryAttack = -0.001; + } + + if ( pto->m_flTimeWeaponIdle < -0.001 ) + { + pto->m_flTimeWeaponIdle = -0.001; + } + + if ( pto->m_flNextReload < -0.001 ) + { + pto->m_flNextReload = -0.001; + } + + if ( pto->fuser1 < -0.001 ) + { + pto->fuser1 = -0.001; + } + } + + // m_flNextAttack is now part of the weapons, but is part of the player instead + to->client.m_flNextAttack -= cmd->msec / 1000.0; + if ( to->client.m_flNextAttack < -0.001 ) + { + to->client.m_flNextAttack = -0.001; + } + + to->client.fuser2 -= cmd->msec / 1000.0; + if ( to->client.fuser2 < -0.001 ) + { + to->client.fuser2 = -0.001; + } + + to->client.fuser3 -= cmd->msec / 1000.0; + if ( to->client.fuser3 < -0.001 ) + { + to->client.fuser3 = -0.001; + } + + // Store off the last position from the predicted state. + HUD_SetLastOrg(); + + // Wipe it so we can't use it after this frame + g_finalstate = NULL; +} + +/* +===================== +HUD_PostRunCmd + +Client calls this during prediction, after it has moved the player and updated any info changed into to-> +time is the current client clock based on prediction +cmd is the command that caused the movement, etc +runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should +be ignored +===================== +*/ +void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) +{ + g_runfuncs = runfuncs; + +#if defined( CLIENT_WEAPONS ) + if ( cl_lw && cl_lw->value ) + { + HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); + } + else +#endif + { + to->client.fov = g_lastFOV; + } + + if ( g_irunninggausspred == 1 ) + { + Vector forward; + gEngfuncs.pfnAngleVectors( v_angles, forward, NULL, NULL ); + to->client.velocity = to->client.velocity - forward * g_flApplyVel * 5; + g_irunninggausspred = false; + } + + // All games can use FOV state + g_lastFOV = to->client.fov; +} diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp new file mode 100644 index 00000000..374f3b9d --- /dev/null +++ b/cl_dll/hud.cpp @@ -0,0 +1,587 @@ +/*** +* +* 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. +* +****/ +// +// hud.cpp +// +// implementation of CHud class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "hud_servers.h" + + +#include "demo.h" +#include "demo_api.h" + + + + +extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +extern cvar_t *sensitivity; +cvar_t *cl_lw = NULL; + +void ShutdownInput (void); + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Logo(pszName, iSize, pbuf ); +} + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); +} + +int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); +} + +int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); +} + +int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); +} + +// TFFree Command Menu +void __CmdFunc_OpenCommandMenu(void) +{ +} + +// TFC "special" command +void __CmdFunc_InputPlayerSpecial(void) +{ +} + +void __CmdFunc_CloseCommandMenu(void) +{ +} + +void __CmdFunc_ForceCloseCommandMenu( void ) +{ +} + +void __CmdFunc_ToggleServerBrowser( void ) +{ +} + +// TFFree Command Menu Message Handlers +int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + + +int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +// This is called every time the DLL is loaded +void CHud :: Init( void ) +{ + HOOK_MESSAGE( Logo ); + HOOK_MESSAGE( ResetHUD ); + HOOK_MESSAGE( GameMode ); + HOOK_MESSAGE( InitHUD ); + HOOK_MESSAGE( ViewMode ); + HOOK_MESSAGE( SetFOV ); + HOOK_MESSAGE( Concuss ); + + // TFFree CommandMenu + HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); + HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); + HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); + HOOK_COMMAND( "special", InputPlayerSpecial ); + HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); + + HOOK_MESSAGE( ValClass ); + HOOK_MESSAGE( TeamNames ); + HOOK_MESSAGE( Feign ); + HOOK_MESSAGE( Detpack ); + HOOK_MESSAGE( BuildSt ); + HOOK_MESSAGE( RandomPC ); + HOOK_MESSAGE( ServerName ); + + HOOK_MESSAGE( Spectator ); + HOOK_MESSAGE( AllowSpec ); + + // VGUI Menus + HOOK_MESSAGE( VGUIMenu ); + + CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch + CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round + + + m_iLogo = 0; + m_iFOV = 0; + + CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); + default_fov = CVAR_CREATE( "default_fov", "90", 0 ); + m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); + m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); + cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); + + m_pSpriteList = NULL; + + // Clear any old HUD list + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + // In case we get messages before the first update -- time will be valid + m_flTime = 1.0; + + m_Ammo.Init(); + m_Health.Init(); + m_SayText.Init(); + m_Spectator.Init(); + m_Geiger.Init(); + m_Train.Init(); + m_Battery.Init(); + m_Flash.Init(); + m_Message.Init(); + m_StatusBar.Init(); + m_DeathNotice.Init(); + m_AmmoSecondary.Init(); + m_TextMessage.Init(); + m_StatusIcons.Init(); + m_MOTD.Init(); + m_Scoreboard.Init(); + + m_Menu.Init(); + + + MsgFunc_ResetHUD(0, 0, NULL ); +} + +// CHud destructor +// cleans up memory allocated for m_rg* arrays +CHud :: ~CHud() +{ + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + +} + +// GetSpriteIndex() +// searches through the sprite list loaded from hud.txt for a name matching SpriteName +// returns an index into the gHUD.m_rghSprites[] array +// returns 0 if sprite not found +int CHud :: GetSpriteIndex( const char *SpriteName ) +{ + // look through the loaded sprite name list for SpriteName + for ( int i = 0; i < m_iSpriteCount; i++ ) + { + if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) + return i; + } + + return -1; // invalid sprite +} + +void CHud :: VidInit( void ) +{ + m_scrinfo.iSize = sizeof(m_scrinfo); + GetScreenInfo(&m_scrinfo); + + // ---------- + // Load Sprites + // --------- +// m_hsprFont = LoadSprite("sprites/%d_font.spr"); + + m_hsprLogo = 0; + m_hsprCursor = 0; + + if (ScreenWidth < 640) + m_iRes = 320; + else + m_iRes = 640; + + // Only load this once + if ( !m_pSpriteList ) + { + // we need to load the hud.txt, and all sprites within + m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); + + if (m_pSpriteList) + { + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + client_sprite_t *p = m_pSpriteList; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf(sz, "sprites/%s.spr", p->szSprite); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + } + else + { + // we have already have loaded the sprite reference from hud.txt, but + // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) + client_sprite_t *p = m_pSpriteList; + + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + + // assumption: number_1, number_2, etc, are all listed and loaded sequentially + m_HUD_number_0 = GetSpriteIndex( "number_0" ); + + m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; + + m_Ammo.VidInit(); + m_Health.VidInit(); + m_Spectator.VidInit(); + m_Geiger.VidInit(); + m_Train.VidInit(); + m_Battery.VidInit(); + m_Flash.VidInit(); + m_Message.VidInit(); + m_StatusBar.VidInit(); + m_DeathNotice.VidInit(); + m_SayText.VidInit(); + m_Menu.VidInit(); + m_AmmoSecondary.VidInit(); + m_TextMessage.VidInit(); + m_StatusIcons.VidInit(); + m_Scoreboard.VidInit(); + m_MOTD.VidInit(); + +} + +int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update Train data + m_iLogo = READ_BYTE(); + + return 1; +} + +float g_lastFOV = 0.0; + +/* +============ +COM_FileBase +============ +*/ +// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) +void COM_FileBase ( const char *in, char *out) +{ + int len, start, end; + + len = strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + end--; + + if ( in[end] != '.' ) // no '.', copy to end + end = len-1; + else + end--; // Found ',', copy to left of '.' + + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start--; + + if ( in[start] != '/' && in[start] != '\\' ) + start = 0; + else + start++; + + // Length of new sting + len = end - start + 1; + + // Copy partial string + strncpy( out, &in[start], len ); + // Terminate it + out[len] = 0; +} + +/* +================= +HUD_IsGame + +================= +*/ +int HUD_IsGame( const char *game ) +{ + const char *gamedir; + char gd[ 1024 ]; + + gamedir = gEngfuncs.pfnGetGameDirectory(); + if ( gamedir && gamedir[0] ) + { + COM_FileBase( gamedir, gd ); + if ( !stricmp( gd, game ) ) + return 1; + } + return 0; +} + +/* +===================== +HUD_GetFOV + +Returns last FOV +===================== +*/ +float HUD_GetFOV( void ) +{ + if ( gEngfuncs.pDemoAPI->IsRecording() ) + { + // Write it + int i = 0; + unsigned char buf[ 100 ]; + + // Active + *( float * )&buf[ i ] = g_lastFOV; + i += sizeof( float ); + + Demo_WriteBuffer( TYPE_ZOOM, i, buf ); + } + + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + { + g_lastFOV = g_demozoom; + } + return g_lastFOV; +} + +int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int newfov = READ_BYTE(); + int def_fov = CVAR_GET_FLOAT( "default_fov" ); + + //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). + if ( cl_lw && cl_lw->value ) + return 1; + + g_lastFOV = newfov; + + if ( newfov == 0 ) + { + m_iFOV = def_fov; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == def_fov ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + return 1; +} + + +void CHud::AddHudElem(CHudBase *phudelem) +{ + HUDLIST *pdl, *ptemp; + +//phudelem->Think(); + + if (!phudelem) + return; + + pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); + if (!pdl) + return; + + memset(pdl, 0, sizeof(HUDLIST)); + pdl->p = phudelem; + + if (!m_pHudList) + { + m_pHudList = pdl; + return; + } + + ptemp = m_pHudList; + + while (ptemp->pNext) + ptemp = ptemp->pNext; + + ptemp->pNext = pdl; +} + +float CHud::GetSensitivity( void ) +{ + return m_flMouseSensitivity; +} + + diff --git a/cl_dll/hud.h b/cl_dll/hud.h new file mode 100644 index 00000000..2078ea3e --- /dev/null +++ b/cl_dll/hud.h @@ -0,0 +1,701 @@ +/*** +* +* 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. +* +****/ +// +// hud.h +// +// class CHud declaration +// +// CHud handles the message, calculation, and drawing the HUD +// + + +#define RGB_YELLOWISH 0x00FFA000 //255,160,0 +#define RGB_REDISH 0x00FF1010 //255,160,0 +#define RGB_GREENISH 0x0000A000 //0,160,0 + +#include "wrect.h" +#include "cl_dll.h" +#include "ammo.h" + +#define DHN_DRAWZERO 1 +#define DHN_2DIGITS 2 +#define DHN_3DIGITS 4 +#define MIN_ALPHA 100 + +#define HUDELEM_ACTIVE 1 + +typedef struct { + int x, y; +} POSITION; + +enum +{ + MAX_PLAYERS = 64, + MAX_TEAMS = 64, + MAX_TEAM_NAME = 16, +}; + +typedef struct { + unsigned char r,g,b,a; +} RGBA; + +typedef struct cvar_s cvar_t; + + +#define HUD_ACTIVE 1 +#define HUD_INTERMISSION 2 + +#define MAX_PLAYER_NAME_LENGTH 32 + +#define MAX_MOTD_LENGTH 1536 + +// +//----------------------------------------------------- +// +class CHudBase +{ +public: + POSITION m_pos; + int m_type; + int m_iFlags; // active, moving, + virtual ~CHudBase() {} + virtual int Init( void ) {return 0;} + virtual int VidInit( void ) {return 0;} + virtual int Draw(float flTime) {return 0;} + virtual void Think(void) {return;} + virtual void Reset(void) {return;} + virtual void InitHUDData( void ) {} // called every time a server is connected to + +}; + +struct HUDLIST { + CHudBase *p; + HUDLIST *pNext; +}; + + + +// +//----------------------------------------------------- +#include "hud_spectator.h" + + +// +//----------------------------------------------------- +// +class CHudAmmo: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Think(void); + void Reset(void); + int DrawWList(float flTime); + int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); + int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); + + void SlotInput( int iSlot ); + void _cdecl UserCmd_Slot1( void ); + void _cdecl UserCmd_Slot2( void ); + void _cdecl UserCmd_Slot3( void ); + void _cdecl UserCmd_Slot4( void ); + void _cdecl UserCmd_Slot5( void ); + void _cdecl UserCmd_Slot6( void ); + void _cdecl UserCmd_Slot7( void ); + void _cdecl UserCmd_Slot8( void ); + void _cdecl UserCmd_Slot9( void ); + void _cdecl UserCmd_Slot10( void ); + void _cdecl UserCmd_Close( void ); + void _cdecl UserCmd_NextWeapon( void ); + void _cdecl UserCmd_PrevWeapon( void ); + +private: + float m_fFade; + RGBA m_rgba; + WEAPON *m_pWeapon; + int m_HUD_bucket0; + int m_HUD_selection; + +}; + +// +//----------------------------------------------------- +// + +class CHudAmmoSecondary: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + + int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); + +private: + enum { + MAX_SEC_AMMO_VALUES = 4 + }; + + int m_HUD_ammoicon; // sprite indices + int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; + float m_fFade; +}; + + +#include "health.h" + + +#define FADE_TIME 100 + + +// +//----------------------------------------------------- +// +class CHudGeiger: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); + +private: + int m_iGeigerRange; + +}; + +// +//----------------------------------------------------- +// +class CHudTrain: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); + +private: + HSPRITE m_hSprite; + int m_iPos; + +}; + +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// + +class CHudMOTD : public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw( float flTime ); + void Reset( void ); + + int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); + void Scroll( int dir ); + void Scroll( float amount ); + float scroll; + bool m_bShow; + +protected: + static int MOTD_DISPLAY_TIME; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + + int m_iLines; + int m_iMaxLength; +}; + + +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScores( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamNames( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +}; + + +// +//----------------------------------------------------- +// +class CHudStatusBar : public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw( float flTime ); + void Reset( void ); + void ParseStatusString( int line_num ); + + int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); + +protected: + enum { + MAX_STATUSTEXT_LENGTH = 128, + MAX_STATUSBAR_VALUES = 8, + MAX_STATUSBAR_LINES = 2, + }; + + char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn + char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn + int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar + + int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated + + // an array of colors...one color for each line + float *m_pflNameColors[MAX_STATUSBAR_LINES]; +}; + +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// +/* +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +private: + struct cvar_s *cl_showpacketloss; + +}; +*/ + +struct extra_player_info_t +{ + short frags; + short deaths; + short playerclass; + short teamnumber; + char teamname[MAX_TEAM_NAME]; +}; + +struct team_info_t +{ + char name[MAX_TEAM_NAME]; + short frags; + short deaths; + short ping; + short packetloss; + short ownteam; + short players; + int already_drawn; + int scores_overriden; + int teamnumber; +}; + +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS+1]; +extern int g_IsSpectator[MAX_PLAYERS+1]; + + +// +//----------------------------------------------------- +// +class CHudDeathNotice : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ); + +private: + int m_HUD_d_skull; // sprite index of skull icon +}; + +// +//----------------------------------------------------- +// +class CHudMenu : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + void Reset( void ); + int Draw( float flTime ); + int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ); + + void SelectMenuItem( int menu_item ); + + int m_fMenuDisplayed; + int m_bitsValidSlots; + float m_flShutoffTime; + int m_fWaitingForMore; +}; + +// +//----------------------------------------------------- +// +class CHudSayText : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); + void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); + void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); +friend class CHudSpectator; + +private: + + struct cvar_s * m_HUD_saytext; + struct cvar_s * m_HUD_saytext_time; +}; + +// +//----------------------------------------------------- +// +class CHudBattery: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + wrect_t *m_prc1; + wrect_t *m_prc2; + int m_iBat; + float m_fFade; + int m_iHeight; // width of the battery innards +}; + + +// +//----------------------------------------------------- +// +class CHudFlashlight: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset( void ); + int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + HSPRITE m_hBeam; + wrect_t *m_prc1; + wrect_t *m_prc2; + wrect_t *m_prcBeam; + float m_flBat; + int m_iBat; + int m_fOn; + float m_fFade; + int m_iWidth; // width of the battery innards +}; + +// +//----------------------------------------------------- +// +const int maxHUDMessages = 16; +struct message_parms_t +{ + client_textmessage_t *pMessage; + float time; + int x, y; + int totalWidth, totalHeight; + int width; + int lines; + int lineLength; + int length; + int r, g, b; + int text; + int fadeBlend; + float charTime; + float fadeTime; +}; + +// +//----------------------------------------------------- +// + +class CHudTextMessage: public CHudBase +{ +public: + int Init( void ); + static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); + static char *BufferedLocaliseTextString( const char *msg ); + char *LookupString( const char *msg_name, int *msg_dest = NULL ); + int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); +}; + +// +//----------------------------------------------------- +// + +class CHudMessage: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); + int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); + + float FadeBlend( float fadein, float fadeout, float hold, float localTime ); + int XPosition( float x, int width, int lineWidth ); + int YPosition( float y, int height ); + + void MessageAdd( const char *pName, float time ); + void MessageAdd(client_textmessage_t * newMessage ); + void MessageDrawScan( client_textmessage_t *pMessage, float time ); + void MessageScanStart( void ); + void MessageScanNextChar( void ); + void Reset( void ); + +private: + client_textmessage_t *m_pMessages[maxHUDMessages]; + float m_startTime[maxHUDMessages]; + message_parms_t m_parms; + float m_gameTitleTime; + client_textmessage_t *m_pGameTitle; + + int m_HUD_title_life; + int m_HUD_title_half; +}; + +// +//----------------------------------------------------- +// +#define MAX_SPRITE_NAME_LENGTH 24 + +class CHudStatusIcons: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf); + + enum { + MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, + MAX_ICONSPRITES = 4, + }; + + + //had to make these public so CHud could access them (to enable concussion icon) + //could use a friend declaration instead... + void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); + void DisableIcon( char *pszIconName ); + +private: + + typedef struct + { + char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; + HSPRITE spr; + wrect_t rc; + unsigned char r, g, b; + } icon_sprite_t; + + icon_sprite_t m_IconList[MAX_ICONSPRITES]; + +}; + +// +//----------------------------------------------------- +// + + + +class CHud +{ +private: + HUDLIST *m_pHudList; + HSPRITE m_hsprLogo; + int m_iLogo; + client_sprite_t *m_pSpriteList; + int m_iSpriteCount; + int m_iSpriteCountAllRes; + float m_flMouseSensitivity; + int m_iConcussionEffect; + +public: + + HSPRITE m_hsprCursor; + float m_flTime; // the current client time + float m_fOldTime; // the time at which the HUD was last redrawn + double m_flTimeDelta; // the difference between flTime and fOldTime + Vector m_vecOrigin; + Vector m_vecAngles; + int m_iKeyBits; + int m_iHideHUDDisplay; + int m_iFOV; + int m_Teamplay; + int m_iRes; + cvar_t *m_pCvarStealMouse; + cvar_t *m_pCvarDraw; + + int m_iFontHeight; + int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); + int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b ); + int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); + int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); + int GetNumWidth(int iNumber, int iFlags); + void DrawDarkRectangle( int x, int y, int wide, int tall); + +private: + // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. + // freed in ~CHud() + HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt + wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ + char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ + + struct cvar_s *default_fov; +public: + HSPRITE GetSprite( int index ) + { + return (index < 0) ? 0 : m_rghSprites[index]; + } + + wrect_t& GetSpriteRect( int index ) + { + return m_rgrcRects[index]; + } + + + int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array + + CHudAmmo m_Ammo; + CHudHealth m_Health; + CHudSpectator m_Spectator; + CHudGeiger m_Geiger; + CHudBattery m_Battery; + CHudTrain m_Train; + CHudFlashlight m_Flash; + CHudMessage m_Message; + CHudStatusBar m_StatusBar; + CHudDeathNotice m_DeathNotice; + CHudSayText m_SayText; + CHudMenu m_Menu; + CHudAmmoSecondary m_AmmoSecondary; + CHudTextMessage m_TextMessage; + CHudStatusIcons m_StatusIcons; + CHudScoreboard m_Scoreboard; + CHudMOTD m_MOTD; + + + void Init( void ); + void VidInit( void ); + void Think(void); + int Redraw( float flTime, int intermission ); + int UpdateClientData( client_data_t *cdata, float time ); + + CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} + ~CHud(); // destructor, frees allocated memory + + // user messages + int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); + void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); + void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); + + // Screen information + SCREENINFO m_scrinfo; + + int m_iWeaponBits; + int m_fPlayerDead; + int m_iIntermission; + + // sprite indexes + int m_HUD_number_0; + + int m_iNoConsolePrint; + + void AddHudElem(CHudBase *p); + + float GetSensitivity(); + +}; + + +extern CHud gHUD; + +extern int g_iPlayerClass; +extern int g_iTeamNumber; +extern int g_iUser1; +extern int g_iUser2; +extern int g_iUser3; + diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h new file mode 100644 index 00000000..8427d77f --- /dev/null +++ b/cl_dll/hud_iface.h @@ -0,0 +1,25 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_IFACEH ) +#define HUD_IFACEH +#pragma once + +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#define _DLLEXPORT __declspec( dllexport ) +#else +#define EXPORT +#define _DLLEXPORT +#endif + +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +#include "wrect.h" +#include "../engine/cdll_int.h" +extern cl_enginefunc_t gEngfuncs; + +#endif \ No newline at end of file diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp new file mode 100644 index 00000000..0505d172 --- /dev/null +++ b/cl_dll/hud_msg.cpp @@ -0,0 +1,120 @@ +/*** +* +* 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. +* +****/ +// +// hud_msg.cpp +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "r_efx.h" + +#define MAX_CLIENTS 32 + +extern BEAM *pBeam; +extern BEAM *pBeam2; + +/// USER-DEFINED SERVER MESSAGE HANDLERS + +int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) +{ + ASSERT( iSize == 0 ); + + // clear all hud data + HUDLIST *pList = m_pHudList; + + while ( pList ) + { + if ( pList->p ) + pList->p->Reset(); + pList = pList->pNext; + } + + // reset sensitivity + m_flMouseSensitivity = 0; + + // reset concussion effect + m_iConcussionEffect = 0; + + return 1; +} + +void CAM_ToFirstPerson(void); + +void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) +{ + CAM_ToFirstPerson(); +} + +void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) +{ + // prepare all hud data + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( pList->p ) + pList->p->InitHUDData(); + pList = pList->pNext; + } + + //Probably not a good place to put this. + pBeam = pBeam2 = NULL; +} + + +int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_Teamplay = READ_BYTE(); + + return 1; +} + + +int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + int armor, blood; + Vector from; + int i; + float count; + + BEGIN_READ( pbuf, iSize ); + armor = READ_BYTE(); + blood = READ_BYTE(); + + for (i=0 ; i<3 ; i++) + from[i] = READ_COORD(); + + count = (blood * 0.5) + (armor * 0.5); + + if (count < 10) + count = 10; + + // TODO: kick viewangles, show damage visually + + return 1; +} + +int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_iConcussionEffect = READ_BYTE(); + if (m_iConcussionEffect) + this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0); + else + this->m_StatusIcons.DisableIcon("dmg_concuss"); + return 1; +} diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp new file mode 100644 index 00000000..ad6999d8 --- /dev/null +++ b/cl_dll/hud_redraw.cpp @@ -0,0 +1,342 @@ +/*** +* +* 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. +* +****/ +// +// hud_redraw.cpp +// +#include +#include "hud.h" +#include "cl_util.h" +#include "triangleapi.h" + + +#define MAX_LOGO_FRAMES 56 + +int grgLogoFrame[MAX_LOGO_FRAMES] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, + 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 +}; + + +extern int g_iVisibleMouse; + +float HUD_GetFOV( void ); + +extern cvar_t *sensitivity; + +// Think +void CHud::Think(void) +{ + int newfov; + HUDLIST *pList = m_pHudList; + + while (pList) + { + if (pList->p->m_iFlags & HUD_ACTIVE) + pList->p->Think(); + pList = pList->pNext; + } + + newfov = HUD_GetFOV(); + if ( newfov == 0 ) + { + m_iFOV = default_fov->value; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == default_fov->value ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + // think about default fov + if ( m_iFOV == 0 ) + { // only let players adjust up in fov, and only if they are not overriden by something else + m_iFOV = max( default_fov->value, 90 ); + } +} + +// Redraw +// step through the local data, placing the appropriate graphics & text as appropriate +// returns 1 if they've changed, 0 otherwise +int CHud :: Redraw( float flTime, int intermission ) +{ + m_fOldTime = m_flTime; // save time of previous redraw + m_flTime = flTime; + m_flTimeDelta = (double)m_flTime - m_fOldTime; + static float m_flShotTime = 0; + + // Clock was reset, reset delta + if ( m_flTimeDelta < 0 ) + m_flTimeDelta = 0; + + + if (m_flShotTime && m_flShotTime < flTime) + { + gEngfuncs.pfnClientCmd("snapshot\n"); + m_flShotTime = 0; + } + + m_iIntermission = intermission; + + // if no redrawing is necessary + // return 0; + + if ( m_pCvarDraw->value ) + { + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( !intermission ) + { + if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) + pList->p->Draw(flTime); + } + else + { // it's an intermission, so only draw hud elements that are set to draw during intermissions + if ( pList->p->m_iFlags & HUD_INTERMISSION ) + pList->p->Draw( flTime ); + } + + pList = pList->pNext; + } + } + + // are we in demo mode? do we need to draw the logo in the top corner? + if (m_iLogo) + { + int x, y, i; + + if (m_hsprLogo == 0) + m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + + SPR_Set(m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width(m_hsprLogo, 0); + x = ScreenWidth - x; + y = SPR_Height(m_hsprLogo, 0)/2; + + // Draw the logo at 20 fps + int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + i = grgLogoFrame[iFrame] - 1; + + SPR_DrawAdditive(i, x, y, NULL); + } + + /* + if ( g_iVisibleMouse ) + { + void IN_GetMousePos( int *mx, int *my ); + int mx, my; + + IN_GetMousePos( &mx, &my ); + + if (m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + m_hsprCursor = SPR_Load( sz ); + } + + SPR_Set(m_hsprCursor, 250, 250, 250 ); + + // Draw the logo at 20 fps + SPR_DrawAdditive( 0, mx, my, NULL ); + } + */ + + return 1; +} + +void ScaleColors( int &r, int &g, int &b, int a ) +{ + float x = (float)a / 255; + r = (int)(r * x); + g = (int)(g * x); + b = (int)(b * x); +} + +int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +{ + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next > iMaxX ) + return xpos; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + xpos = next; + } + + return xpos; +} + +int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) +{ + char szString[32]; + sprintf( szString, "%d", iNumber ); + return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); + +} + +// draws a string from right to left (right-aligned) +int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +{ + // find the end of the string + for ( char *szIt = szString; *szIt != 0; szIt++ ) + { // we should count the length? + } + + // iterate throug the string in reverse + for ( szIt--; szIt != (szString-1); szIt-- ) + { + int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next < iMinX ) + return xpos; + xpos = next; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + } + + return xpos; +} + +int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) +{ + int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; + int k; + + if (iNumber > 0) + { + // SPR_Draw 100's + if (iNumber >= 100) + { + k = iNumber/100; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw 10's + if (iNumber >= 10) + { + k = (iNumber % 100)/10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + k = iNumber % 10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & DHN_DRAWZERO) + { + SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); + + // SPR_Draw 100's + if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); + x += iWidth; + } + + return x; +} + + +int CHud::GetNumWidth( int iNumber, int iFlags ) +{ + if (iFlags & (DHN_3DIGITS)) + return 3; + + if (iFlags & (DHN_2DIGITS)) + return 2; + + if (iNumber <= 0) + { + if (iFlags & (DHN_DRAWZERO)) + return 1; + else + return 0; + } + + if (iNumber < 10) + return 1; + + if (iNumber < 100) + return 2; + + return 3; + +} + + +void CHud::DrawDarkRectangle( int x, int y, int wide, int tall ) +{ + FillRGBA( x, y, wide, tall, 0, 0, 0, 0 ); + float m_flScale = 1; + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + gEngfuncs.pTriAPI->Color4f(0.0, 0.0, 0.0, 0.6); + gEngfuncs.pTriAPI->Vertex3f(x * m_flScale, (y+tall)*m_flScale, 0); + gEngfuncs.pTriAPI->Vertex3f(x * m_flScale, y*m_flScale, 0); + gEngfuncs.pTriAPI->Vertex3f((x + wide)*m_flScale, y*m_flScale, 0); + gEngfuncs.pTriAPI->Vertex3f((x + wide)*m_flScale, (y+tall)*m_flScale, 0); + gEngfuncs.pTriAPI->End(); + FillRGBA( x+1, y, wide-1, 1, 255, 140, 0, 255 ); + FillRGBA( x, y, 1, tall-1, 255, 140, 0, 255 ); + FillRGBA( x+wide-1, y+1, 1, tall-1, 255, 140, 0, 255 ); + FillRGBA( x, y+tall-1, wide-1, 1, 255, 140, 0, 255 ); +} diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp new file mode 100644 index 00000000..8bd42d33 --- /dev/null +++ b/cl_dll/hud_servers.cpp @@ -0,0 +1,1230 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// hud_servers.cpp +#include "hud.h" +#include "cl_util.h" +#include "hud_servers_priv.h" +#include "hud_servers.h" +#include "net_api.h" +#include +#include + +static int context_id; + +// Default master server address in case we can't read any from woncomm.lst file +#define VALVE_MASTER_ADDRESS "half-life.east.won.net" +#define PORT_MASTER 27010 +#define PORT_SERVER 27015 + +// File where we really should look for master servers +#define MASTER_PARSE_FILE "woncomm.lst" + +#define MAX_QUERIES 20 + +#define NET_API gEngfuncs.pNetAPI + +static CHudServers *g_pServers = NULL; + +/* +=================== +ListResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ListResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ListResponse( response ); + } +} + +/* +=================== +ServerResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ServerResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ServerResponse( response ); + } +} + +/* +=================== +PingResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PingResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PingResponse( response ); + } +} + +/* +=================== +RulesResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK RulesResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->RulesResponse( response ); + } +} +/* +=================== +PlayersResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PlayersResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PlayersResponse( response ); + } +} +/* +=================== +ListResponse + +=================== +*/ +void CHudServers::ListResponse( struct net_response_s *response ) +{ + request_t *list; + request_t *p; + int c = 0; + + if ( !( response->error == NET_SUCCESS ) ) + return; + + if ( response->type != NETAPI_REQUEST_SERVERLIST ) + return; + + if ( response->response ) + { + list = ( request_t * ) response->response; + while ( list ) + { + c++; + + //if ( c < 40 ) + { + // Copy from parsed stuff + p = new request_t; + p->context = -1; + p->remote_address = list->remote_address; + p->next = m_pServerList; + m_pServerList = p; + } + + // Move on + list = list->next; + } + } + + gEngfuncs.Con_Printf( "got list\n" ); + + m_nQuerying = 1; + m_nActiveQueries = 0; +} + +/* +=================== +ServerResponse + +=================== +*/ +void CHudServers::ServerResponse( struct net_response_s *response ) +{ + char *szresponse; + request_t *p; + server_t *browser; + int len; + char sz[ 32 ]; + + // Remove from active list + p = FindRequest( response->context, m_pActiveList ); + if ( p ) + { + RemoveServerFromList( &m_pActiveList, p ); + m_nActiveQueries--; + } + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_DETAILS: + if ( response->response ) + { + szresponse = (char *)response->response; + len = strlen( szresponse ) + 100 + 1; + sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); + + browser = new server_t; + browser->remote_address = response->remote_address; + browser->info = new char[ len ]; + browser->ping = (int)( 1000.0 * response->ping ); + strcpy( browser->info, szresponse ); + + NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); + NET_API->SetValueForKey( browser->info, "ping", sz, len ); + + AddServer( &m_pServers, browser ); + } + break; + default: + break; + } +} + +/* +=================== +PingResponse + +=================== +*/ +void CHudServers::PingResponse( struct net_response_s *response ) +{ + char sz[ 32 ]; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PING: + sprintf( sz, "%.2f", 1000.0 * response->ping ); + + gEngfuncs.Con_Printf( "ping == %s\n", sz ); + break; + default: + break; + } +} + +/* +=================== +RulesResponse + +=================== +*/ +void CHudServers::RulesResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_RULES: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "rules %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +PlayersResponse + +=================== +*/ +void CHudServers::PlayersResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PLAYERS: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "players %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +CompareServers + +Return 1 if p1 is "less than" p2, 0 otherwise +=================== +*/ +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +{ + const char *n1, *n2; + + if ( p1->ping < p2->ping ) + return 1; + + if ( p1->ping == p2->ping ) + { + // Pings equal, sort by second key: hostname + if ( p1->info && p2->info ) + { + n1 = NET_API->ValueForKey( p1->info, "hostname" ); + n2 = NET_API->ValueForKey( p2->info, "hostname" ); + + if ( n1 && n2 ) + { + if ( stricmp( n1, n2 ) < 0 ) + return 1; + } + } + } + + return 0; +} + +/* +=================== +AddServer + +=================== +*/ +void CHudServers::AddServer( server_t **ppList, server_t *p ) +{ +server_t *list; + + if ( !ppList || ! p ) + return; + + m_nServerCount++; + + // What sort key? Ping? + list = *ppList; + + // Head of list? + if ( !list ) + { + p->next = NULL; + *ppList = p; + return; + } + + // Put on head of list + if ( CompareServers( p, list ) ) + { + p->next = *ppList; + *ppList = p; + } + else + { + while ( list->next ) + { + // Insert before list next + if ( CompareServers( p, list->next ) ) + { + p->next = list->next->next; + list->next = p; + return; + } + + list = list->next; + } + + // Just add at end + p->next = NULL; + list->next = p; + } +} + +/* +=================== +Think + +=================== +*/ +void CHudServers::Think( double time ) +{ + m_fElapsed += time; + + if ( !m_nRequesting ) + return; + + if ( !m_nQuerying ) + return; + + QueryThink(); + + if ( ServerListSize() > 0 ) + return; + + m_dStarted = 0.0; + m_nRequesting = 0; + m_nDone = 0; + m_nQuerying = 0; + m_nActiveQueries = 0; +} + +/* +=================== +QueryThink + +=================== +*/ +void CHudServers::QueryThink( void ) +{ + request_t *p; + + if ( !m_nRequesting || m_nDone ) + return; + + if ( !m_nQuerying ) + return; + + if ( m_nActiveQueries > MAX_QUERIES ) + return; + + // Nothing left + if ( !m_pServerList ) + return; + + while ( 1 ) + { + p = m_pServerList; + + // No more in list? + if ( !p ) + break; + + // Move to next + m_pServerList = m_pServerList->next; + + // Setup context_id + p->context = context_id; + + // Start up query on this one + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); + + // Increment active list + m_nActiveQueries++; + + // Add to active list + p->next = m_pActiveList; + m_pActiveList = p; + + // Too many active? + if ( m_nActiveQueries > MAX_QUERIES ) + break; + } +} + +/* +================== +ServerListSize + +# of servers in active query and in pending to be queried lists +================== +*/ +int CHudServers::ServerListSize( void ) +{ + int c = 0; + request_t *p; + + p = m_pServerList; + while ( p ) + { + c++; + p = p->next; + } + + p = m_pActiveList; + while ( p ) + { + c++; + p = p->next; + } + + return c; +} + +/* +=================== +FindRequest + +Look up a request by context id +=================== +*/ +CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) +{ + request_t *p; + p = pList; + while ( p ) + { + if ( context == p->context ) + return p; + + p = p->next; + } + return NULL; +} + +/* +=================== +RemoveServerFromList + +Remote, but don't delete, item from *ppList +=================== +*/ +void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) +{ + request_t *p, *n; + request_t *newlist = NULL; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + if ( p != item ) + { + p->next = newlist; + newlist = p; + } + p = n; + } + *ppList = newlist; +} + +/* +=================== +ClearRequestList + +=================== +*/ +void CHudServers::ClearRequestList( request_t **ppList ) +{ + request_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete p; + p = n; + } + *ppList = NULL; +} + +/* +=================== +ClearServerList + +=================== +*/ +void CHudServers::ClearServerList( server_t **ppList ) +{ + server_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete[] p->info; + delete p; + p = n; + } + *ppList = NULL; +} + +int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) +{ + const char *sz1, *sz2; + float fv1, fv2; + + sz1 = NET_API->ValueForKey( p1->info, fieldname ); + sz2 = NET_API->ValueForKey( p2->info, fieldname ); + + fv1 = atof( sz1 ); + fv2 = atof( sz2 ); + + if ( fv1 && fv2 ) + { + if ( fv1 > fv2 ) + return iSortOrder; + else if ( fv1 < fv2 ) + return -iSortOrder; + else + return 0; + } + + // String compare + return stricmp( sz1, sz2 ); +} + +int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) +{ + if (!p1 || !p2) // No meaningful comparison + return 0; + + int iSortOrder = 1; + + int retval = 0; + + retval = CompareField( p1, p2, fieldname, iSortOrder ); + + return retval; +} + +static char g_fieldname[ 256 ]; +int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +{ + CHudServers::server_t *list1, *list2; + + list1 = *(CHudServers::server_t **)elem1; + list2 = *(CHudServers::server_t **)elem2; + + return ServerListCompareFunc( list1, list2, g_fieldname ); +} + +void CHudServers::SortServers( const char *fieldname ) +{ + server_t *p; + // Create a list + if ( !m_pServers ) + return; + + strcpy( g_fieldname, fieldname ); + + int i; + int c = 0; + + p = m_pServers; + while ( p ) + { + c++; + p = p->next; + } + + server_t **pSortArray; + + pSortArray = new server_t *[ c ]; + memset( pSortArray, 0, c * sizeof( server_t * ) ); + + // Now copy the list into the pSortArray: + p = m_pServers; + i = 0; + while ( p ) + { + pSortArray[ i++ ] = p; + p = p->next; + } + + // Now do that actual sorting. + size_t nCount = c; + size_t nSize = sizeof( server_t * ); + + qsort( + pSortArray, + (size_t)nCount, + (size_t)nSize, + FnServerCompare + ); + + // Now rebuild the list. + m_pServers = pSortArray[0]; + for ( i = 0; i < c - 1; i++ ) + { + pSortArray[ i ]->next = pSortArray[ i + 1 ]; + } + pSortArray[ c - 1 ]->next = NULL; + + // Clean Up. + delete[] pSortArray; +} + +/* +=================== +GetServer + +Return particular server +=================== +*/ +CHudServers::server_t *CHudServers::GetServer( int server ) +{ + int c = 0; + server_t *p; + + p = m_pServers; + while ( p ) + { + if ( c == server ) + return p; + + c++; + p = p->next; + } + return NULL; +} + +/* +=================== +GetServerInfo + +Return info ( key/value ) string for particular server +=================== +*/ +char *CHudServers::GetServerInfo( int server ) +{ + server_t *p = GetServer( server ); + if ( p ) + { + return p->info; + } + return NULL; +} + +/* +=================== +CancelRequest + +Kill all pending requests in engine +=================== +*/ +void CHudServers::CancelRequest( void ) +{ + m_nRequesting = 0; + m_nQuerying = 0; + m_nDone = 1; + + NET_API->CancelAllRequests(); +} + +/* +================== +LoadMasterAddresses + +Loads the master server addresses from file and into the passed in array +================== +*/ +int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) +{ + int i; + char szMaster[ 256 ]; + char szMasterFile[256]; + char *pbuffer = NULL; + char *pstart = NULL ; + netadr_t adr; + char szAdr[64]; + int nPort; + int nCount = 0; + bool bIgnore; + int nDefaultPort; + + // Assume default master and master file + strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + strcpy( szMasterFile, MASTER_PARSE_FILE ); + + // See if there is a command line override + i = gEngfuncs.CheckParm( "-comm", &pstart ); + if ( i && pstart ) + { + strcpy (szMasterFile, pstart ); + } + + // Read them in from proper file + pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc + if ( !pbuffer ) + { + goto finish_master; + } + + pstart = pbuffer; + + while ( nCount < maxservers ) + { + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if ( strlen(m_szToken) <= 0) + break; + + bIgnore = true; + + if ( !stricmp( m_szToken, "Master" ) ) + { + nDefaultPort = PORT_MASTER; + bIgnore = FALSE; + } + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + if ( strlen(m_szToken) <= 0 ) + break; + + if ( stricmp ( m_szToken, "{" ) ) + break; + + // Parse addresses until we get to "}" + while ( nCount < maxservers ) + { + char base[256]; + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( !stricmp ( m_szToken, "}" ) ) + break; + + sprintf( base, "%s", m_szToken ); + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( stricmp( m_szToken, ":" ) ) + break; + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + nPort = atoi ( m_szToken ); + if ( !nPort ) + nPort = nDefaultPort; + + sprintf( szAdr, "%s:%i", base, nPort ); + + // Can we resolve it any better + if ( !NET_API->StringToAdr( szAdr, &adr ) ) + bIgnore = true; + + if ( !bIgnore ) + { + padr[ nCount++ ] = adr; + } + } + } + +finish_master: + if ( !nCount ) + { + sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + + // Convert to netadr_t + if ( NET_API->StringToAdr ( szMaster, &adr ) ) + { + + padr[ nCount++ ] = adr; + } + } + + *count = nCount; + + if ( pbuffer ) + { + gEngfuncs.COM_FreeFile( pbuffer ); + } + + return ( nCount > 0 ) ? 1 : 0; +} + +/* +=================== +RequestList + +Request list of game servers from master +=================== +*/ +void CHudServers::RequestList( void ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + int count = 0; + netadr_t adr; + + if ( !LoadMasterAddresses( 1, &count, &adr ) ) + { + gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); + return; + } + + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Kill off left overs if any + NET_API->CancelAllRequests(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); +} + +void CHudServers::RequestBroadcastList( int clearpending ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + netadr_t adr; + memset( &adr, 0, sizeof( adr ) ); + + if ( clearpending ) + { + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + } + + // Make sure to byte swap server if necessary ( using "host" to "net" conversion + adr.port = htons( PORT_SERVER ); + + // Make sure networking system has started. + NET_API->InitNetworking(); + + if ( clearpending ) + { + // Kill off left overs if any + NET_API->CancelAllRequests(); + } + + adr.type = NA_BROADCAST; + + // Request Servers from LAN via IP + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); + + adr.type = NA_BROADCAST_IPX; + + // Request Servers from LAN via IPX ( if supported ) + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); +} + +void CHudServers::ServerPing( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); +} + +void CHudServers::ServerRules( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); +} + +void CHudServers::ServerPlayers( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); +} + +int CHudServers::isQuerying() +{ + return m_nRequesting ? 1 : 0; +} + + +/* +=================== +GetServerCount + +Return number of servers in browser list +=================== +*/ +int CHudServers::GetServerCount( void ) +{ + return m_nServerCount; +} + +/* +=================== +CHudServers + +=================== +*/ +CHudServers::CHudServers( void ) +{ + m_nRequesting = 0; + m_dStarted = 0.0; + m_nDone = 0; + m_pServerList = NULL; + m_pServers = NULL; + m_pActiveList = NULL; + m_nQuerying = 0; + m_nActiveQueries = 0; + + m_fElapsed = 0.0; + + + m_pPingRequest = NULL; + m_pRulesRequest = NULL; + m_pPlayersRequest = NULL; +} + +/* +=================== +~CHudServers + +=================== +*/ +CHudServers::~CHudServers( void ) +{ + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + if ( m_pPingRequest ) + { + delete m_pPingRequest; + m_pPingRequest = NULL; + + } + + if ( m_pRulesRequest ) + { + delete m_pRulesRequest; + m_pRulesRequest = NULL; + } + + if ( m_pPlayersRequest ) + { + delete m_pPlayersRequest; + m_pPlayersRequest = NULL; + } +} + +/////////////////////////////// +// +// PUBLIC APIs +// +/////////////////////////////// + +/* +=================== +ServersGetCount + +=================== +*/ +int ServersGetCount( void ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerCount(); + } + return 0; +} + +int ServersIsQuerying( void ) +{ + if ( g_pServers ) + { + return g_pServers->isQuerying(); + } + return 0; +} + +/* +=================== +ServersGetInfo + +=================== +*/ +const char *ServersGetInfo( int server ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerInfo( server ); + } + + return NULL; +} + +void SortServers( const char *fieldname ) +{ + if ( g_pServers ) + { + g_pServers->SortServers( fieldname ); + } +} + +/* +=================== +ServersShutdown + +=================== +*/ +void ServersShutdown( void ) +{ + if ( g_pServers ) + { + delete g_pServers; + g_pServers = NULL; + } +} + +/* +=================== +ServersInit + +=================== +*/ +void ServersInit( void ) +{ + // Kill any previous instance + ServersShutdown(); + + g_pServers = new CHudServers(); +} + +/* +=================== +ServersThink + +=================== +*/ +void ServersThink( double time ) +{ + if ( g_pServers ) + { + g_pServers->Think( time ); + } +} + +/* +=================== +ServersCancel + +=================== +*/ +void ServersCancel( void ) +{ + if ( g_pServers ) + { + g_pServers->CancelRequest(); + } +} + +// Requests +/* +=================== +ServersList + +=================== +*/ +void ServersList( void ) +{ + if ( g_pServers ) + { + g_pServers->RequestList(); + } +} + +void BroadcastServersList( int clearpending ) +{ + if ( g_pServers ) + { + g_pServers->RequestBroadcastList( clearpending ); + } +} + +void ServerPing( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPing( server ); + } +} + +void ServerRules( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerRules( server ); + } +} + +void ServerPlayers( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPlayers( server ); + } +} \ No newline at end of file diff --git a/cl_dll/hud_servers.h b/cl_dll/hud_servers.h new file mode 100644 index 00000000..02bc8555 --- /dev/null +++ b/cl_dll/hud_servers.h @@ -0,0 +1,41 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERSH ) +#define HUD_SERVERSH +#pragma once + +#define NET_CALLBACK /* */ + +// Dispatchers +void NET_CALLBACK ListResponse( struct net_response_s *response ); +void NET_CALLBACK ServerResponse( struct net_response_s *response ); +void NET_CALLBACK PingResponse( struct net_response_s *response ); +void NET_CALLBACK RulesResponse( struct net_response_s *response ); +void NET_CALLBACK PlayersResponse( struct net_response_s *response ); + +void ServersInit( void ); +void ServersShutdown( void ); +void ServersThink( double time ); +void ServersCancel( void ); + +// Get list and get server info from each +void ServersList( void ); + +// Query for IP / IPX LAN servers +void BroadcastServersList( int clearpending ); + +void ServerPing( int server ); +void ServerRules( int server ); +void ServerPlayers( int server ); + +int ServersGetCount( void ); +const char *ServersGetInfo( int server ); +int ServersIsQuerying( void ); +void SortServers( const char *fieldname ); + +#endif // HUD_SERVERSH \ No newline at end of file diff --git a/cl_dll/hud_servers_priv.h b/cl_dll/hud_servers_priv.h new file mode 100644 index 00000000..1919a0a7 --- /dev/null +++ b/cl_dll/hud_servers_priv.h @@ -0,0 +1,98 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERS_PRIVH ) +#define HUD_SERVERS_PRIVH +#pragma once + +#include "netadr.h" + +class CHudServers +{ +public: + typedef struct request_s + { + struct request_s *next; + netadr_t remote_address; + int context; + } request_t; + + typedef struct server_s + { + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; + } server_t; + + CHudServers(); + ~CHudServers(); + + void Think( double time ); + void QueryThink( void ); + int isQuerying( void ); + + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + + void RequestList( void ); + void RequestBroadcastList( int clearpending ); + + void ServerPing( int server ); + void ServerRules( int server ); + void ServerPlayers( int server ); + + void CancelRequest( void ); + + int CompareServers( server_t *p1, server_t *p2 ); + + void ClearServerList( server_t **ppList ); + void ClearRequestList( request_t **ppList ); + + void AddServer( server_t **ppList, server_t *p ); + + void RemoveServerFromList( request_t **ppList, request_t *item ); + + request_t *FindRequest( int context, request_t *pList ); + + int ServerListSize( void ); + char *GetServerInfo( int server ); + int GetServerCount( void ); + void SortServers( const char *fieldname ); + + void ListResponse( struct net_response_s *response ); + void ServerResponse( struct net_response_s *response ); + void PingResponse( struct net_response_s *response ); + void RulesResponse( struct net_response_s *response ); + void PlayersResponse( struct net_response_s *response ); +private: + + server_t *GetServer( int server ); + + // + char m_szToken[ 1024 ]; + int m_nRequesting; + int m_nDone; + + double m_dStarted; + + request_t *m_pServerList; + request_t *m_pActiveList; + + server_t *m_pServers; + + int m_nServerCount; + + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; + + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; +}; + +#endif // HUD_SERVERS_PRIVH \ No newline at end of file diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp new file mode 100644 index 00000000..e174ca51 --- /dev/null +++ b/cl_dll/hud_spectator.cpp @@ -0,0 +1,1595 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "hltv.h" + +#include "pm_shared.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "parsemsg.h" +#include "entity_types.h" + +// these are included for the math functions +#include "com_model.h" +#include "demo_api.h" +#include "event_api.h" +#include "studio_util.h" +#include "screenfade.h" + + +#pragma warning(disable: 4244) + +extern "C" int iJumpSpectator; +extern "C" float vJumpOrigin[3]; +extern "C" float vJumpAngles[3]; + + +extern void V_GetInEyePos(int entity, float * origin, float * angles ); +extern void V_ResetChaseCam(); +extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); +extern float * GetClientColor( int clientIndex ); + +extern vec3_t v_origin; // last view origin +extern vec3_t v_angles; // last view angle +extern vec3_t v_cl_angles; // last client/mouse angle +extern vec3_t v_sim_org; // last sim origin + +void SpectatorMode(void) +{ + + + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_mode
[]\n" ); + return; + } + + // SetModes() will decide if command is executed on server or local + if ( gEngfuncs.Cmd_Argc() == 2 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), -1 ); + else if ( gEngfuncs.Cmd_Argc() == 3 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); +} + +void SpectatorSpray(void) +{ + vec3_t forward; + char string[128]; + + if ( !gEngfuncs.IsSpectateOnly() ) + return; + + AngleVectors(v_angles,forward,NULL,NULL); + VectorScale(forward, 128, forward); + VectorAdd(forward, v_origin, forward); + pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); + if ( trace->fraction != 1.0 ) + { + sprintf(string, "drc_spray %.2f %.2f %.2f %i", + trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); + gEngfuncs.pfnServerCmd(string); + } + +} +void SpectatorHelp(void) +{ + { + char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + + if ( text ) + { + while ( *text ) + { + if ( *text != 13 ) + gEngfuncs.Con_Printf( "%c", *text ); + text++; + } + } + } +} + +void SpectatorMenu( void ) +{ + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); + return; + } + +} + +void ToggleScores( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudSpectator::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + m_flNextObserverInput = 0.0f; + m_zoomDelta = 0.0f; + m_moveDelta = 0.0f; + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + iJumpSpectator = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + + gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); + gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); + gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); + gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); + gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); + + m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); + m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); + m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); + m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); + m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); + + if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip) + { + gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); + return 0; + } + + return 1; +} + + +//----------------------------------------------------------------------------- +// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed +//----------------------------------------------------------------------------- + +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++ ) + { + pVector[j] = atof( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + + if (j < 2) + { + for (j = j+1;j < 3; j++) + pVector[j] = 0; + } +} + +int UTIL_FindEntityInMap(char * name, float * origin, float * angle) +{ + int n,found = 0; + char keyname[256]; + char token[2048]; + + cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + + if ( !pEnt ) return 0; + + if ( !pEnt->model ) return 0; + + char * data = pEnt->model->entities; + + while (data) + { + data = gEngfuncs.COM_ParseFile(data, token); + + if ( (token[0] == '}') || (token[0]==0) ) + break; + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + } + + if (token[0] != '{') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); + return 0; + } + + // we parse the first { now parse entities properties + + while ( 1 ) + { + // parse key + data = gEngfuncs.COM_ParseFile(data, token); + if (token[0] == '}') + break; // finish parsing this entity + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + strcpy (keyname, token); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = gEngfuncs.COM_ParseFile(data, token); + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + if (token[0] == '}') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); + return 0; + } + + if (!strcmp(keyname,"classname")) + { + if (!strcmp(token, name )) + { + found = 1; // thats our entity + } + }; + + if( !strcmp( keyname, "angle" ) ) + { + float y = atof( token ); + + if (y >= 0) + { + angle[0] = 0.0f; + angle[1] = y; + } + else if ((int)y == -1) + { + angle[0] = -90.0f; + angle[1] = 0.0f;; + } + else + { + angle[0] = 90.0f; + angle[1] = 0.0f; + } + + angle[2] = 0.0f; + } + + if( !strcmp( keyname, "angles" ) ) + { + UTIL_StringToVector(angle, token); + } + + if (!strcmp(keyname,"origin")) + { + UTIL_StringToVector(origin, token); + + }; + + } // while (1) + + if (found) + return 1; + + } + + return 0; // we search all entities, but didn't found the correct + +} + +//----------------------------------------------------------------------------- +// SetSpectatorStartPosition(): +// Get valid map position and 'beam' spectator to this position +//----------------------------------------------------------------------------- + +void CHudSpectator::SetSpectatorStartPosition() +{ + // search for info_player start + if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else + { + // jump to 0,0,0 if no better position was found + VectorCopy(vec3_origin, m_cameraOrigin); + VectorCopy(vec3_origin, m_cameraAngles); + } + + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + + iJumpSpectator = 1; // jump anyway +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudSpectator::VidInit() +{ + m_hsprPlayer = SPR_Load("sprites/iplayer.spr"); + m_hsprPlayerBlue = SPR_Load("sprites/iplayerblue.spr"); + m_hsprPlayerRed = SPR_Load("sprites/iplayerred.spr"); + m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); + m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); + m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); + m_hsprCamera = SPR_Load("sprites/camera.spr"); + m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudSpectator::Draw(float flTime) +{ + int lx; + + char string[256]; + float * color; + + // draw only in spectator mode + if ( !g_iUser1 ) + return 0; + + // if user pressed zoom, aplly changes + if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) + { + m_mapZoom += m_zoomDelta; + + if ( m_mapZoom > 3.0f ) + m_mapZoom = 3.0f; + + if ( m_mapZoom < 0.5f ) + m_mapZoom = 0.5f; + } + + // if user moves in map mode, change map origin + if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) + { + vec3_t right; + AngleVectors(v_angles, NULL, right, NULL); + VectorNormalize(right); + VectorScale(right, m_moveDelta, right ); + + VectorAdd( m_mapOrigin, right, m_mapOrigin ) + + } + + // Only draw the icon names only if map mode is in Main Mode + if ( g_iUser1 < OBS_MAP_FREE ) + return 1; + + if ( !m_drawnames->value ) + return 1; + + // make sure we have player info + //gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + + // loop through all the players and draw additional infos to their sprites on the map + for (int i = 0; i < MAX_PLAYERS; i++) + { + + if ( m_vPlayerPos[i][2]<0 ) // marked as invisible ? + continue; + + // check if name would be in inset window + if ( m_pip->value != INSET_OFF ) + { + if ( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && + m_vPlayerPos[i][1] > YRES( m_OverviewData.insetWindowY ) && + m_vPlayerPos[i][0] < XRES( m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth ) && + m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) + ) continue; + } + + color = GetClientColor( i+1 ); + + // draw the players name and health underneath + sprintf(string, "%s", g_PlayerInfoList[i+1].name ); + + lx = strlen(string)*3; // 3 is avg. character length :) + + gEngfuncs.pfnDrawSetTextColor( color[0], color[1], color[2] ); + DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); + + } + + return 1; +} + + +void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) +{ + float value; + char * string; + + BEGIN_READ( pbuf, iSize ); + + int cmd = READ_BYTE(); + + switch ( cmd ) // director command byte + { + case DRC_CMD_START : + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + // fake a InitHUD & ResetHUD message + gHUD.MsgFunc_InitHUD(NULL,0, NULL); + gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); + + break; + + case DRC_CMD_EVENT : + m_lastPrimaryObject = READ_WORD(); + m_lastSecondaryObject = READ_WORD(); + m_iObserverFlags = READ_LONG(); + + if ( m_autoDirector->value ) + { + if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) + V_ResetChaseCam(); + + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + + // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); + break; + + case DRC_CMD_MODE : + if ( m_autoDirector->value ) + { + SetModes( READ_BYTE(), -1 ); + } + break; + + case DRC_CMD_CAMERA : + if ( m_autoDirector->value ) + { + vJumpOrigin[0] = READ_COORD(); // position + vJumpOrigin[1] = READ_COORD(); + vJumpOrigin[2] = READ_COORD(); + + vJumpAngles[0] = READ_COORD(); // view angle + vJumpAngles[1] = READ_COORD(); + vJumpAngles[2] = READ_COORD(); + + gEngfuncs.SetViewAngles( vJumpAngles ); + + iJumpSpectator = 1; + } + break; + + case DRC_CMD_MESSAGE: + { + client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + + msg->effect = READ_BYTE(); // effect + + UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color + msg->r2 = msg->r1; + msg->g2 = msg->g1; + msg->b2 = msg->b1; + msg->a2 = msg->a1 = 0xFF; // not transparent + + msg->x = READ_FLOAT(); // x pos + msg->y = READ_FLOAT(); // y pos + + msg->fadein = READ_FLOAT(); // fadein + msg->fadeout = READ_FLOAT(); // fadeout + msg->holdtime = READ_FLOAT(); // holdtime + msg->fxtime = READ_FLOAT(); // fxtime; + + strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); + m_HUDMessageText[m_lastHudMessage][127]=0; // text + + msg->pMessage = m_HUDMessageText[m_lastHudMessage]; + msg->pName = "HUD_MESSAGE"; + + gHUD.m_Message.MessageAdd( msg ); + + m_lastHudMessage++; + m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; + + } + + break; + + case DRC_CMD_SOUND : + string = READ_STRING(); + value = READ_FLOAT(); + + // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); + gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + + break; + + case DRC_CMD_TIMESCALE : + value = READ_FLOAT(); + break; + + + + case DRC_CMD_STATUS: + READ_LONG(); // total number of spectator slots + m_iSpectatorNumber = READ_LONG(); // total number of spectator + READ_WORD(); // total number of relay proxies + + break; + + case DRC_CMD_BANNER: + // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga + break; + + case DRC_CMD_FADE: + break; + + case DRC_CMD_STUFFTEXT: + ClientCmd( READ_STRING() ); + break; + + default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + } +} + +void CHudSpectator::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; + cl_entity_t * pEnt = NULL; + + // if we are NOT in HLTV mode, spectator targets are set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + char cmdstring[32]; + // forward command to server + sprintf(cmdstring,"follownext %i",bReverse?1:0); + gEngfuncs.pfnServerCmd(cmdstring); + return; + } + + if ( g_iUser2 ) + iStart = g_iUser2; + else + iStart = 1; + + g_iUser2 = 0; + + int iCurrent = iStart; + + int iDir = bReverse ? -1 : 1; + + // make sure we have player info + //gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > MAX_PLAYERS) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = MAX_PLAYERS; + + pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); + + if ( !IsActivePlayer( pEnt ) ) + continue; + + // MOD AUTHORS: Add checks on target here. + + g_iUser2 = iCurrent; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( !g_iUser2 ) + { + gEngfuncs.Con_DPrintf( "No observer targets.\n" ); + // take save camera position + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + } + else + { + // use new entity position for roaming + VectorCopy ( pEnt->origin, vJumpOrigin ); + VectorCopy ( pEnt->angles, vJumpAngles ); + } + iJumpSpectator = 1; +} + +void CHudSpectator::HandleButtonsDown( int ButtonPressed ) +{ + double time = gEngfuncs.GetClientTime(); + + int newMainMode = g_iUser1; + int newInsetMode = m_pip->value; + + // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + + //Not in intermission. + if ( gHUD.m_iIntermission ) + return; + + if ( !g_iUser1 ) + return; // dont do anything if not in spectator mode + + // don't handle buttons during normal demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + return; + // Slow down mouse clicks. + if ( m_flNextObserverInput > time ) + return; + + // enable spectator screen + //if ( ButtonPressed & IN_DUCK ) + // gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); + + // 'Use' changes inset window mode + if ( ButtonPressed & IN_USE ) + { + newInsetMode = ToggleInset(true); + } + + // if not in HLTV mode, buttons are handled server side + if ( gEngfuncs.IsSpectateOnly() ) + { + // changing target or chase mode not in overviewmode without inset window + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + if ( g_iUser1 == OBS_CHASE_LOCKED ) + newMainMode = OBS_CHASE_FREE; + + else if ( g_iUser1 == OBS_CHASE_FREE ) + newMainMode = OBS_IN_EYE; + + else if ( g_iUser1 == OBS_IN_EYE ) + newMainMode = OBS_ROAMING; + + else if ( g_iUser1 == OBS_ROAMING ) + newMainMode = OBS_MAP_FREE; + + else if ( g_iUser1 == OBS_MAP_FREE ) + newMainMode = OBS_MAP_CHASE; + + else + newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore + } + + // Attack moves to the next player + if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + { + FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + + if ( g_iUser1 == OBS_ROAMING ) + { + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + + } + // lease directed mode if player want to see another player + m_autoDirector->value = 0.0f; + } + } + + SetModes(newMainMode, newInsetMode); + + if ( g_iUser1 == OBS_MAP_FREE ) + { + if ( ButtonPressed & IN_FORWARD ) + m_zoomDelta = 0.01f; + + if ( ButtonPressed & IN_BACK ) + m_zoomDelta = -0.01f; + + if ( ButtonPressed & IN_MOVELEFT ) + m_moveDelta = -12.0f; + + if ( ButtonPressed & IN_MOVERIGHT ) + m_moveDelta = 12.0f; + } + + m_flNextObserverInput = time + 0.2; +} + +void CHudSpectator::HandleButtonsUp( int ButtonPressed ) +{ + + if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) + m_zoomDelta = 0.0f; + + if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + m_moveDelta = 0.0f; +} + +void CHudSpectator::SetModes(int iNewMainMode, int iNewInsetMode) +{ + // if value == -1 keep old value + if ( iNewMainMode == -1 ) + iNewMainMode = g_iUser1; + + if ( iNewInsetMode == -1 ) + iNewInsetMode = m_pip->value; + + // inset mode is handled only clients side + m_pip->value = iNewInsetMode; + + if ( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) + { + gEngfuncs.Con_Printf("Invalid spectator mode.\n"); + return; + } + + // main modes ettings will override inset window settings + if ( iNewMainMode != g_iUser1 ) + { + // if we are NOT in HLTV mode, main spectator mode is set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + return; + } + + if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + { + // choose last Director object if still available + if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + { + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + else + FindNextPlayer(false); // find any target + } + + switch ( iNewMainMode ) + { + case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; + break; + + case OBS_CHASE_FREE : g_iUser1 = OBS_CHASE_FREE; + break; + + case OBS_ROAMING : // jump to current vJumpOrigin/angle + g_iUser1 = OBS_ROAMING; + if ( g_iUser2 ) + { + V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; + + case OBS_IN_EYE : g_iUser1 = OBS_IN_EYE; + break; + + case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + + case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + } + + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + char string[128]; + sprintf(string, "#Spec_Mode%d", g_iUser1 ); + sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + +} + +bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) +{ + return ( ent && + ent->player && + ent->curstate.solid != SOLID_NOT && + ent != gEngfuncs.GetLocalPlayer() && + g_PlayerInfoList[ent->index].name != NULL + ); +} + + +bool CHudSpectator::ParseOverviewFile( ) +{ + char filename[255]; + char levelname[255]; + char token[1024]; + float height; + + char *pfile = NULL; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + + // fill in standrd values + m_OverviewData.insetWindowX = 4; // upper left corner + m_OverviewData.insetWindowY = 4; + m_OverviewData.insetWindowHeight = 180; + m_OverviewData.insetWindowWidth = 240; + m_OverviewData.origin[0] = 0.0f; + m_OverviewData.origin[1] = 0.0f; + m_OverviewData.origin[2] = 0.0f; + m_OverviewData.zoom = 1.0f; + m_OverviewData.layers = 0; + m_OverviewData.layersHeights[0] = 0.0f; + strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); + + if ( strlen( m_OverviewData.map ) == 0 ) + return false; // not active yet + + strcpy(levelname, m_OverviewData.map + 5); + levelname[strlen(levelname)-4] = 0; + + sprintf(filename, "overviews/%s.txt", levelname ); + + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + + if (!pfile) + { + gEngfuncs.Con_DPrintf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + return false; + } + + + while (true) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if (!pfile) + break; + + if ( !stricmp( token, "global" ) ) + { + // parse the global data + pfile = gEngfuncs.COM_ParseFile(pfile, token); + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "zoom" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.zoom = atof( token ); + } + else if ( !stricmp( token, "origin" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[0] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.origin[1] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[2] = atof( token ); + } + else if ( !stricmp( token, "rotated" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.rotated = atoi( token ); + } + else if ( !stricmp( token, "inset" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowX = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowY = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowWidth = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowHeight = atof( token ); + + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + + } + } + else if ( !stricmp( token, "layer" ) ) + { + // parse a layer data + + if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "image" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); + + + } + else if ( !stricmp( token, "height" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + height = atof(token); + m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + } + + m_OverviewData.layers++; + + } + } + + gEngfuncs.COM_FreeFile( pfile ); + + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + + return true; + +} + +void CHudSpectator::LoadMapSprites() +{ + // right now only support for one map layer + if (m_OverviewData.layers > 0 ) + { + m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); + } + else + m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead +} + +void CHudSpectator::DrawOverviewLayer() +{ + float screenaspect, xs, ys, xStep, yStep, x,y,z; + int ix,iy,i,xTiles,yTiles,frame; + + qboolean hasMapImage = m_MapSprite?TRUE:FALSE; + model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); + + if ( hasMapImage) + { + i = m_MapSprite->numframes / (4*3); + i = sqrt(i); + xTiles = i*4; + yTiles = i*3; + } + else + { + xTiles = 8; + yTiles = 6; + } + + + screenaspect = 4.0f/3.0f; + + + xs = m_OverviewData.origin[0]; + ys = m_OverviewData.origin[1]; + z = ( 90.0f - v_angles[0] ) / 90.0f; + z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; + + // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); + + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + frame = 0; + + + // rotated view ? + if ( m_OverviewData.rotated ) + { + xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); + + for (iy = 0; iy < yTiles; iy++) + { + x = xs - (4096.0f / (m_OverviewData.zoom)); + + for (ix = 0; ix < xTiles; ix++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + x+= xStep; + } + + y+=yStep; + } + } + else + { + xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + + x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); + + + + for (ix = 0; ix < yTiles; ix++) + { + + y = ys + (4096.0f / (m_OverviewData.zoom)); + + for (iy = 0; iy < xTiles; iy++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + + y+=yStep; + } + + x+= xStep; + + } + } +} + +void CHudSpectator::DrawOverviewEntities() +{ + int i,ir,ig,ib; + struct model_s *hSpriteModel; + vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; + float x,y,z, r,g,b, sizeScale = 4.0f; + cl_entity_t * ent; + float rmatrix[3][4]; // transformation matrix + + float zScale = (90.0f - v_angles[0] ) / 90.0f; + + + z = m_OverviewData.layersHeights[0] * zScale; + // get yellow/brown HUD color + UnpackRGB(ir,ig,ib, RGB_YELLOWISH); + r = (float)ir/255.0f; + g = (float)ig/255.0f; + b = (float)ib/255.0f; + + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + + for (i=0; i < MAX_PLAYERS; i++ ) + m_vPlayerPos[i][2] = -1; // mark as invisible + + // draw all players + for (i=0 ; i < MAX_OVERVIEW_ENTITIES ; i++) + { + if ( !m_OverviewEntities[i].hSprite ) + continue; + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); + ent = m_OverviewEntities[i].entity; + + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + + // see R_DrawSpriteModel + // draws players sprite + + AngleVectors(ent->angles, right, up, NULL ); + + VectorCopy(ent->origin,origin); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (1,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->End (); + + + if ( !ent->player) + continue; + // draw line under player icons + origin[2] *= zScale; + + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + // calculate screen position for name and infromation in hud::draw() + if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) + continue; // object is behind viewer + + screen[0] = XPROJECT(screen[0]); + screen[1] = YPROJECT(screen[1]); + screen[2] = 0.0f; + + // calculate some offset under the icon + origin[0]+=32.0f; + origin[1]+=32.0f; + + gEngfuncs.pTriAPI->WorldToScreen(origin,offset); + + offset[0] = XPROJECT(offset[0]); + offset[1] = YPROJECT(offset[1]); + offset[2] = 0.0f; + + VectorSubtract(offset, screen, offset ); + + int playerNum = ent->index - 1; + + m_vPlayerPos[playerNum][0] = screen[0]; + m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); + m_vPlayerPos[playerNum][2] = 1; // mark player as visible + } + + if ( !m_pip->value || !m_drawcone->value ) + return; + + // get current camera position and angle + + if ( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) + { + V_GetInEyePos( g_iUser2, origin, angles ); + } + else if ( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) + { + V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); + } + else if ( g_iUser1 == OBS_ROAMING ) + { + VectorCopy( v_sim_org, origin ); + VectorCopy( v_cl_angles, angles ); + } + else + V_GetChasePos( g_iUser2, NULL, origin, angles ); + + + // draw camera sprite + + x = origin[0]; + y = origin[1]; + z = origin[2]; + + angles[0] = 0; // always show horizontal camera sprite + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + + gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); + + AngleVectors(angles, forward, NULL, NULL ); + VectorScale (forward, 512.0f, forward); + + offset[0] = 0.0f; + offset[1] = 45.0f; + offset[2] = 0.0f; + + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , right ); + + offset[1]= -45.0f; + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , left ); + + gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); + gEngfuncs.pTriAPI->End (); + +} + + + +void CHudSpectator::DrawOverview() +{ + // draw only in sepctator mode + if ( !g_iUser1 ) + return; + + // Only draw the overview if Map Mode is selected for this view + if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) + return; + + if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) + return; + + DrawOverviewLayer(); + DrawOverviewEntities(); + CheckOverviewEntities(); +} +void CHudSpectator::CheckOverviewEntities() +{ + double time = gEngfuncs.GetClientTime(); + + // removes old entities from list + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // remove entity from list if it is too old + if ( m_OverviewEntities[i].killTime < time ) + { + memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); + } + } +} + +bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) +{ + HSPRITE hSprite = 0; + double duration = -1.0f; // duration -1 means show it only this frame; + + if ( !ent ) + return false; + + if ( type == ET_PLAYER ) + { + if ( ent->curstate.solid != SOLID_NOT) + { + switch ( g_PlayerExtraInfo[ent->index].teamnumber ) + { + // blue and red teams are swapped in CS and TFC + case 1 : hSprite = m_hsprPlayerBlue; break; + case 2 : hSprite = m_hsprPlayerRed; break; + default : hSprite = m_hsprPlayer; break; + } + } + else + return false; // it's an spectator + } + else if (type == ET_NORMAL) + { + return false; + } + else + return false; + + return AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration ); +} + +void CHudSpectator::DeathMessage(int victim) +{ + // find out where the victim is + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); + + if (pl && pl->player) + AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); +} + +bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) +{ + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // find empty entity slot + if ( m_OverviewEntities[i].entity == NULL) + { + m_OverviewEntities[i].entity = ent; + m_OverviewEntities[i].hSprite = sprite; + m_OverviewEntities[i].killTime = killTime; + return true; + } + } + + return false; // maximum overview entities reached +} +void CHudSpectator::CheckSettings() +{ + // disallow same inset mode as main mode: + + m_pip->value = (int)m_pip->value; + + if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) + { + // otherwise both would show in World picures + m_pip->value = INSET_MAP_FREE; + } + + if ( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) + { + // both would show map views + m_pip->value = INSET_CHASE_FREE; + } + + // disble in intermission screen + if ( gHUD.m_iIntermission ) + m_pip->value = INSET_OFF; + + // check chat mode + if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) + { + // hud_saytext changed + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // tell proxy our new chat mode + char chatcmd[32]; + sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); + gEngfuncs.pfnServerCmd(chatcmd); + } + } + + // HL/TFC has no oberserver corsshair, so set it client side + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + + + // if we are a real player on server don't allow inset window + // in First Person mode since this is our resticted forcecamera mode 2 + // team number 3 = SPECTATOR see player.h + + if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) + m_pip->value = INSET_OFF; + + // draw small border around inset view, adjust upper black bar +} + +int CHudSpectator::ToggleInset(bool allowOff) +{ + int newInsetMode = (int)m_pip->value + 1; + + if ( g_iUser1 < OBS_MAP_FREE ) + { + if ( newInsetMode > INSET_MAP_CHASE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_MAP_FREE; + } + + if ( newInsetMode == INSET_CHASE_FREE ) + newInsetMode = INSET_MAP_FREE; + } + else + { + if ( newInsetMode > INSET_IN_EYE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_CHASE_FREE; + } + } + + return newInsetMode; +} +void CHudSpectator::Reset() +{ + // Reset HUD + if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) + { + // update level overview if level changed + ParseOverviewFile(); + LoadMapSprites(); + } + + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + SetSpectatorStartPosition(); +} + +void CHudSpectator::InitHUDData() +{ + m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + m_lastHudMessage = 0; + m_iSpectatorNumber = 0; + iJumpSpectator = 0; + g_iUser1 = g_iUser2 = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) + m_autoDirector->value = 1.0f; + else + m_autoDirector->value = 0.0f; + + Reset(); + + SetModes( OBS_CHASE_FREE, INSET_OFF ); + + g_iUser2 = 0; // fake not target until first camera command + + // reset HUD FOV + gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); +} + diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h new file mode 100644 index 00000000..7f1a3610 --- /dev/null +++ b/cl_dll/hud_spectator.h @@ -0,0 +1,132 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SPECTATOR_H +#define SPECTATOR_H +#pragma once + +#include "cl_entity.h" + + + +#define INSET_OFF 0 +#define INSET_CHASE_FREE 1 +#define INSET_IN_EYE 2 +#define INSET_MAP_FREE 3 +#define INSET_MAP_CHASE 4 + +#define MAX_SPEC_HUD_MESSAGES 8 + + + +#define OVERVIEW_TILE_SIZE 128 // don't change this +#define OVERVIEW_MAX_LAYERS 1 + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) +//----------------------------------------------------------------------------- + +typedef struct overviewInfo_s { + char map[64]; // cl.levelname or empty + vec3_t origin; // center of map + float zoom; // zoom of map images + int layers; // how may layers do we have + float layersHeights[OVERVIEW_MAX_LAYERS]; + char layersImages[OVERVIEW_MAX_LAYERS][255]; + qboolean rotated; // are map images rotated (90 degrees) ? + + int insetWindowX; + int insetWindowY; + int insetWindowHeight; + int insetWindowWidth; +} overviewInfo_t; + +typedef struct overviewEntity_s { + + HSPRITE hSprite; + struct cl_entity_s * entity; + double killTime; +} overviewEntity_t; + +#define MAX_OVERVIEW_ENTITIES 128 + +class CHudSpectator : public CHudBase +{ +public: + void Reset(); + int ToggleInset(bool allowOff); + void CheckSettings(); + void InitHUDData( void ); + bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime); + void DeathMessage(int victim); + bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void CheckOverviewEntities(); + void DrawOverview(); + void DrawOverviewEntities(); + void GetMapPosition( float * returnvec ); + void DrawOverviewLayer(); + void LoadMapSprites(); + bool ParseOverviewFile(); + bool IsActivePlayer(cl_entity_t * ent); + void SetModes(int iMainMode, int iInsetMode); + void HandleButtonsDown(int ButtonPressed); + void HandleButtonsUp(int ButtonPressed); + void FindNextPlayer( bool bReverse ); + void DirectorMessage( int iSize, void *pbuf ); + void SetSpectatorStartPosition(); + int Init(); + int VidInit(); + + int Draw(float flTime); + + int m_iDrawCycle; + client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; + char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; + int m_lastHudMessage; + overviewInfo_t m_OverviewData; + overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; + int m_iObserverFlags; + int m_iSpectatorNumber; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + cvar_t * m_drawnames; + cvar_t * m_drawcone; + cvar_t * m_drawstatus; + cvar_t * m_autoDirector; + cvar_t * m_pip; + + + qboolean m_chatEnabled; + + vec3_t m_cameraOrigin; // a help camera + vec3_t m_cameraAngles; // and it's angles + + +private: + vec3_t m_vPlayerPos[MAX_PLAYERS]; + HSPRITE m_hsprPlayerBlue; + HSPRITE m_hsprPlayerRed; + HSPRITE m_hsprPlayer; + HSPRITE m_hsprCamera; + HSPRITE m_hsprPlayerDead; + HSPRITE m_hsprViewcone; + HSPRITE m_hsprUnkownMap; + HSPRITE m_hsprBeam; + HSPRITE m_hCrosshair; + + wrect_t m_crosshairRect; + + struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame + float m_flNextObserverInput; + float m_zoomDelta; + float m_moveDelta; + int m_lastPrimaryObject; + int m_lastSecondaryObject; +}; + +#endif // SPECTATOR_H diff --git a/cl_dll/hud_update.cpp b/cl_dll/hud_update.cpp new file mode 100644 index 00000000..b3da6721 --- /dev/null +++ b/cl_dll/hud_update.cpp @@ -0,0 +1,54 @@ +/*** +* +* 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. +* +****/ +// +// hud_update.cpp +// + +#include +#include "hud.h" +#include "cl_util.h" +#include +#include + +int CL_ButtonBits( int ); +void CL_ResetButtonBits( int bits ); + +extern float v_idlescale; +float in_fov; +extern void HUD_SetCmdBits( int bits ); + +int CHud::UpdateClientData(client_data_t *cdata, float time) +{ + memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); + memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); + + m_iKeyBits = CL_ButtonBits( 0 ); + m_iWeaponBits = cdata->iWeaponBits; + + in_fov = cdata->fov; + + Think(); + + cdata->fov = m_iFOV; + + v_idlescale = m_iConcussionEffect; + + CL_ResetButtonBits( m_iKeyBits ); + + // return 1 if in anything in the client_data struct has been changed, 0 otherwise + return 1; +} + + diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp new file mode 100644 index 00000000..26551864 --- /dev/null +++ b/cl_dll/in_camera.cpp @@ -0,0 +1,620 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" + + +float CL_KeyState (kbutton_t *key); + +extern "C" +{ + void DLLEXPORT CAM_Think( void ); + int DLLEXPORT CL_IsThirdPerson( void ); + void DLLEXPORT CL_CameraOffset( float *ofs ); +} + +extern cl_enginefunc_t gEngfuncs; + +//-------------------------------------------------- Constants + +#define CAM_DIST_DELTA 1.0 +#define CAM_ANGLE_DELTA 2.5 +#define CAM_ANGLE_SPEED 2.5 +#define CAM_MIN_DIST 30.0 +#define CAM_ANGLE_MOVE .5 +#define MAX_ANGLE_DIFF 10.0 +#define PITCH_MAX 90.0 +#define PITCH_MIN 0 +#define YAW_MAX 135.0 +#define YAW_MIN -135.0 + +enum ECAM_Command +{ + CAM_COMMAND_NONE = 0, + CAM_COMMAND_TOTHIRDPERSON = 1, + CAM_COMMAND_TOFIRSTPERSON = 2 +}; + +//-------------------------------------------------- Global Variables + +cvar_t *cam_command; +cvar_t *cam_snapto; +cvar_t *cam_idealyaw; +cvar_t *cam_idealpitch; +cvar_t *cam_idealdist; +cvar_t *cam_contain; + +cvar_t *c_maxpitch; +cvar_t *c_minpitch; +cvar_t *c_maxyaw; +cvar_t *c_minyaw; +cvar_t *c_maxdistance; +cvar_t *c_mindistance; + +// pitch, yaw, dist +vec3_t cam_ofs; + + +// In third person +int cam_thirdperson; +int cam_mousemove; //true if we are moving the cam with the mouse, False if not +int iMouseInUse=0; +int cam_distancemove; +extern int mouse_x, mouse_y; //used to determine what the current x and y values are +int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement +POINT cam_mouse; +//-------------------------------------------------- Local Variables + +static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; +static kbutton_t cam_in, cam_out, cam_move; + +//-------------------------------------------------- Prototypes + +void CAM_ToThirdPerson(void); +void CAM_ToFirstPerson(void); +void CAM_StartDistance(void); +void CAM_EndDistance(void); + + +//-------------------------------------------------- Local Functions + +float MoveToward( float cur, float goal, float maxspeed ) +{ + if( cur != goal ) + { + if( abs( cur - goal ) > 180.0 ) + { + if( cur < goal ) + cur += 360.0; + else + cur -= 360.0; + } + + if( cur < goal ) + { + if( cur < goal - 1.0 ) + cur += ( goal - cur ) / 4.0; + else + cur = goal; + } + else + { + if( cur > goal + 1.0 ) + cur -= ( cur - goal ) / 4.0; + else + cur = goal; + } + } + + + // bring cur back into range + if( cur < 0 ) + cur += 360.0; + else if( cur >= 360 ) + cur -= 360; + + return cur; +} + + +//-------------------------------------------------- Gobal Functions + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; + qboolean monsterclip; +} moveclip_t; + +extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + +void DLLEXPORT CAM_Think( void ) +{ + vec3_t origin; + vec3_t ext, pnt, camForward, camRight, camUp; + moveclip_t clip; + float dist; + vec3_t camAngles; + float flSensitivity; +#ifdef LATER + int i; +#endif + vec3_t viewangles; + + switch( (int) cam_command->value ) + { + case CAM_COMMAND_TOTHIRDPERSON: + CAM_ToThirdPerson(); + break; + + case CAM_COMMAND_TOFIRSTPERSON: + CAM_ToFirstPerson(); + break; + + case CAM_COMMAND_NONE: + default: + break; + } + + if( !cam_thirdperson ) + return; + +#ifdef LATER + if ( cam_contain->value ) + { + gEngfuncs.GetClientOrigin( origin ); + ext[0] = ext[1] = ext[2] = 0.0; + } +#endif + + camAngles[ PITCH ] = cam_idealpitch->value; + camAngles[ YAW ] = cam_idealyaw->value; + dist = cam_idealdist->value; + // + //movement of the camera with the mouse + // + if (cam_mousemove) + { + //get windows cursor position + GetCursorPos (&cam_mouse); + //check for X delta values and adjust accordingly + //eventually adjust YAW based on amount of movement + //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera + if (!cam_distancemove) + { + + //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) + if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) + { + //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) + if (camAngles[YAW]value) + { + camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); + } + if (camAngles[YAW]>c_maxyaw->value) + { + + camAngles[YAW]=c_maxyaw->value; + } + } + else if (cam_mouse.x225.0)) + if (camAngles[YAW]>c_minyaw->value) + { + camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); + + } + if (camAngles[YAW]value) + { + camAngles[YAW]=c_minyaw->value; + + } + } + + //check for y delta values and adjust accordingly + //eventually adjust PITCH based on amount of movement + //also make sure camera is within bounds + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(camAngles[PITCH]value) + { + camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (camAngles[PITCH]>c_maxpitch->value) + { + camAngles[PITCH]=c_maxpitch->value; + } + } + else if (cam_mouse.yc_minpitch->value) + { + camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (camAngles[PITCH]value) + { + camAngles[PITCH]=c_minpitch->value; + } + } + + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } + } + + //Nathan code here + if( CL_KeyState( &cam_pitchup ) ) + camAngles[ PITCH ] += CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_pitchdown ) ) + camAngles[ PITCH ] -= CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_yawleft ) ) + camAngles[ YAW ] -= CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_yawright ) ) + camAngles[ YAW ] += CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_in ) ) + { + dist -= CAM_DIST_DELTA; + if( dist < CAM_MIN_DIST ) + { + // If we go back into first person, reset the angle + camAngles[ PITCH ] = 0; + camAngles[ YAW ] = 0; + dist = CAM_MIN_DIST; + } + + } + else if( CL_KeyState( &cam_out ) ) + dist += CAM_DIST_DELTA; + + if (cam_distancemove) + { + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(distvalue) + { + dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (dist>c_maxdistance->value) + { + dist=c_maxdistance->value; + } + } + else if (cam_mouse.yc_mindistance->value) + { + dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (distvalue) + { + dist=c_mindistance->value; + } + } + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } +#ifdef LATER + if( cam_contain->value ) + { + // check new ideal + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction == 1.0 ) + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + } + else +#endif + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + + // Move towards ideal + VectorCopy( cam_ofs, camAngles ); + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( cam_snapto->value ) + { + camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; + camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; + camAngles[ 2 ] = cam_idealdist->value; + } + else + { + if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) + camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); + + if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) + camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); + + if( abs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) + camAngles[ 2 ] = cam_idealdist->value; + else + camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; + } +#ifdef LATER + if( cam_contain->value ) + { + // Test new position + dist = camAngles[ ROLL ]; + camAngles[ ROLL ] = 0; + + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + ext[0] = ext[1] = ext[2] = 0.0; + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction != 1.0 ) + return; + } +#endif + cam_ofs[ 0 ] = camAngles[ 0 ]; + cam_ofs[ 1 ] = camAngles[ 1 ]; + cam_ofs[ 2 ] = dist; +} + +extern void KeyDown (kbutton_t *b); // HACK +extern void KeyUp (kbutton_t *b); // HACK + +void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } +void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } +void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } +void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } +void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } +void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } +void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } +void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } +void CAM_InDown(void) { KeyDown( &cam_in ); } +void CAM_InUp(void) { KeyUp( &cam_in ); } +void CAM_OutDown(void) { KeyDown( &cam_out ); } +void CAM_OutUp(void) { KeyUp( &cam_out ); } + +void CAM_ToThirdPerson(void) +{ + vec3_t viewangles; + +#if !defined( _DEBUG ) + if ( gEngfuncs.GetMaxClients() > 1 ) + { + // no thirdperson in multiplayer. + return; + } +#endif + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( !cam_thirdperson ) + { + cam_thirdperson = 1; + + cam_ofs[ YAW ] = viewangles[ YAW ]; + cam_ofs[ PITCH ] = viewangles[ PITCH ]; + cam_ofs[ 2 ] = CAM_MIN_DIST; + } + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToFirstPerson(void) +{ + cam_thirdperson = 0; + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToggleSnapto( void ) +{ + cam_snapto->value = !cam_snapto->value; +} + +void CAM_Init( void ) +{ + gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown ); + gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp ); + gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown ); + gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp ); + gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown ); + gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp ); + gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown ); + gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp ); + gEngfuncs.pfnAddCommand( "+camin", CAM_InDown ); + gEngfuncs.pfnAddCommand( "-camin", CAM_InUp ); + gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown ); + gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp ); + gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson ); + gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson ); + gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove); + gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove); + gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance ); + gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); + gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); + + cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson + cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view + cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw + cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch + cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance + cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world + + c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); + c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); + c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); + c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); + c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); + c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); +} + +void CAM_ClearStates( void ) +{ + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + cam_pitchup.state = 0; + cam_pitchdown.state = 0; + cam_yawleft.state = 0; + cam_yawright.state = 0; + cam_in.state = 0; + cam_out.state = 0; + + cam_thirdperson = 0; + cam_command->value = 0; + cam_mousemove=0; + + cam_snapto->value = 0; + cam_distancemove = 0; + + cam_ofs[ 0 ] = 0.0; + cam_ofs[ 1 ] = 0.0; + cam_ofs[ 2 ] = CAM_MIN_DIST; + + cam_idealpitch->value = viewangles[ PITCH ]; + cam_idealyaw->value = viewangles[ YAW ]; + cam_idealdist->value = CAM_MIN_DIST; +} + +void CAM_StartMouseMove(void) +{ + float flSensitivity; + + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_mousemove) + { + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndMouseMove(void) +{ + cam_mousemove=0; + iMouseInUse=0; +} + + +//---------------------------------------------------------- +//routines to start the process of moving the cam in or out +//using the mouse +//---------------------------------------------------------- +void CAM_StartDistance(void) +{ + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_distancemove) + { + cam_distancemove=1; + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndDistance(void) +{ + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; +} + +int DLLEXPORT CL_IsThirdPerson( void ) +{ + return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) ); +} + +void DLLEXPORT CL_CameraOffset( float *ofs ) +{ + VectorCopy( cam_ofs, ofs ); +} \ No newline at end of file diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h new file mode 100644 index 00000000..b78ffa9e --- /dev/null +++ b/cl_dll/in_defs.h @@ -0,0 +1,31 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( IN_DEFSH ) +#define IN_DEFSH +#pragma once + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +typedef struct point_s{ + int x; + int y; +} POINT; +#define GetCursorPos(x) +#define SetCursorPos(x,y) +#endif + +#endif diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp new file mode 100644 index 00000000..bb4ecbf3 --- /dev/null +++ b/cl_dll/input.cpp @@ -0,0 +1,1006 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// cl.input.c -- builds an intended movement command to send to the server + +//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +extern "C" +{ +#include "kbutton.h" +} +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "view.h" +#include +#include + + + +extern "C" +{ + struct kbutton_s DLLEXPORT *KB_Find( const char *name ); + void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); + void DLLEXPORT HUD_Shutdown( void ); + int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); +} + +extern int g_iAlive; + +extern int g_weaponselect; +extern cl_enginefunc_t gEngfuncs; + +// Defined in pm_math.c +extern "C" float anglemod( float a ); + +void IN_Init (void); +void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Shutdown( void ); +void V_Init( void ); +void VectorAngles( const float *forward, float *angles ); +int CL_ButtonBits( int ); + +// xxx need client dll function to get and clear impuse +extern cvar_t *in_joystick; + +int in_impulse = 0; +int in_cancel = 0; + +cvar_t *m_pitch; +cvar_t *m_yaw; +cvar_t *m_forward; +cvar_t *m_side; + +cvar_t *lookstrafe; +cvar_t *lookspring; +cvar_t *cl_pitchup; +cvar_t *cl_pitchdown; +cvar_t *cl_upspeed; +cvar_t *cl_forwardspeed; +cvar_t *cl_backspeed; +cvar_t *cl_sidespeed; +cvar_t *cl_movespeedkey; +cvar_t *cl_yawspeed; +cvar_t *cl_pitchspeed; +cvar_t *cl_anglespeedkey; +cvar_t *cl_vsmoothing; +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook; +kbutton_t in_klook; +kbutton_t in_jlook; +kbutton_t in_left; +kbutton_t in_right; +kbutton_t in_forward; +kbutton_t in_back; +kbutton_t in_lookup; +kbutton_t in_lookdown; +kbutton_t in_moveleft; +kbutton_t in_moveright; +kbutton_t in_strafe; +kbutton_t in_speed; +kbutton_t in_use; +kbutton_t in_jump; +kbutton_t in_attack; +kbutton_t in_attack2; +kbutton_t in_up; +kbutton_t in_down; +kbutton_t in_duck; +kbutton_t in_reload; +kbutton_t in_alt1; +kbutton_t in_score; +kbutton_t in_break; +kbutton_t in_graph; // Display the netgraph + +typedef struct kblist_s +{ + struct kblist_s *next; + kbutton_t *pkey; + char name[32]; +} kblist_t; + +kblist_t *g_kbkeys = NULL; + +/* +============ +KB_ConvertString + +Removes references to +use and replaces them with the keyname in the output string. If + a binding is unfound, then the original text is retained. +NOTE: Only works for text with +word in it. +============ +*/ +int KB_ConvertString( char *in, char **ppout ) +{ + char sz[ 4096 ]; + char binding[ 64 ]; + char *p; + char *pOut; + char *pEnd; + const char *pBinding; + + if ( !ppout ) + return 0; + + *ppout = NULL; + p = in; + pOut = sz; + while ( *p ) + { + if ( *p == '+' ) + { + pEnd = binding; + while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + { + *pEnd++ = *p++; + } + + *pEnd = '\0'; + + pBinding = NULL; + if ( strlen( binding + 1 ) > 0 ) + { + // See if there is a binding for binding? + pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); + } + + if ( pBinding ) + { + *pOut++ = '['; + pEnd = (char *)pBinding; + } + else + { + pEnd = binding; + } + + while ( *pEnd ) + { + *pOut++ = *pEnd++; + } + + if ( pBinding ) + { + *pOut++ = ']'; + } + } + else + { + *pOut++ = *p++; + } + } + + *pOut = '\0'; + + pOut = ( char * )malloc( strlen( sz ) + 1 ); + strcpy( pOut, sz ); + *ppout = pOut; + + return 1; +} + +/* +============ +KB_Find + +Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files +============ +*/ +struct kbutton_s DLLEXPORT *KB_Find( const char *name ) +{ + kblist_t *p; + p = g_kbkeys; + while ( p ) + { + if ( !stricmp( name, p->name ) ) + return p->pkey; + + p = p->next; + } + return NULL; +} + +/* +============ +KB_Add + +Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find +============ +*/ +void KB_Add( const char *name, kbutton_t *pkb ) +{ + kblist_t *p; + kbutton_t *kb; + + kb = KB_Find( name ); + + if ( kb ) + return; + + p = ( kblist_t * )malloc( sizeof( kblist_t ) ); + memset( p, 0, sizeof( *p ) ); + + strcpy( p->name, name ); + p->pkey = pkb; + + p->next = g_kbkeys; + g_kbkeys = p; +} + +/* +============ +KB_Init + +Add kbutton_t definitions that the engine can query if needed +============ +*/ +void KB_Init( void ) +{ + g_kbkeys = NULL; + + KB_Add( "in_graph", &in_graph ); + KB_Add( "in_mlook", &in_mlook ); + KB_Add( "in_jlook", &in_jlook ); +} + +/* +============ +KB_Shutdown + +Clear kblist +============ +*/ +void KB_Shutdown( void ) +{ + kblist_t *p, *n; + p = g_kbkeys; + while ( p ) + { + n = p->next; + free( p ); + p = n; + } + g_kbkeys = NULL; +} + +/* +============ +KeyDown +============ +*/ +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyUp +============ +*/ +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + { + //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + return; // some other key is still holding it down + } + + if (!(b->state & 1)) + return; // still up (this should not happen) + + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +/* +============ +HUD_Key_Event + +Return 1 to allow engine to process the key, otherwise, act on it as needed +============ +*/ +int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) +{ + + return 1; +} + +void IN_BreakDown( void ) { KeyDown( &in_break );}; +void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_JLookDown (void) {KeyDown(&in_jlook);} +void IN_JLookUp (void) {KeyUp(&in_jlook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} + +void IN_ForwardDown(void) +{ + KeyDown(&in_forward); + gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); +} + +void IN_ForwardUp(void) +{ + KeyUp(&in_forward); + gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); +} + +void IN_BackDown(void) +{ + KeyDown(&in_back); + gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); +} + +void IN_BackUp(void) +{ + KeyUp(&in_back); + gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); +} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) +{ + KeyDown(&in_moveleft); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); +} + +void IN_MoveleftUp(void) +{ + KeyUp(&in_moveleft); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); +} + +void IN_MoverightDown(void) +{ + KeyDown(&in_moveright); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); +} + +void IN_MoverightUp(void) +{ + KeyUp(&in_moveright); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); +} +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +// needs capture by hud/vgui also +extern void __CmdFunc_InputPlayerSpecial(void); + +void IN_Attack2Down(void) +{ + KeyDown(&in_attack2); + + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); +} + +void IN_Attack2Up(void) {KeyUp(&in_attack2);} +void IN_UseDown (void) +{ + KeyDown(&in_use); + gHUD.m_Spectator.HandleButtonsDown( IN_USE ); +} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) +{ + KeyDown(&in_jump); + gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); + +} +void IN_JumpUp (void) {KeyUp(&in_jump);} +void IN_DuckDown(void) +{ + KeyDown(&in_duck); + gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); + +} +void IN_DuckUp(void) {KeyUp(&in_duck);} +void IN_ReloadDown(void) {KeyDown(&in_reload);} +void IN_ReloadUp(void) {KeyUp(&in_reload);} +void IN_Alt1Down(void) {KeyDown(&in_alt1);} +void IN_Alt1Up(void) {KeyUp(&in_alt1);} +void IN_GraphDown(void) {KeyDown(&in_graph);} +void IN_GraphUp(void) {KeyUp(&in_graph);} + +void IN_AttackDown(void) +{ + KeyDown( &in_attack ); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); +} + +void IN_AttackUp(void) +{ + KeyUp( &in_attack ); + in_cancel = 0; +} + +// Special handling +void IN_Cancel(void) +{ + in_cancel = 1; +} + +void IN_Impulse (void) +{ + in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); +} + +void IN_ScoreDown(void) +{ + KeyDown(&in_score); +} + +void IN_ScoreUp(void) +{ + KeyUp(&in_score); +} + +void IN_MLookUp (void) +{ + KeyUp( &in_mlook ); +} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val = 0.0; + int impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + + if ( impulsedown && !impulseup ) + { + // pressed and held this frame? + val = down ? 0.5 : 0.0; + } + + if ( impulseup && !impulsedown ) + { + // released this frame? + val = down ? 0.0 : 0.0; + } + + if ( !impulsedown && !impulseup ) + { + // held the entire frame? + val = down ? 1.0 : 0.0; + } + + if ( impulsedown && impulseup ) + { + if ( down ) + { + // released and re-pressed this frame + val = 0.75; + } + else + { + // pressed and released this frame + val = 0.25; + } + } + + // clear impulses + key->state &= 1; + return val; +} + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles ( float frametime, float *viewangles ) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + { + speed = frametime * cl_anglespeedkey->value; + } + else + { + speed = frametime; + } + + if (!(in_strafe.state & 1)) + { + viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); + viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); + viewangles[YAW] = anglemod(viewangles[YAW]); + } + if (in_klook.state & 1) + { + viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); + viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + viewangles[PITCH] -= speed*cl_pitchspeed->value * up; + viewangles[PITCH] += speed*cl_pitchspeed->value * down; + + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + if (viewangles[ROLL] > 50) + viewangles[ROLL] = 50; + if (viewangles[ROLL] < -50) + viewangles[ROLL] = -50; +} + +/* +================ +CL_CreateMove + +Send the intended movement message to the server +if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and +2 ) we have finished signing on to server +================ +*/ +void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) +{ + float spd; + vec3_t viewangles; + static vec3_t oldangles; + + if ( active ) + { + //memset( viewangles, 0, sizeof( vec3_t ) ); + //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + gEngfuncs.GetViewAngles( (float *)viewangles ); + + CL_AdjustAngles ( frametime, viewangles ); + + memset (cmd, 0, sizeof(*cmd)); + + gEngfuncs.SetViewAngles( (float *)viewangles ); + + if ( in_strafe.state & 1 ) + { + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + + if ( !(in_klook.state & 1 ) ) + { + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); + } + + // adjust for speed key + if ( in_speed.state & 1 ) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + cmd->upmove *= cl_movespeedkey->value; + } + + // clip to maxspeed + spd = gEngfuncs.GetClientMaxspeed(); + if ( spd != 0.0 ) + { + // scale the 3 speeds so that the total velocity is not > cl.maxspeed + float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + + if ( fmov > spd ) + { + float fratio = spd / fmov; + cmd->forwardmove *= fratio; + cmd->sidemove *= fratio; + cmd->upmove *= fratio; + } + } + + // Allow mice and other controllers to add their inputs + IN_Move ( frametime, cmd ); + } + + cmd->impulse = in_impulse; + in_impulse = 0; + + cmd->weaponselect = g_weaponselect; + g_weaponselect = 0; + // + // set button and flag bits + // + cmd->buttons = CL_ButtonBits( 1 ); + + + // Using joystick? + if ( in_joystick->value ) + { + if ( cmd->forwardmove > 0 ) + { + cmd->buttons |= IN_FORWARD; + } + else if ( cmd->forwardmove < 0 ) + { + cmd->buttons |= IN_BACK; + } + } + + gEngfuncs.GetViewAngles( (float *)viewangles ); + // Set current view angles. + + if ( g_iAlive ) + { + VectorCopy( viewangles, cmd->viewangles ); + VectorCopy( viewangles, oldangles ); + } + else + { + VectorCopy( oldangles, cmd->viewangles ); + } + +} + +/* +============ +CL_IsDead + +Returns 1 if health is <= 0 +============ +*/ +int CL_IsDead( void ) +{ + return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; +} + +/* +============ +CL_ButtonBits + +Returns appropriate button info for keyboard and mouse state +Set bResetState to 1 to clear old state info +============ +*/ +int CL_ButtonBits( int bResetState ) +{ + int bits = 0; + + if ( in_attack.state & 3 ) + { + if(gHUD.m_MOTD.m_bShow) + gHUD.m_MOTD.Reset(); + else + bits |= IN_ATTACK; + } + + + if (in_duck.state & 3) + { + bits |= IN_DUCK; + } + + if (in_jump.state & 3) + { + bits |= IN_JUMP; + } + + if ( in_forward.state & 3 ) + { + bits |= IN_FORWARD; + } + + if (in_back.state & 3) + { + bits |= IN_BACK; + } + + if (in_use.state & 3) + { + bits |= IN_USE; + } + + if (in_cancel) + { + bits |= IN_CANCEL; + } + + if ( in_left.state & 3 ) + { + bits |= IN_LEFT; + } + + if (in_right.state & 3) + { + bits |= IN_RIGHT; + } + + if ( in_moveleft.state & 3 ) + { + bits |= IN_MOVELEFT; + } + + if (in_moveright.state & 3) + { + bits |= IN_MOVERIGHT; + } + + if (in_attack2.state & 3) + { + bits |= IN_ATTACK2; + } + + if (in_reload.state & 3) + { + bits |= IN_RELOAD; + } + + if (in_alt1.state & 3) + { + bits |= IN_ALT1; + } + + if ( in_score.state & 3 ) + { + bits |= IN_SCORE; + } + + // Dead or in intermission? Shore scoreboard, too + if ( CL_IsDead() || gHUD.m_iIntermission ) + { + bits |= IN_SCORE; + } + + if ( bResetState ) + { + in_attack.state &= ~2; + in_duck.state &= ~2; + in_jump.state &= ~2; + in_forward.state &= ~2; + in_back.state &= ~2; + in_use.state &= ~2; + in_left.state &= ~2; + in_right.state &= ~2; + in_moveleft.state &= ~2; + in_moveright.state &= ~2; + in_attack2.state &= ~2; + in_reload.state &= ~2; + in_alt1.state &= ~2; + in_score.state &= ~2; + } + + return bits; +} + +/* +============ +CL_ResetButtonBits + +============ +*/ +void CL_ResetButtonBits( int bits ) +{ + int bitsNew = CL_ButtonBits( 0 ) ^ bits; + + // Has the attack button been changed + if ( bitsNew & IN_ATTACK ) + { + // Was it pressed? or let go? + if ( bits & IN_ATTACK ) + { + KeyDown( &in_attack ); + } + else + { + // totally clear state + in_attack.state &= ~7; + } + } +} + +/* +============ +InitInput +============ +*/ +void InitInput (void) +{ + gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); + gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); + gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); + gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); + gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); + gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); + gEngfuncs.pfnAddCommand ("+right",IN_RightDown); + gEngfuncs.pfnAddCommand ("-right",IN_RightUp); + gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); + gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); + gEngfuncs.pfnAddCommand ("+back",IN_BackDown); + gEngfuncs.pfnAddCommand ("-back",IN_BackUp); + gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); + gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); + gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); + gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); + gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); + gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); + gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); + gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); + gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); + gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); + gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); + gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); + gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); + gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); + gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); + gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); + gEngfuncs.pfnAddCommand ("+use", IN_UseDown); + gEngfuncs.pfnAddCommand ("-use", IN_UseUp); + gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); + gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); + gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); + gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); + gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); + gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); + gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); + gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); + gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); + gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); + gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); + gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); + gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); + gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); + gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); + gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); + gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); + gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); + gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + + lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + + cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + + m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + + // Initialize third person camera controls. + CAM_Init(); + // Initialize inputs + IN_Init(); + // Initialize keyboard + KB_Init(); + // Initialize view system + V_Init(); +} + +/* +============ +ShutdownInput +============ +*/ +void ShutdownInput (void) +{ + IN_Shutdown(); + KB_Shutdown(); +} + +void DLLEXPORT HUD_Shutdown( void ) +{ + ShutdownInput(); +} diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp new file mode 100644 index 00000000..c3737c8f --- /dev/null +++ b/cl_dll/input_xash3d.cpp @@ -0,0 +1,268 @@ +#include "hud.h" +#include "usercmd.h" +#include "cvardef.h" +#include "kbutton.h" +#include "keydefs.h" +cvar_t *sensitivity; +cvar_t *in_joystick; +#define DLLEXPORT +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + +extern "C" void DLLEXPORT IN_ClientMoveEvent( float forwardmove, float sidemove ); +extern "C" void DLLEXPORT IN_ClientLookEvent( float relyaw, float relpitch ); + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; +extern kbutton_t in_forward; +extern kbutton_t in_back; +extern kbutton_t in_moveleft; +extern kbutton_t in_moveright; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; +cvar_t *cl_laddermode; + + +float ac_forwardmove; +float ac_sidemove; +int ac_movecount; +float rel_yaw; +float rel_pitch; + +#define F 1<<0 // Forward +#define B 1<<1 // Back +#define L 1<<2 // Left +#define R 1<<3 // Right +#define T 1<<4 // Forward stop +#define S 1<<5 // Side stop + +#define BUTTON_DOWN 1 +#define IMPULSE_DOWN 2 +#define IMPULSE_UP 4 + + +void IN_ToggleButtons( float forwardmove, float sidemove ) +{ + static uint moveflags = T | S; + + if( forwardmove ) + moveflags &= ~T; + else + { + //if( in_forward.state || in_back.state ) gEngfuncs.Con_Printf("Buttons pressed f%d b%d\n", in_forward.state, in_back.state); + if( !( moveflags & T ) ) + { + //IN_ForwardUp(); + //IN_BackUp(); + //gEngfuncs.Con_Printf("Reset forwardmove state f%d b%d\n", in_forward.state, in_back.state); + in_forward.state &= ~BUTTON_DOWN; + in_back.state &= ~BUTTON_DOWN; + moveflags |= T; + } + } + if( sidemove ) + moveflags &= ~S; + else + { + //gEngfuncs.Con_Printf("l%d r%d\n", in_moveleft.state, in_moveright.state); + //if( in_moveleft.state || in_moveright.state ) gEngfuncs.Con_Printf("Buttons pressed l%d r%d\n", in_moveleft.state, in_moveright.state); + if( !( moveflags & S ) ) + { + //IN_MoverightUp(); + //IN_MoveleftUp(); + //gEngfuncs.Con_Printf("Reset sidemove state f%d b%d\n", in_moveleft.state, in_moveright.state); + in_moveleft.state &= ~BUTTON_DOWN; + in_moveright.state &= ~BUTTON_DOWN; + moveflags |= S; + } + } + + if ( forwardmove > 0.7 && !( moveflags & F )) + { + moveflags |= F; + in_forward.state |= BUTTON_DOWN; + } + if ( forwardmove < 0.7 && ( moveflags & F )) + { + moveflags &= ~F; + in_forward.state &= ~BUTTON_DOWN; + } + if ( forwardmove < -0.7 && !( moveflags & B )) + { + moveflags |= B; + in_back.state |= BUTTON_DOWN; + } + if ( forwardmove > -0.7 && ( moveflags & B )) + { + moveflags &= ~B; + in_back.state &= ~BUTTON_DOWN; + } + if ( sidemove > 0.9 && !( moveflags & R )) + { + moveflags |= R; + in_moveright.state |= BUTTON_DOWN; + } + if ( sidemove < 0.9 && ( moveflags & R )) + { + moveflags &= ~R; + in_moveright.state &= ~BUTTON_DOWN; + } + if ( sidemove < -0.9 && !( moveflags & L )) + { + moveflags |= L; + in_moveleft.state |= BUTTON_DOWN; + } + if ( sidemove > -0.9 && ( moveflags & L )) + { + moveflags &= ~L; + in_moveleft.state &= ~BUTTON_DOWN; + } + +} + +void IN_ClientMoveEvent( float forwardmove, float sidemove ) +{ + //gEngfuncs.Con_Printf("IN_MoveEvent\n"); + + ac_forwardmove += forwardmove; + ac_sidemove += sidemove; + ac_movecount++; +} + +void IN_ClientLookEvent( float relyaw, float relpitch ) +{ + rel_yaw += relyaw; + rel_pitch += relpitch; +} +// Rotate camera and add move values to usercmd +void IN_Move( float frametime, usercmd_t *cmd ) +{ + Vector viewangles; + gEngfuncs.GetViewAngles( viewangles ); + bool fLadder = false; + if( cl_laddermode->value !=2 ) fLadder = gEngfuncs.GetLocalPlayer()->curstate.movetype == MOVETYPE_FLY; + //if(ac_forwardmove || ac_sidemove) + //gEngfuncs.Con_Printf("Move: %f %f %f %f\n", ac_forwardmove, ac_sidemove, rel_pitch, rel_yaw); +#if 0 + if( in_mlook.state & 1 ) + { + V_StopPitchDrift(); + } +#endif + if( !gHUD.m_iIntermission ) + { + if( gHUD.GetSensitivity() != 0 ) + { + rel_yaw *= gHUD.GetSensitivity(); + rel_pitch *= gHUD.GetSensitivity(); + } + else + { + rel_yaw *= sensitivity->value; + rel_pitch *= sensitivity->value; + } + + viewangles[YAW] += rel_yaw; + if( fLadder ) + { + if( ( cl_laddermode->value == 1 ) ) + viewangles[YAW] -= ac_sidemove * 5; + ac_sidemove = 0; + } + if(gHUD.m_MOTD.m_bShow) + gHUD.m_MOTD.scroll += rel_pitch; + else + viewangles[PITCH] += rel_pitch; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + float rgfl[3]; + viewangles.CopyToArray( rgfl ); + gEngfuncs.SetViewAngles( rgfl ); + + if( ac_movecount ) + { + IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); + if( ac_forwardmove ) cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; + if( ac_sidemove ) cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; + } + + ac_sidemove = ac_forwardmove = rel_pitch = rel_yaw = 0; + ac_movecount = 0; +} + +extern "C" void IN_MouseEvent( int mstate ) +{ + static int mouse_oldbuttonstate; + // perform button actions + for( int i = 0; i < 5; i++ ) + { + if(( mstate & (1 << i)) && !( mouse_oldbuttonstate & (1 << i))) + { + gEngfuncs.Key_Event( K_MOUSE1 + i, 1 ); + } + + if( !( mstate & (1 << i)) && ( mouse_oldbuttonstate & (1 << i))) + { + gEngfuncs.Key_Event( K_MOUSE1 + i, 0 ); + } + } + + mouse_oldbuttonstate = mstate; +} + +// Stubs + +extern "C" void IN_ClearStates ( void ) +{ + //gEngfuncs.Con_Printf("IN_ClearStates\n"); +} + +extern "C" void IN_ActivateMouse ( void ) +{ + //gEngfuncs.Con_Printf("IN_ActivateMouse\n"); +} + +extern "C" void IN_DeactivateMouse ( void ) +{ + //gEngfuncs.Con_Printf("IN_DeactivateMouse\n"); +} + +extern "C" void IN_Accumulate ( void ) +{ + //gEngfuncs.Con_Printf("IN_Accumulate\n"); +} + +void IN_Commands ( void ) +{ + //gEngfuncs.Con_Printf("IN_Commands\n"); +} + +void IN_Shutdown ( void ) +{ +} +// Register cvars and reset data +void IN_Init( void ) +{ + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity", "3", FCVAR_ARCHIVE ); + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick", "0", FCVAR_ARCHIVE ); + cl_laddermode = gEngfuncs.pfnRegisterVariable ( "cl_laddermode", "2", FCVAR_ARCHIVE ); + ac_forwardmove = ac_sidemove = rel_yaw = rel_pitch = 0; +} diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp new file mode 100644 index 00000000..7176746b --- /dev/null +++ b/cl_dll/inputw32.cpp @@ -0,0 +1,947 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// in_win.c -- windows 95 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "../engine/keydefs.h" +#include "view.h" +#include "windows.h" + +#define MOUSE_BUTTON_COUNT 5 + +// Set this to 1 to show mouse cursor. Experimental +int g_iVisibleMouse = 0; + +extern "C" +{ + void DLLEXPORT IN_ActivateMouse( void ); + void DLLEXPORT IN_DeactivateMouse( void ); + void DLLEXPORT IN_MouseEvent (int mstate); + void DLLEXPORT IN_Accumulate (void); + void DLLEXPORT IN_ClearStates (void); +} + +extern cl_enginefunc_t gEngfuncs; + +extern int iMouseInUse; + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; + +// mouse variables +cvar_t *m_filter; +cvar_t *sensitivity; + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, + AxisForward, + AxisLook, + AxisSide, + AxisTurn +}; + +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, + JOY_RETURNY, + JOY_RETURNZ, + JOY_RETURNR, + JOY_RETURNU, + JOY_RETURNV +}; + +DWORD dwAxisMap[ JOY_MAX_AXES ]; +DWORD dwControlMap[ JOY_MAX_AXES ]; +PDWORD pdwRawValue[ JOY_MAX_AXES ]; + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; + +int joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; + +static JOYINFOEX ji; + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + vec3_t viewangles; + + if (!iMouseInUse) + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + viewangles[PITCH] = 0; + gEngfuncs.SetViewAngles( (float *)viewangles ); + } +} + +/* +=========== +IN_ActivateMouse +=========== +*/ +void DLLEXPORT IN_ActivateMouse (void) +{ + if (mouseinitialized) + { + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + mouseactive = 1; + } +} + +/* +=========== +IN_DeactivateMouse +=========== +*/ +void DLLEXPORT IN_DeactivateMouse (void) +{ + if (mouseinitialized) + { + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); + + mouseactive = 0; + } +} + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) + return; + + mouseinitialized = 1; + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + newmouseparms[2] = originalmouseparms[2]; + + if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } + + mouse_buttons = MOUSE_BUTTON_COUNT; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + IN_DeactivateMouse (); +} + +/* +=========== +IN_GetMousePos + +Ask for mouse position from engine +=========== +*/ +void IN_GetMousePos( int *mx, int *my ) +{ + gEngfuncs.GetMousePosition( mx, my ); +} + +/* +=========== +IN_ResetMouse + +FIXME: Call through to engine? +=========== +*/ +void IN_ResetMouse( void ) +{ + SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); +} + +/* +=========== +IN_MouseEvent +=========== +*/ +void DLLEXPORT IN_MouseEvent (int mstate) +{ + int i; + + if ( iMouseInUse || g_iVisibleMouse ) + return; + + // perform button actions + for (i=0 ; ivalue) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + if ( gHUD.GetSensitivity() != 0 ) + { + mouse_x *= gHUD.GetSensitivity(); + mouse_y *= gHUD.GetSensitivity(); + } + else + { + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + } + + // add mouse X/Y movement to cmd + if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + cmd->sidemove += m_side->value * mouse_x; + else + viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + viewangles[PITCH] += m_pitch->value * mouse_y; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + else + { + if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + { + cmd->upmove -= m_forward->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } + + // if the mouse has moved, force it to the center, so there's room to move + if ( mx || my ) + { + IN_ResetMouse(); + } + } + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +/* +//#define TRACE_TEST +#if defined( TRACE_TEST ) + { + int mx, my; + void V_Move( int mx, int my ); + IN_GetMousePos( &mx, &my ); + V_Move( mx, my ); + } +#endif +*/ +} + +/* +=========== +IN_Accumulate +=========== +*/ +void DLLEXPORT IN_Accumulate (void) +{ + //only accumulate mouse if we are not moving the camera with the mouse + if ( !iMouseInUse && !g_iVisibleMouse ) + { + if (mouseactive) + { + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); + + // force the mouse to the center, so there's room to move + IN_ResetMouse(); + } + } + +} + +/* +=================== +IN_ClearStates +=================== +*/ +void DLLEXPORT IN_ClearStates (void) +{ + if ( !mouseactive ) + return; + + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; +} + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick + joy_avail = 0; + + // abort startup if user requests no joystick + if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_idvalue == 0.0) + { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } + else + { + if ( strcmp ( joy_name->string, "joystick") != 0 ) + { + // notify user of advanced controller + gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + } + + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = (DWORD) joy_advaxisx->value; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisy->value; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisz->value; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisr->value; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisu->value; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisv->value; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } + + // compute the axes to collect from DirectInput + joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; + for (i = 0; i < JOY_MAX_AXES; i++) + { + if (dwAxisMap[i] != AxisNada) + { + joy_flags |= dwAxisFlags[i]; + } + } +} + + +/* +=========== +IN_Commands +=========== +*/ +void IN_Commands (void) +{ + int i, key_index; + DWORD buttonstate, povstate; + + if (!joy_avail) + { + return; + } + + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = ji.dwButtons; + for (i=0 ; i < (int)joy_numbuttons ; i++) + { + if ( (buttonstate & (1<value != 0.0) + { + ji.dwUpos += 100; + } + return 1; + } + else + { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Con_Printf ("IN_ReadJoystick: no response\n"); + // joy_avail = 0; + return 0; + } +} + + +/* +=========== +IN_JoyMove +=========== +*/ +void IN_JoyMove ( float frametime, usercmd_t *cmd ) +{ + float speed, aspeed; + float fAxisValue, fTemp; + int i; + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + + // complete initialization if first time in + // this is needed as cvars are not available at initialization time + if( joy_advancedinit != 1 ) + { + Joy_AdvancedUpdate_f(); + joy_advancedinit = 1; + } + + // verify joystick is available and that the user wants to use it + if (!joy_avail || !in_joystick->value) + { + return; + } + + // collect the joystick data, if possible + if (IN_ReadJoystick () != 1) + { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + + aspeed = speed * frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) + { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = (float) *pdwRawValue[i]; + // move centerpoint to zero + fAxisValue -= 32768.0; + + if (joy_wwhack2->value != 0.0) + { + if (dwAxisMap[i] == AxisTurn) + { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is factored out) + // then bounds check result to level out excessively high spin rates + fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is 0) + if (m_pitch->value < 0.0) + { + viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if(lookspring->value == 0.0) + { + V_StopPitchDrift(); + } + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold->value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold->value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + } + else + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (in_jlook.state & 1) + { + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if( lookspring->value == 0.0 ) + { + V_StopPitchDrift(); + } + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +} + +/* +=========== +IN_Move +=========== +*/ +void IN_Move ( float frametime, usercmd_t *cmd) +{ + if ( !iMouseInUse && mouseactive ) + { + IN_MouseMove ( frametime, cmd); + } + + IN_JoyMove ( frametime, cmd); +} + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + + gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); + gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + IN_StartupMouse (); + IN_StartupJoystick (); +} \ No newline at end of file diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h new file mode 100644 index 00000000..a772b3d3 --- /dev/null +++ b/cl_dll/kbutton.h @@ -0,0 +1,18 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +#endif // !KBUTTONH \ No newline at end of file diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp new file mode 100644 index 00000000..60ae2403 --- /dev/null +++ b/cl_dll/menu.cpp @@ -0,0 +1,186 @@ +/*** +* +* 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. +* +****/ +// +// menu.cpp +// +// generic menu handler +// +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + +#define MAX_MENU_STRING 512 +char g_szMenuString[MAX_MENU_STRING]; +char g_szPrelocalisedMenuString[MAX_MENU_STRING]; + +int KB_ConvertString( char *in, char **ppout ); + +DECLARE_MESSAGE( m_Menu, ShowMenu ); + +int CHudMenu :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( ShowMenu ); + + InitHUDData(); + + return 1; +} + +void CHudMenu :: InitHUDData( void ) +{ + m_fMenuDisplayed = 0; + m_bitsValidSlots = 0; + Reset(); +} + +void CHudMenu :: Reset( void ) +{ + g_szPrelocalisedMenuString[0] = 0; + m_fWaitingForMore = FALSE; +} + +int CHudMenu :: VidInit( void ) +{ + return 1; +} + +int CHudMenu :: Draw( float flTime ) +{ + // check for if menu is set to disappear + if ( m_flShutoffTime > 0 ) + { + if ( m_flShutoffTime <= gHUD.m_flTime ) + { // times up, shutoff + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + } + + // don't draw the menu if the scoreboard is being shown + + + + // draw the menu, along the left-hand side of the screen + + // count the number of newlines + int nlc = 0; + for ( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + { + if ( g_szMenuString[i] == '\n' ) + nlc++; + } + + // center it + int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text + int x = 20; + + i = 0; + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) + { + gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); + y += 12; + + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) + i++; + if ( g_szMenuString[i] == '\n' ) + i++; + } + + return 1; +} + +// selects an item from the menu +void CHudMenu :: SelectMenuItem( int menu_item ) +{ + // if menu_item is in a valid slot, send a menuselect command to the server + if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) + { + char szbuf[32]; + sprintf( szbuf, "menuselect %d\n", menu_item ); + ClientCmd( szbuf ); + + // remove the menu + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + } +} + + +// Message handler for ShowMenu message +// takes four values: +// short: a bitfield of keys that are valid input +// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. +// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string +// string: menu string to display +// if this message is never received, then scores will simply be the combined totals of the players. +int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) +{ + char *temp = NULL; + + BEGIN_READ( pbuf, iSize ); + + m_bitsValidSlots = READ_SHORT(); + int DisplayTime = READ_CHAR(); + int NeedMore = READ_BYTE(); + + if ( DisplayTime > 0 ) + m_flShutoffTime = DisplayTime + gHUD.m_flTime; + else + m_flShutoffTime = -1; + + if ( m_bitsValidSlots ) + { + if ( !m_fWaitingForMore ) // this is the start of a new menu + { + strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING ); + } + else + { // append to the current menu string + strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); + } + g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) + + if ( !NeedMore ) + { // we have the whole string, so we can localise it now + strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + + // Swap in characters + if ( KB_ConvertString( g_szMenuString, &temp ) ) + { + strcpy( g_szMenuString, temp ); + free( temp ); + } + } + + m_fMenuDisplayed = 1; + m_iFlags |= HUD_ACTIVE; + } + else + { + m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off + m_iFlags &= ~HUD_ACTIVE; + } + + m_fWaitingForMore = NeedMore; + + return 1; +} diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp new file mode 100644 index 00000000..61ea55a7 --- /dev/null +++ b/cl_dll/message.cpp @@ -0,0 +1,536 @@ +/*** +* +* 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. +* +****/ +// +// Message.cpp +// +// implementation of CHudMessage class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE( m_Message, HudText ) +DECLARE_MESSAGE( m_Message, GameTitle ) + +// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt +client_textmessage_t g_pCustomMessage; +char *g_pCustomName = "Custom"; +char g_pCustomText[1024]; + +int CHudMessage::Init(void) +{ + HOOK_MESSAGE( HudText ); + HOOK_MESSAGE( GameTitle ); + + gHUD.AddHudElem(this); + + Reset(); + + return 1; +}; + +int CHudMessage::VidInit( void ) +{ + m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); + m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); + + return 1; +}; + + +void CHudMessage::Reset( void ) +{ + memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); + memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); + + m_gameTitleTime = 0; + m_pGameTitle = NULL; +} + + +float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) +{ + float fadeTime = fadein + hold; + float fadeBlend; + + if ( localTime < 0 ) + return 0; + + if ( localTime < fadein ) + { + fadeBlend = 1 - ((fadein - localTime) / fadein); + } + else if ( localTime > fadeTime ) + { + if ( fadeout > 0 ) + fadeBlend = 1 - ((localTime - fadeTime) / fadeout); + else + fadeBlend = 0; + } + else + fadeBlend = 1; + + return fadeBlend; +} + + +int CHudMessage::XPosition( float x, int width, int totalWidth ) +{ + int xPos; + + if ( x == -1 ) + { + xPos = (ScreenWidth - width) / 2; + } + else + { + if ( x < 0 ) + xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right + else + xPos = x * ScreenWidth; + } + + if ( xPos + width > ScreenWidth ) + xPos = ScreenWidth - width; + else if ( xPos < 0 ) + xPos = 0; + + return xPos; +} + + +int CHudMessage::YPosition( float y, int height ) +{ + int yPos; + + if ( y == -1 ) // Centered? + yPos = (ScreenHeight - height) * 0.5; + else + { + // Alight bottom? + if ( y < 0 ) + yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom + else // align top + yPos = y * ScreenHeight; + } + + if ( yPos + height > ScreenHeight ) + yPos = ScreenHeight - height; + else if ( yPos < 0 ) + yPos = 0; + + return yPos; +} + + +void CHudMessage::MessageScanNextChar( void ) +{ + int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue; + int blend; + + srcRed = m_parms.pMessage->r1; + srcGreen = m_parms.pMessage->g1; + srcBlue = m_parms.pMessage->b1; + blend = 0; // Pure source + + switch( m_parms.pMessage->effect ) + { + // Fade-in / Fade-out + case 0: + case 1: + destRed = destGreen = destBlue = 0; + blend = m_parms.fadeBlend; + break; + + case 2: + m_parms.charTime += m_parms.pMessage->fadein; + if ( m_parms.charTime > m_parms.time ) + { + srcRed = srcGreen = srcBlue = 0; + blend = 0; // pure source + } + else + { + float deltaTime = m_parms.time - m_parms.charTime; + + destRed = destGreen = destBlue = 0; + if ( m_parms.time > m_parms.fadeTime ) + { + blend = m_parms.fadeBlend; + } + else if ( deltaTime > m_parms.pMessage->fxtime ) + blend = 0; // pure dest + else + { + destRed = m_parms.pMessage->r2; + destGreen = m_parms.pMessage->g2; + destBlue = m_parms.pMessage->b2; + blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); + } + } + break; + } + if ( blend > 255 ) + blend = 255; + else if ( blend < 0 ) + blend = 0; + + m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; + m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; + m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; + + if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) + { + if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); + } +} + + +void CHudMessage::MessageScanStart( void ) +{ + switch( m_parms.pMessage->effect ) + { + // Fade-in / out with flicker + case 1: + case 0: + m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; + + + if ( m_parms.time < m_parms.pMessage->fadein ) + { + m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); + } + else if ( m_parms.time > m_parms.fadeTime ) + { + if ( m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 255; // Pure dest (off) + } + else + m_parms.fadeBlend = 0; // Pure source (on) + m_parms.charTime = 0; + + if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) + m_parms.charTime = 1; + break; + + case 2: + m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; + + if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 0; + break; + } +} + + +void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) +{ + int i, j, length, width; + const char *pText; + unsigned char line[80]; + + pText = pMessage->pMessage; + // Count lines + m_parms.lines = 1; + m_parms.time = time; + m_parms.pMessage = pMessage; + length = 0; + width = 0; + m_parms.totalWidth = 0; + while ( *pText ) + { + if ( *pText == '\n' ) + { + m_parms.lines++; + if ( width > m_parms.totalWidth ) + m_parms.totalWidth = width; + width = 0; + } + else + width += gHUD.m_scrinfo.charWidths[*pText]; + pText++; + length++; + } + m_parms.length = length; + m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); + + + m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); + pText = pMessage->pMessage; + + m_parms.charTime = 0; + + MessageScanStart(); + + for ( i = 0; i < m_parms.lines; i++ ) + { + m_parms.lineLength = 0; + m_parms.width = 0; + while ( *pText && *pText != '\n' ) + { + unsigned char c = *pText; + line[m_parms.lineLength] = c; + m_parms.width += gHUD.m_scrinfo.charWidths[c]; + m_parms.lineLength++; + pText++; + } + pText++; // Skip LF + line[m_parms.lineLength] = 0; + + m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); + + for ( j = 0; j < m_parms.lineLength; j++ ) + { + m_parms.text = line[j]; + int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; + MessageScanNextChar(); + + if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); + m_parms.x = next; + } + + m_parms.y += gHUD.m_scrinfo.iCharHeight; + } +} + + +int CHudMessage::Draw( float fTime ) +{ + int i, drawn; + client_textmessage_t *pMessage; + float endTime; + + drawn = 0; + + if ( m_gameTitleTime > 0 ) + { + float localTime = gHUD.m_flTime - m_gameTitleTime; + float brightness; + + // Maybe timer isn't set yet + if ( m_gameTitleTime > gHUD.m_flTime ) + m_gameTitleTime = gHUD.m_flTime; + + if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) + m_gameTitleTime = 0; + else + { + brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); + + int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; + int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; + int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; + + int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); + int y = YPosition( m_pGameTitle->y, fullHeight ); + + + SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); + + SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); + + drawn = 1; + } + } + // Fixup level transitions + for ( i = 0; i < maxHUDMessages; i++ ) + { + // Assume m_parms.time contains last time + if ( m_pMessages[i] ) + { + pMessage = m_pMessages[i]; + if ( m_startTime[i] > gHUD.m_flTime ) + m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this + } + } + + for ( i = 0; i < maxHUDMessages; i++ ) + { + if ( m_pMessages[i] ) + { + pMessage = m_pMessages[i]; + + // This is when the message is over + switch( pMessage->effect ) + { + case 0: + case 1: + endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime; + break; + + // Fade in is per character in scanning messages + case 2: + endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime; + break; + } + + if ( fTime <= endTime ) + { + float messageTime = fTime - m_startTime[i]; + + // Draw the message + // effect 0 is fade in/fade out + // effect 1 is flickery credits + // effect 2 is write out (training room) + MessageDrawScan( pMessage, messageTime ); + + drawn++; + } + else + { + // The message is over + m_pMessages[i] = NULL; + } + } + } + + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + // Don't call until we get another message + if ( !drawn ) + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + + +void CHudMessage::MessageAdd( const char *pName, float time ) +{ + int i,j; + client_textmessage_t *tempMessage; + + for ( i = 0; i < maxHUDMessages; i++ ) + { + if ( !m_pMessages[i] ) + { + // Trim off a leading # if it's there + if ( pName[0] == '#' ) + tempMessage = TextMessageGet( pName+1 ); + else + tempMessage = TextMessageGet( pName ); + // If we couldnt find it in the titles.txt, just create it + if ( !tempMessage ) + { + g_pCustomMessage.effect = 2; + g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; + g_pCustomMessage.r2 = 240; + g_pCustomMessage.g2 = 110; + g_pCustomMessage.b2 = 0; + g_pCustomMessage.a2 = 0; + g_pCustomMessage.x = -1; // Centered + g_pCustomMessage.y = 0.7; + g_pCustomMessage.fadein = 0.01; + g_pCustomMessage.fadeout = 1.5; + g_pCustomMessage.fxtime = 0.25; + g_pCustomMessage.holdtime = 5; + g_pCustomMessage.pName = g_pCustomName; + strcpy( g_pCustomText, pName ); + g_pCustomMessage.pMessage = g_pCustomText; + + tempMessage = &g_pCustomMessage; + } + + for ( j = 0; j < maxHUDMessages; j++ ) + { + if ( m_pMessages[j] ) + { + // is this message already in the list + if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) + { + return; + } + + // get rid of any other messages in same location (only one displays at a time) + if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) + { + if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) + { + m_pMessages[j] = NULL; + } + } + } + } + + m_pMessages[i] = tempMessage; + m_startTime[i] = time; + return; + } + } +} + + +int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + char *pString = READ_STRING(); + + MessageAdd( pString, gHUD.m_flTime ); + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + + return 1; +} + + +int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) +{ + m_pGameTitle = TextMessageGet( "GAMETITLE" ); + if ( m_pGameTitle != NULL ) + { + m_gameTitleTime = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + } + + return 1; +} + +void CHudMessage::MessageAdd(client_textmessage_t * newMessage ) +{ + m_parms.time = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + + for ( int i = 0; i < maxHUDMessages; i++ ) + { + if ( !m_pMessages[i] ) + { + m_pMessages[i] = newMessage; + m_startTime[i] = gHUD.m_flTime; + return; + } + } + +} diff --git a/cl_dll/overview.cpp b/cl_dll/overview.cpp new file mode 100644 index 00000000..4f0ad0a3 --- /dev/null +++ b/cl_dll/overview.cpp @@ -0,0 +1,163 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "overview.h" + +// these are included for the math functions +#include "com_model.h" +#include "studio_util.h" + +#pragma warning(disable: 4244) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudOverview::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudOverview::VidInit() +{ + m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); + m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudOverview::Draw(float flTime) +{ +#if 0 + // only draw in overview mode + if (!gEngfuncs.Overview_GetOverviewState()) + return 1; + + // make sure we have player info +// gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + // calculate player size on the overview + int x1, y1, x2, y2; + float v0[3]={0,0,0}, v1[3]={64,64,0}; + gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); + gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); + float scale = abs(x2 - x1); + + // loop through all the players and draw them on the map + for (int i = 1; i < MAX_PLAYERS; i++) + { + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); + + if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) + { + int x, y, z = 0; + float v[3]={pl->origin[0], pl->origin[1], 0}; + gEngfuncs.Overview_WorldToScreen(v, &x, &y); + + // hack in some team colors + float r, g, bc; + if (g_PlayerExtraInfo[i].teamnumber == 1) + { + r = 0.0f; g = 0.0f; bc = 1.0f; + } + else if (g_PlayerExtraInfo[i].teamnumber == 2) + { + r = 1.0f; g = 0.0f; bc = 0.0f; + } + else + { + // just use the default orange color if the team isn't set + r = 1.0f; g = 0.7f; bc = 0.0f; + } + + // set the current texture + gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); + + // additive render mode + gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); + + // no culling + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + // draw a square + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + + // set the color to be that of the team + gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); + + // calculate rotational matrix + vec3_t a, b, angles; + float rmatrix[3][4]; // transformation matrix + VectorCopy(pl->angles, angles); + angles[0] = 0.0f; + angles[1] += 90.f; + angles[1] = -angles[1]; + angles[2] = 0.0f; + AngleMatrix(angles, rmatrix); + a[2] = 0; + + a[0] = -scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); + + a[0]=-scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + // finish up + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + + // draw the players name and health underneath + char string[256]; + sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); + DrawConsoleString(x, y + (1.1 * scale), string); + } + } + +#endif + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: called every time a server is connected to +//----------------------------------------------------------------------------- +void CHudOverview::InitHUDData() +{ +// this block would force the spectator view to be on +// gEngfuncs.Overview_SetDrawOverview( 1 ); +// gEngfuncs.Overview_SetDrawInset( 0 ); +} + diff --git a/cl_dll/overview.h b/cl_dll/overview.h new file mode 100644 index 00000000..7f0502e3 --- /dev/null +++ b/cl_dll/overview.h @@ -0,0 +1,31 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef OVERVIEW_H +#define OVERVIEW_H +#pragma once + + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the top-down map and all the things on it +//----------------------------------------------------------------------------- +class CHudOverview : public CHudBase +{ +public: + int Init(); + int VidInit(); + + int Draw(float flTime); + void InitHUDData( void ); + +private: + HSPRITE m_hsprPlayer; + HSPRITE m_hsprViewcone; +}; + + +#endif // OVERVIEW_H diff --git a/cl_dll/parsemsg.cpp b/cl_dll/parsemsg.cpp new file mode 100644 index 00000000..84f03b8b --- /dev/null +++ b/cl_dll/parsemsg.cpp @@ -0,0 +1,166 @@ +/*** +* +* 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. +* +****/ +// +// parsemsg.cpp +// +typedef unsigned char byte; +#define true 1 + +static byte *gpBuf; +static int giSize; +static int giRead; +static int giBadRead; + +void BEGIN_READ( void *buf, int size ) +{ + giRead = 0; + giBadRead = 0; + giSize = size; + gpBuf = (byte*)buf; +} + + +int READ_CHAR( void ) +{ + int c; + + if (giRead + 1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (signed char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_BYTE( void ) +{ + int c; + + if (giRead+1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (unsigned char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_SHORT( void ) +{ + int c; + + if (giRead+2 > giSize) + { + giBadRead = true; + return -1; + } + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); + + giRead += 2; + + return c; +} + +int READ_WORD( void ) +{ + return READ_SHORT(); +} + + +int READ_LONG( void ) +{ + int c; + + if (giRead+4 > giSize) + { + giBadRead = true; + return -1; + } + + c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); + + giRead += 4; + + return c; +} + +float READ_FLOAT( void ) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead+1]; + dat.b[2] = gpBuf[giRead+2]; + dat.b[3] = gpBuf[giRead+3]; + giRead += 4; + +// dat.l = LittleLong (dat.l); + + return dat.f; +} + +char* READ_STRING( void ) +{ + static char string[2048]; + int l,c; + + string[0] = 0; + + l = 0; + do + { + if ( giRead+1 > giSize ) + break; // no more characters + + c = READ_BYTE(); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float READ_COORD( void ) +{ + return (float)(READ_SHORT() * (1.0/8)); +} + +float READ_ANGLE( void ) +{ + return (float)(READ_CHAR() * (360.0/256)); +} + +float READ_HIRESANGLE( void ) +{ + return (float)(READ_SHORT() * (360.0/65536)); +} + diff --git a/cl_dll/parsemsg.h b/cl_dll/parsemsg.h new file mode 100644 index 00000000..ab8ff154 --- /dev/null +++ b/cl_dll/parsemsg.h @@ -0,0 +1,40 @@ +/*** +* +* 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. +* +****/ +// +// parsemsg.h +// + +#define ASSERT( x ) + +void BEGIN_READ( void *buf, int size ); +int READ_CHAR( void ); +int READ_BYTE( void ); +int READ_SHORT( void ); +int READ_WORD( void ); +int READ_LONG( void ); +float READ_FLOAT( void ); +char* READ_STRING( void ); +float READ_COORD( void ); +float READ_ANGLE( void ); +float READ_HIRESANGLE( void ); + + + + + + + + + diff --git a/cl_dll/readme.txt b/cl_dll/readme.txt new file mode 100644 index 00000000..23d561be --- /dev/null +++ b/cl_dll/readme.txt @@ -0,0 +1,107 @@ + client dll readme.txt +------------------------- + +This file details the structure of the half-life client dll, and +how it communicates with the half-life game engine. + + +Engine callback functions: + +Drawing functions: + HSPRITE SPR_Load( char *picname ); + Loads a sprite into memory, and returns a handle to it. + + int SPR_Frames( HSPRITE sprite ); + Returns the number of frames stored in the specified sprite. + + int SPR_Height( HSPRITE x, int frame ) + Returns the height, in pixels, of a sprite at the specified frame. + Returns 0 is the frame number or the sprite handle is invalid. + + int SPR_Width( HSPRITE x, int f ) + Returns the width, in pixels, of a sprite at the specified frame. + Returns 0 is the frame number or the sprite handle is invalid. + + int SPR_Set( HSPRITE sprite, int r, int g, int b ); + Prepares a sprite about to be drawn. RBG color values are applied to the sprite at this time. + + + void SPR_Draw( int frame, int x, int y ); + Precondition: SPR_Set has already been called for a sprite. + Draws the currently active sprite to the screen, at position (x,y), where (0,0) is + the top left-hand corner of the screen. + + + void SPR_DrawHoles( int frame, int x, int y ); + Precondition: SPR_Set has already been called for a sprite. + Draws the currently active sprite to the screen. Color index #255 is treated as transparent. + + void SPR_DrawAdditive( int frame, int x, int y ); + Precondition: SPR_Set has already been called for a sprite. + Draws the currently active sprite to the screen, adding it's color values to the background. + + void SPR_EnableScissor( int x, int y, int width, int height ); + Creates a clipping rectangle. No pixels will be drawn outside the specified area. Will + stay in effect until either the next frame, or SPR_DisableScissor is called. + + void SPR_DisableScissor( void ); + Disables the effect of an SPR_EnableScissor call. + + int IsHighRes( void ); + returns 1 if the res mode is 640x480 or higher; 0 otherwise. + + int ScreenWidth( void ); + returns the screen width, in pixels. + + int ScreenHeight( void ); + returns the screen height, in pixels. + +// Sound functions + void PlaySound( char *szSound, int volume ) + plays the sound 'szSound' at the specified volume. Loads the sound if it hasn't been cached. + If it can't find the sound, it displays an error message and plays no sound. + + void PlaySound( int iSound, int volume ) + Precondition: iSound has been precached. + Plays the sound, from the precache list. + + +// Communication functions + void SendClientCmd( char *szCmdString ); + sends a command to the server, just as if the client had typed the szCmdString at the console. + + char *GetPlayerName( int entity_number ); + returns a pointer to a string, that contains the name of the specified client. + Returns NULL if the entity_number is not a client. + + + DECLARE_MESSAGE(), HOOK_MESSAGE() + These two macros bind the message sending between the entity DLL and the client DLL to + the CHud object. + + HOOK_MESSAGE( message_name ) + This is used inside CHud::Init(). It calls into the engine to hook that message + from the incoming message stream. + Precondition: There must be a function of name UserMsg_message_name declared + for CHud. Eg, CHud::UserMsg_Health() must be declared if you want to + use HOOK_MESSAGE( Health ); + + DECLARE_MESSAGE( message_name ) + For each HOOK_MESSAGE you must have an equivalent DECLARE_MESSAGE. This creates + a function which passes the hooked messages into the CHud object. + + + HOOK_COMMAND(), DECLARE_COMMAND() + These two functions declare and hook console commands into the client dll. + + HOOK_COMMAND( char *command, command_name ) + Whenever the user types the 'command' at the console, the function 'command_name' + will be called. + Precondition: There must be a function of the name UserCmd_command_name declared + for CHud. Eg, CHud::UserMsg_ShowScores() must be declared if you want to + use HOOK_COMMAND( "+showscores", ShowScores ); + + DECLARE_COMMAND( command_name ) + For each HOOK_COMMAND you must have an equivelant DECLARE_COMMAND. This creates + a function which passes the hooked commands into the CHud object. + diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp new file mode 100644 index 00000000..47ebb142 --- /dev/null +++ b/cl_dll/saytext.cpp @@ -0,0 +1,312 @@ +/*** +* +* 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. +* +****/ +// +// saytext.cpp +// +// implementation of CHudSayText class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + +extern float *GetClientColor( int clientIndex ); + +#define MAX_LINES 5 +#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ + +// allow 20 pixels on either side of the text +#define MAX_LINE_WIDTH ( ScreenWidth - 40 ) +#define LINE_START 10 +static float SCROLL_SPEED = 5; + +static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; +static float *g_pflNameColors[ MAX_LINES + 1 ]; +static int g_iNameLengths[ MAX_LINES + 1 ]; +static float flScrollTime = 0; // the time at which the lines next scroll up + +static int Y_START = 0; +static int line_height = 0; + +DECLARE_MESSAGE( m_SayText, SayText ); + +int CHudSayText :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( SayText ); + + InitHUDData(); + + m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); + m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); + + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + + return 1; +} + + +void CHudSayText :: InitHUDData( void ) +{ + memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); + memset( g_pflNameColors, 0, sizeof g_pflNameColors ); + memset( g_iNameLengths, 0, sizeof g_iNameLengths ); +} + +int CHudSayText :: VidInit( void ) +{ + return 1; +} + + +int ScrollTextUp( void ) +{ + ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer + g_szLineBuffer[MAX_LINES][0] = 0; + memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line + memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); + memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); + g_szLineBuffer[MAX_LINES-1][0] = 0; + + if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines + { + g_szLineBuffer[0][0] = 2; + return 1 + ScrollTextUp(); + } + + return 1; +} + +int CHudSayText :: Draw( float flTime ) +{ + int y = Y_START; + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + if ( flScrollTime <= flTime ) + { + if ( *g_szLineBuffer[0] ) + { + flScrollTime = flTime + m_HUD_saytext_time->value; + // push the console up + ScrollTextUp(); + } + else + { // buffer is empty, just disable drawing of this section + m_iFlags &= ~HUD_ACTIVE; + } + } + + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( *g_szLineBuffer[i] ) + { + if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + { + // it's a saytext string + static char buf[MAX_PLAYER_NAME_LENGTH+32]; + + // draw the first x characters in the player color + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); + buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + gEngfuncs.pfnDrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + int x = DrawConsoleString( LINE_START, y, buf ); + + // color is reset after each string draw + DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); + } + else + { + // normal draw + DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + } + } + + y += line_height; + } + + + return 1; +} + +int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int client_index = READ_BYTE(); // the client who spoke the message + SayTextPrint( READ_STRING(), iSize - 1, client_index ); + + return 1; +} + +void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) +{ + ConsolePrint( pszBuf ); + + // find an empty string slot + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( ! *g_szLineBuffer[i] ) + break; + } + if ( i == MAX_LINES ) + { + // force scroll buffer up + ScrollTextUp(); + i = MAX_LINES - 1; + } + + g_iNameLengths[i] = 0; + g_pflNameColors[i] = NULL; + + // if it's a say message, search for the players name in the string + if ( *pszBuf == 2 && clientIndex > 0 ) + { + GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); + const char *pName = g_PlayerInfoList[clientIndex].name; + + if ( pName ) + { + const char *nameInString = strstr( pszBuf, pName ); + + if ( nameInString ) + { + g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); + g_pflNameColors[i] = GetClientColor( clientIndex ); + } + } + } + + strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); + + // make sure the text fits in one line + EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); + + // Set scroll time + if ( i == 0 ) + { + flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; + } + + m_iFlags |= HUD_ACTIVE; + PlaySound( "misc/talk.wav", 1 ); + + if ( ScreenHeight >= 480 ) + Y_START = ScreenHeight - 60; + else + Y_START = ScreenHeight - 45; + Y_START -= (line_height * (MAX_LINES+1)); + +} + +void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) +{ + int line_width = 0; + GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); + + if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) + { // string is too long to fit on line + // scan the string until we find what word is too long, and wrap the end of the sentence after the word + int length = LINE_START; + int tmp_len = 0; + char *last_break = NULL; + for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) + { + // check for a color change, if so skip past it + if ( x[0] == '/' && x[1] == '(' ) + { + x += 2; + // skip forward until past mode specifier + while ( *x != 0 && *x != ')' ) + x++; + + if ( *x != 0 ) + x++; + + if ( *x == 0 ) + break; + } + + char buf[2]; + buf[1] = 0; + + if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character + last_break = x; + + buf[0] = *x; // get the length of the current character + GetConsoleStringSize( buf, &tmp_len, &line_height ); + length += tmp_len; + + if ( length > MAX_LINE_WIDTH ) + { // needs to be broken up + if ( !last_break ) + last_break = x-1; + + x = last_break; + + // find an empty string slot + int j; + do + { + for ( j = 0; j < MAX_LINES; j++ ) + { + if ( ! *g_szLineBuffer[j] ) + break; + } + if ( j == MAX_LINES ) + { + // need to make more room to display text, scroll stuff up then fix the pointers + int linesmoved = ScrollTextUp(); + line -= linesmoved; + last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + } + } + while ( j == MAX_LINES ); + + // copy remaining string into next buffer, making sure it starts with a space character + if ( (char)*last_break == (char)' ' ) + { + int linelen = strlen(g_szLineBuffer[j]); + int remaininglen = strlen(last_break); + + if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) + strcat( g_szLineBuffer[j], last_break ); + } + else + { + if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) + { + strcat( g_szLineBuffer[j], " " ); + strcat( g_szLineBuffer[j], last_break ); + } + } + + *last_break = 0; // cut off the last string + + EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); + break; + } + } + } +} \ No newline at end of file diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp new file mode 100644 index 00000000..15aa9f2e --- /dev/null +++ b/cl_dll/scoreboard.cpp @@ -0,0 +1,603 @@ +/*** +* +* Copyright (c) 1999, 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. +* +****/ +// +// Scoreboard.cpp +// +// implementation of CHudScoreboard class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "triangleapi.h" + +#include +#include + +cvar_t *cl_showpacketloss; +hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +team_info_t g_TeamInfo[MAX_TEAMS+1]; +int g_iUser1; +int g_iUser2; +int g_iUser3; +int g_iTeamNumber; +int g_iPlayerClass; + +//#include "vgui_TeamFortressViewport.h" + +DECLARE_COMMAND( m_Scoreboard, ShowScores ); +DECLARE_COMMAND( m_Scoreboard, HideScores ); + +DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ); +DECLARE_MESSAGE( m_Scoreboard, TeamInfo ); +DECLARE_MESSAGE( m_Scoreboard, TeamScore ); + +int CHudScoreboard :: Init( void ) +{ + gHUD.AddHudElem( this ); + + // Hook messages & commands here + HOOK_COMMAND( "+showscores", ShowScores ); + HOOK_COMMAND( "-showscores", HideScores ); + + HOOK_MESSAGE( ScoreInfo ); + HOOK_MESSAGE( TeamScore ); + HOOK_MESSAGE( TeamInfo ); + + InitHUDData(); + + cl_showpacketloss = CVAR_CREATE( "cl_showpacketloss", "0", FCVAR_ARCHIVE ); + + return 1; +} + + +int CHudScoreboard :: VidInit( void ) +{ + // Load sprites here + return 1; +} + +void CHudScoreboard :: InitHUDData( void ) +{ + memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); + m_iLastKilledBy = 0; + m_fLastKillTime = 0; + m_iPlayerNum = 0; + m_iNumTeams = 0; + memset( g_TeamInfo, 0, sizeof g_TeamInfo ); + + m_iFlags &= ~HUD_ACTIVE; // starts out inactive + + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission +} + +/* The scoreboard +We have a minimum width of 1-320 - we could have the field widths scale with it? +*/ + +// X positions +// relative to the side of the scoreboard +#define NAME_RANGE_MIN 20 +#define NAME_RANGE_MAX 145 +#define KILLS_RANGE_MIN 130 +#define KILLS_RANGE_MAX 170 +#define DIVIDER_POS 180 +#define DEATHS_RANGE_MIN 185 +#define DEATHS_RANGE_MAX 210 +#define PING_RANGE_MIN 245 +#define PING_RANGE_MAX 295 +#define PL_RANGE_MIN 315 +#define PL_RANGE_MAX 375 + +int SCOREBOARD_WIDTH = 320; + + +// Y positions +#define ROW_GAP 13 +#define ROW_RANGE_MIN 15 +#define ROW_RANGE_MAX ( ScreenHeight - 50 ) + +int CHudScoreboard :: Draw( float fTime ) +{ + int can_show_packetloss = 0; + int FAR_RIGHT; + gHUD.m_iNoConsolePrint &= ~( 1 << 0 ); + + if ( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) + return 1; + + gHUD.m_iNoConsolePrint |= 1 << 0; + + GetAllPlayersInfo(); + + // Packetloss removed on Kelly 'shipping nazi' Bailey's orders + if ( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) + { + can_show_packetloss = 1; + SCOREBOARD_WIDTH = 400; + } + else + { + SCOREBOARD_WIDTH = 320; + } + + // just sort the list on the fly + // list is sorted first by frags, then by deaths + float list_slot = 0; + int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; + + // print the heading line + int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + int xpos = NAME_RANGE_MIN + xpos_rel; + + FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; + FAR_RIGHT += 5; + gHUD.DrawDarkRectangle(xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX); + if ( !gHUD.m_Teamplay ) + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); + else + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); + + gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "kills", 255, 140, 0 ); + gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); + gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); + gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); + + if ( can_show_packetloss ) + { + gHUD.DrawHudString( PL_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "pkt loss", 255, 140, 0 ); + } + + + list_slot += 1.2; + ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + xpos = NAME_RANGE_MIN + xpos_rel; + FillRGBA( xpos - 4, ypos, FAR_RIGHT -2, 1, 255, 140, 0, 255); // draw the seperator line + + list_slot += 0.8; + + if ( !gHUD.m_Teamplay ) + { + // it's not teamplay, so just draw a simple player list + DrawPlayers( xpos_rel, list_slot ); + return 1; + } + + // clear out team scores + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + if ( !g_TeamInfo[i].scores_overriden ) + g_TeamInfo[i].frags = g_TeamInfo[i].deaths = 0; + g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; + } + + // recalc the team scores, then draw them + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + //if ( g_PlayerInfoList[i].name == NULL ) + // continue; // empty player slot, skip + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // find what team this player is in + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy + continue; + + if ( !g_TeamInfo[j].scores_overriden ) + { + g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; + g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; + } + + g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; + g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; + + if ( g_PlayerInfoList[i].thisplayer ) + g_TeamInfo[j].ownteam = TRUE; + else + g_TeamInfo[j].ownteam = FALSE; + } + + // find team ping/packetloss averages + for ( i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].already_drawn = FALSE; + + if ( g_TeamInfo[i].players > 0 ) + { + g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + } + } + + // Draw the teams + while ( 1 ) + { + int highest_frags = -99999; int lowest_deaths = 99999; + int best_team = 0; + + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 0 ) + continue; + + if ( !g_TeamInfo[i].already_drawn && g_TeamInfo[i].frags >= highest_frags ) + { + if ( g_TeamInfo[i].frags > highest_frags || g_TeamInfo[i].deaths < lowest_deaths ) + { + best_team = i; + lowest_deaths = g_TeamInfo[i].deaths; + highest_frags = g_TeamInfo[i].frags; + } + } + } + + // draw the best team on the scoreboard + if ( !best_team ) + break; + + // draw out the best team + team_info_t *team_info = &g_TeamInfo[best_team]; + + ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + + // check we haven't drawn too far down + if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + break; + + xpos = NAME_RANGE_MIN + xpos_rel; + int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish + + if ( team_info->ownteam ) // if it is their team, draw the background different color + { + // overlay the background in blue, then draw the score text over it + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 0, 0, 255, 70 ); + } + + // draw their name (left to right) + gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); + + // draw kills (right to left) + xpos = KILLS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b ); + + // draw divider + xpos = DIVIDER_POS + xpos_rel; + gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + + // draw deaths + xpos = DEATHS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b ); + + // draw ping + // draw ping & packetloss + static char buf[64]; + sprintf( buf, "%d", team_info->ping ); + xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + UnpackRGB( r, g, b, RGB_YELLOWISH ); + gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); + + // Packetloss removed on Kelly 'shipping nazi' Bailey's orders + if ( can_show_packetloss ) + { + xpos = ((PL_RANGE_MAX - PL_RANGE_MIN) / 2) + PL_RANGE_MIN + xpos_rel + 25; + + sprintf( buf, " %d", team_info->packetloss ); + gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); + } + + team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again + list_slot++; + + // draw all the players that belong to this team, indented slightly + list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name ); + } + + // draw all the players who are not in a team + list_slot += 0.5; + DrawPlayers( xpos_rel, list_slot, 0, "" ); + + return 1; +} +extern float *GetClientColor( int client ); +// returns the ypos where it finishes drawing +int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team ) +{ + int can_show_packetloss = 0; + int FAR_RIGHT; + + // Packetloss removed on Kelly 'shipping nazi' Bailey's orders + if ( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) + { + can_show_packetloss = 1; + SCOREBOARD_WIDTH = 400; + } + else + { + SCOREBOARD_WIDTH = 320; + } + + FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; + FAR_RIGHT += 5; + + // draw the players, in order, and restricted to team if set + while ( 1 ) + { + // Find the top ranking player + int highest_frags = -99999; int lowest_deaths = 99999; + int best_player = 0; + + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) + { + if ( !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team + { + extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; + if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) + { + best_player = i; + lowest_deaths = pl_info->deaths; + highest_frags = pl_info->frags; + } + } + } + } + + if ( !best_player ) + break; + + // draw out the best player + hud_player_info_t *pl_info = &g_PlayerInfoList[best_player]; + + int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + + // check we haven't drawn too far down + if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + break; + + int xpos = NAME_RANGE_MIN + xpos_rel; + int r = 255, g = 255, b = 255; + float *colors = GetClientColor( best_player ); + r *= colors[0], g *= colors[1], b *= colors[2]; + if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + { + if ( pl_info->thisplayer ) + { // green is the suicide color? i wish this could do grey... + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 80, 155, 0, 70 ); + } + else + { // Highlight the killers name - overlay the background in red, then draw the score text over it + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + } + } + else if ( pl_info->thisplayer ) // if it is their name, draw it a different color + { + // overlay the background in blue, then draw the score text over it + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 0, 0, 255, 70 ); + } + + // draw their name (left to right) + gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b ); + + // draw kills (right to left) + xpos = KILLS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, g_PlayerExtraInfo[best_player].frags, r, g, b ); + + // draw divider + xpos = DIVIDER_POS + xpos_rel; + gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + + // draw deaths + xpos = DEATHS_RANGE_MAX + xpos_rel; + gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, g_PlayerExtraInfo[best_player].deaths, r, g, b ); + + // draw ping & packetloss + static char buf[64]; + sprintf( buf, "%d", g_PlayerInfoList[best_player].ping ); + xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); + + // Packetloss removed on Kelly 'shipping nazi' Bailey's orders + if ( can_show_packetloss ) + { + if ( g_PlayerInfoList[best_player].packetloss >= 63 ) + { + UnpackRGB( r, g, b, RGB_REDISH ); + sprintf( buf, " !!!!" ); + } + else + { + sprintf( buf, " %d", g_PlayerInfoList[best_player].packetloss ); + } + + xpos = ((PL_RANGE_MAX - PL_RANGE_MIN) / 2) + PL_RANGE_MIN + xpos_rel + 25; + + gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); + } + + pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again + list_slot++; + } + + return list_slot; +} + + +void CHudScoreboard :: GetAllPlayersInfo( void ) +{ + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + GetPlayerInfo( i, &g_PlayerInfoList[i] ); + + if ( g_PlayerInfoList[i].thisplayer ) + m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine + } +} + +int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + short frags = READ_SHORT(); + short deaths = READ_SHORT(); + short playerclass = READ_SHORT(); + short teamnumber = READ_SHORT(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + g_PlayerExtraInfo[cl].frags = frags; + g_PlayerExtraInfo[cl].deaths = deaths; + g_PlayerExtraInfo[cl].playerclass = playerclass; + g_PlayerExtraInfo[cl].teamnumber = teamnumber; + + //gViewPort->UpdateOnPlayerInfo(); + } + + return 1; +} + +// Message handler for TeamInfo message +// accepts two values: +// byte: client number +// string: client team name +int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { // set the players team + strncpy( g_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); + } + + // rebuild the list of teams + + // clear out player counts from teams + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].players = 0; + } + + // rebuild the team list + GetAllPlayersInfo(); + m_iNumTeams = 0; + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + //if ( g_PlayerInfoList[i].name == NULL ) + // continue; + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // is this player in an existing team? + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + + if ( j > m_iNumTeams ) + { // they aren't in a listed team, so make a new one + // search through for an empty team slot + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + } + m_iNumTeams = max( j, m_iNumTeams ); + + strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); + g_TeamInfo[j].players = 0; + } + + g_TeamInfo[j].players++; + } + + // clear out any empty teams + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); + } + + return 1; +} + +// Message handler for TeamScore message +// accepts three values: +// string: team name +// short: teams kills +// short: teams deaths +// if this message is never received, then scores will simply be the combined totals of the players. +int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + char *TeamName = READ_STRING(); + + // find the team matching the name + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + if ( !stricmp( TeamName, g_TeamInfo[i].name ) ) + break; + } + if ( i > m_iNumTeams ) + return 1; + + // use this new score data instead of combined player scores + g_TeamInfo[i].scores_overriden = TRUE; + g_TeamInfo[i].frags = READ_SHORT(); + g_TeamInfo[i].deaths = READ_SHORT(); + + return 1; +} + +void CHudScoreboard :: DeathMsg( int killer, int victim ) +{ + // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide + if ( victim == m_iPlayerNum || killer == 0 ) + { + m_iLastKilledBy = killer ? killer : m_iPlayerNum; + m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds + + if ( killer == m_iPlayerNum ) + m_iLastKilledBy = m_iPlayerNum; + } +} + + + +void CHudScoreboard :: UserCmd_ShowScores( void ) +{ + m_iShowscoresHeld = TRUE; +} + +void CHudScoreboard :: UserCmd_HideScores( void ) +{ + m_iShowscoresHeld = FALSE; +} diff --git a/cl_dll/soundsystem.cpp b/cl_dll/soundsystem.cpp new file mode 100644 index 00000000..a25084c4 --- /dev/null +++ b/cl_dll/soundsystem.cpp @@ -0,0 +1,162 @@ +//======== (C) Copyright 1996-2002 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: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include "r_studioint.h" + +extern engine_studio_api_t IEngineStudio; + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +LPDIRECTSOUND lpDS = NULL; +LPDIRECTSOUNDBUFFER lpDSBuf = NULL; +LPHWAVEOUT lpHW = NULL; + +static HMODULE hEngine = 0; + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + void ( *unused1 ) ( void ); + void ( *unused2 ) ( void ); + void ( *unused3 ) ( void ); + void ( *unused4 ) ( void ); + void ( *unused5 ) ( void ); + void ( *unused6 ) ( void ); + void ( *unused7 ) ( void ); + void ( *unused8 ) ( void ); + void ( *unused9 ) ( void ); + void ( *unused10 ) ( void ); + void ( *unused11 ) ( void ); + void ( *unused12 ) ( void ); + void ( *unused13 ) ( void ); + void ( *unused14 ) ( void ); + void ( *unused15 ) ( void ); + void ( *unused16 ) ( void ); + void ( *unused17 ) ( void ); + void ( *unused18 ) ( void ); + void ( *unused19 ) ( void ); + void ( *unused20 ) ( void ); + void ( *unused21 ) ( void ); + void ( *unused22 ) ( void ); + void ( *unused23 ) ( void ); + void ( *unused24 ) ( void ); + void ( *unused25 ) ( void ); + void ( *unused26 ) ( void ); + void ( *unused27 ) ( void ); + void ( *unused28 ) ( void ); + void ( *unused29 ) ( void ); + void ( *unused30 ) ( void ); + void ( *unused31 ) ( void ); + void ( *unused32 ) ( void ); + void ( *unused33 ) ( void ); + void ( *unused34 ) ( void ); + + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + + void ( *unused35 ) ( void ); + void ( *unused36 ) ( void ); + void ( *unused37 ) ( void ); + void ( *unused38 ) ( void ); + void ( *unused39 ) ( void ); + void ( *unused40 ) ( void ); + void ( *unused41 ) ( void ); + void ( *unused42 ) ( void ); + void ( *unused43 ) ( void ); + void ( *unused44 ) ( void ); + void ( *unused45 ) ( void ); + void ( *unused46 ) ( void ); + void ( *unused47 ) ( void ); + void ( *unused48 ) ( void ); + void ( *unused49 ) ( void ); + void ( *unused50 ) ( void ); + void ( *unused51 ) ( void ); + void ( *unused52 ) ( void ); + void ( *unused53 ) ( void ); + void ( *unused54 ) ( void ); + void ( *unused55 ) ( void ); +} engine_api_t; + +static engine_api_t engineapi; + +typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); + +//----------------------------------------------------------------------------- +// Purpose: Get launcher/engine interface from engine module +// Input : hMod - +// Output : int +//----------------------------------------------------------------------------- +int Eng_LoadFunctions( HMODULE hMod ) +{ + engine_api_func pfnEngineAPI; + + pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); + if ( !pfnEngineAPI ) + return 0; + + if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + return 0; + + // All is okay + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) +//----------------------------------------------------------------------------- +void LoadSoundAPIs( void ) +{ + hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); + if ( hEngine ) + { + if ( Eng_LoadFunctions( hEngine ) ) + { + if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) + { + engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); + lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Close engine library, release sound pointers +//----------------------------------------------------------------------------- +void ShutdownSoundAPIs( void ) +{ + if( hEngine ) + { + FreeLibrary( hEngine ); + hEngine = 0; + } + + lpDS = 0; + lpDSBuf = 0; + lpHW = 0; +} diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp new file mode 100644 index 00000000..9207143e --- /dev/null +++ b/cl_dll/status_icons.cpp @@ -0,0 +1,162 @@ +/*** +* +* 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. +* +****/ +// +// status_icons.cpp +// +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include +#include +#include "parsemsg.h" +#include "event_api.h" + +DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); + +int CHudStatusIcons::Init( void ) +{ + HOOK_MESSAGE( StatusIcon ); + + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +} + +int CHudStatusIcons::VidInit( void ) +{ + + return 1; +} + +void CHudStatusIcons::Reset( void ) +{ + memset( m_IconList, 0, sizeof m_IconList ); + m_iFlags &= ~HUD_ACTIVE; +} + +// Draw status icons along the left-hand side of the screen +int CHudStatusIcons::Draw( float flTime ) +{ + if (gEngfuncs.IsSpectateOnly()) + return 1; + // find starting position to draw from, along right-hand side of screen + int x = 5; + int y = ScreenHeight / 2; + + // loop through icon list, and draw any valid icons drawing up from the middle of screen + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( m_IconList[i].spr ) + { + y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; + + SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); + SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); + } + } + + return 1; +} + +// Message handler for StatusIcon message +// accepts five values: +// byte : TRUE = ENABLE icon, FALSE = DISABLE icon +// string : the sprite name to display +// byte : red +// byte : green +// byte : blue +int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int ShouldEnable = READ_BYTE(); + char *pszIconName = READ_STRING(); + if ( ShouldEnable ) + { + int r = READ_BYTE(); + int g = READ_BYTE(); + int b = READ_BYTE(); + EnableIcon( pszIconName, r, g, b ); + m_iFlags |= HUD_ACTIVE; + } + else + { + DisableIcon( pszIconName ); + } + + return 1; +} + +// add the icon to the icon list, and set it's drawing color +void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) +{ + // check to see if the sprite is in the current list + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + break; + } + + if ( i == MAX_ICONSPRITES ) + { + // icon not in list, so find an empty slot to add to + for ( i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !m_IconList[i].spr ) + break; + } + } + + // if we've run out of space in the list, overwrite the first icon + if ( i == MAX_ICONSPRITES ) + { + i = 0; + } + + // Load the sprite and add it to the list + // the sprite must be listed in hud.txt + int spr_index = gHUD.GetSpriteIndex( pszIconName ); + m_IconList[i].spr = gHUD.GetSprite( spr_index ); + m_IconList[i].rc = gHUD.GetSpriteRect( spr_index ); + m_IconList[i].r = red; + m_IconList[i].g = green; + m_IconList[i].b = blue; + strcpy( m_IconList[i].szSpriteName, pszIconName ); + + // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) + if ( strstr(m_IconList[i].szSpriteName, "grenade") ) + { + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + } +} + +void CHudStatusIcons::DisableIcon( char *pszIconName ) +{ + // find the sprite is in the current list + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + { + // clear the item from the list + memset( &m_IconList[i], 0, sizeof( icon_sprite_t ) ); + return; + } + } +} diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp new file mode 100644 index 00000000..28018da9 --- /dev/null +++ b/cl_dll/statusbar.cpp @@ -0,0 +1,265 @@ +/*** +* +* 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. +* +****/ +// +// statusbar.cpp +// +// generic text status bar, set by game dll +// runs across bottom of screen +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE( m_StatusBar, StatusText ); +DECLARE_MESSAGE( m_StatusBar, StatusValue ); + +#define STATUSBAR_ID_LINE 1 + +float *GetClientColor( int clientIndex ); +extern float g_ColorYellow[3]; + +int CHudStatusBar :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( StatusText ); + HOOK_MESSAGE( StatusValue ); + + Reset(); + + CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); + + return 1; +} + +int CHudStatusBar :: VidInit( void ) +{ + // Load sprites here + + return 1; +} + +void CHudStatusBar :: Reset( void ) +{ + int i = 0; + + m_iFlags &= ~HUD_ACTIVE; // start out inactive + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_szStatusText[i][0] = 0; + memset( m_iStatusValues, 0, sizeof m_iStatusValues ); + + m_iStatusValues[0] = 1; // 0 is the special index, which always returns true + + // reset our colors for the status bar lines (yellow is default) + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_pflNameColors[i] = g_ColorYellow; +} + +void CHudStatusBar :: ParseStatusString( int line_num ) +{ + // localise string first + char szBuffer[MAX_STATUSTEXT_LENGTH]; + memset( szBuffer, 0, sizeof szBuffer ); + gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); + + // parse m_szStatusText & m_iStatusValues into m_szStatusBar + memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH ); + char *src = szBuffer; + char *dst = m_szStatusBar[line_num]; + + char *src_start = src, *dst_start = dst; + + while ( *src != 0 ) + { + while ( *src == '\n' ) + src++; // skip over any newlines + + if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) + break; + + int index = atoi( src ); + // should we draw this line? + if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) ) + { // parse this line and append result to the status bar + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( *src == '\n' || *src == 0 ) + continue; // no more left in this text line + + // copy the text, char by char, until we hit a % or a \n + while ( *src != '\n' && *src != 0 ) + { + if ( *src != '%' ) + { // just copy the character + *dst = *src; + dst++, src++; + } + else + { + // get the descriptor + char valtype = *(++src); // move over % + + // if it's a %, draw a % sign + if ( valtype == '%' ) + { + *dst = valtype; + dst++, src++; + continue; + } + + // move over descriptor, then get and move over the index + index = atoi( ++src ); + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) + { + int indexval = m_iStatusValues[index]; + + // get the string to substitute in place of the %XX + char szRepString[MAX_PLAYER_NAME_LENGTH]; + switch ( valtype ) + { + case 'p': // player name + GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); + if ( g_PlayerInfoList[indexval].name != NULL ) + { + strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + m_pflNameColors[line_num] = GetClientColor( indexval ); + } + else + { + strcpy( szRepString, "******" ); + } + + break; + case 'i': // number + sprintf( szRepString, "%d", indexval ); + break; + default: + szRepString[0] = 0; + } + + for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) + *dst = *cp; + } + } + } + } + else + { + // skip to next line of text + while ( *src != 0 && *src != '\n' ) + src++; + } + } +} + +int CHudStatusBar :: Draw( float fTime ) +{ + if ( m_bReparseString ) + { + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + m_pflNameColors[i] = g_ColorYellow; + ParseStatusString( i ); + } + m_bReparseString = FALSE; + } + + int Y_START = ScreenHeight - YRES(32 + 4); + + // Draw the status bar lines + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + int TextHeight, TextWidth; + GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); + + int x = 4; + int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen + + // let user set status ID bar centering + if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) + { + x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 ); + y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); + } + + if ( m_pflNameColors[i] ) + gEngfuncs.pfnDrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + + DrawConsoleString( x, y, m_szStatusBar[i] ); + } + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: line number of status bar text +// string: status bar text +// this string describes how the status bar should be drawn +// a semi-regular expression: +// ( slotnum ([a..z] [%pX] [%iX])*)* +// where slotnum is an index into the Value table (see below) +// if slotnum is 0, the string is always drawn +// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline +// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] +// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] +int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int line = READ_BYTE(); + + if ( line < 0 || line >= MAX_STATUSBAR_LINES ) + return 1; + + strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH ); + m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) + + if ( m_szStatusText[0] == 0 ) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar + + m_bReparseString = TRUE; + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: index into the status value array +// short: value to store +int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + if ( index < 1 || index >= MAX_STATUSBAR_VALUES ) + return 1; // index out of range + + m_iStatusValues[index] = READ_SHORT(); + + m_bReparseString = TRUE; + + return 1; +} \ No newline at end of file diff --git a/cl_dll/studio_util.cpp b/cl_dll/studio_util.cpp new file mode 100644 index 00000000..ab14d96e --- /dev/null +++ b/cl_dll/studio_util.cpp @@ -0,0 +1,251 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio_util.h" + +/* +==================== +AngleMatrix + +==================== +*/ +void AngleMatrix (const float *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; +} + +/* +==================== +VectorCompare + +==================== +*/ +int VectorCompare (const float *v1, const float *v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +/* +==================== +CrossProduct + +==================== +*/ +void CrossProduct (const float *v1, const float *v2, float *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]; +} + +/* +==================== +VectorTransform + +==================== +*/ +void VectorTransform (const float *in1, float in2[3][4], float *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]; +} + +/* +================ +ConcatTransforms + +================ +*/ +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +// angles index are not the same as ROLL, PITCH, YAW + +/* +==================== +AngleQuaternion + +==================== +*/ +void AngleQuaternion( float *angles, vec4_t quaternion ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + // FIXME: rescale the inputs to 1/2 angle + angle = angles[2] * 0.5; + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * 0.5; + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * 0.5; + sr = sin(angle); + cr = cos(angle); + + quaternion[0] = sr*cp*cy-cr*sp*sy; // X + quaternion[1] = cr*sp*cy+sr*cp*sy; // Y + quaternion[2] = cr*cp*sy-sr*sp*cy; // Z + quaternion[3] = cr*cp*cy+sr*sp*sy; // W +} + +/* +==================== +QuaternionSlerp + +==================== +*/ +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) +{ + int i; + float omega, cosom, sinom, sclp, sclq; + + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + + for (i = 0; i < 4; i++) + { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + q[i] = -q[i]; + } + } + + cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.0 + cosom) > 0.000001) + { + if ((1.0 - cosom) > 0.000001) + { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0 - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else + { + sclp = 1.0 - t; + sclq = t; + } + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else + { + qt[0] = -q[1]; + qt[1] = q[0]; + qt[2] = -q[3]; + qt[3] = q[2]; + sclp = sin( (1.0 - t) * (0.5 * M_PI)); + sclq = sin( t * (0.5 * M_PI)); + for (i = 0; i < 3; i++) + { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } +} + +/* +==================== +QuaternionMatrix + +==================== +*/ +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) +{ + matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; +} + +/* +==================== +MatrixCopy + +==================== +*/ +void MatrixCopy( float in[3][4], float out[3][4] ) +{ + memcpy( out, in, sizeof( float ) * 3 * 4 ); +} \ No newline at end of file diff --git a/cl_dll/studio_util.h b/cl_dll/studio_util.h new file mode 100644 index 00000000..e1cb980e --- /dev/null +++ b/cl_dll/studio_util.h @@ -0,0 +1,40 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( STUDIO_UTIL_H ) +#define STUDIO_UTIL_H +#if defined( WIN32 ) +#pragma once +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#ifndef PITCH +// MOVEMENT INFO +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 +#endif + +#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) + +void AngleMatrix (const float *angles, float (*matrix)[4] ); +int VectorCompare (const float *v1, const float *v2); +void CrossProduct (const float *v1, const float *v2, float *cross); +void VectorTransform (const float *in1, float in2[3][4], float *out); +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void MatrixCopy( float in[3][4], float out[3][4] ); +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); +void AngleQuaternion( float *angles, vec4_t quaternion ); + +#endif // STUDIO_UTIL_H \ No newline at end of file diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp new file mode 100644 index 00000000..f40cd5e7 --- /dev/null +++ b/cl_dll/text_message.cpp @@ -0,0 +1,209 @@ +/*** +* +* 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. +* +****/ +// +// text_message.cpp +// +// implementation of CHudTextMessage class +// +// this class routes messages through titles.txt for localisation +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + + +DECLARE_MESSAGE( m_TextMessage, TextMsg ); + +int CHudTextMessage::Init(void) +{ + HOOK_MESSAGE( TextMsg ); + + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +}; + +// Searches through the string for any msg names (indicated by a '#') +// any found are looked up in titles.txt and the new message substituted +// the new value is pushed into dst_buffer +char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) +{ + char *dst = dst_buffer; + for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + { + if ( *src == '#' ) + { + // cut msg name out of string + static char word_buf[255]; + char *wdst = word_buf, *word_start = src; + for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) + { + *wdst = *src; + } + *wdst = 0; + + // lookup msg name in titles.txt + client_textmessage_t *clmsg = TextMessageGet( word_buf ); + if ( !clmsg || !(clmsg->pMessage) ) + { + src = word_start; + *dst = *src; + dst++, src++; + continue; + } + + // copy string into message over the msg name + for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) + { + *dst = *wsrc; + } + *dst = 0; + } + else + { + *dst = *src; + dst++, src++; + *dst = 0; + } + } + + dst_buffer[buffer_size-1] = 0; // ensure null termination + return dst_buffer; +} + +// As above, but with a local static buffer +char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) +{ + static char dst_buffer[1024]; + LocaliseTextString( msg, dst_buffer, 1024 ); + return dst_buffer; +} + +// Simplified version of LocaliseTextString; assumes string is only one word +char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) +{ + if ( !msg ) + return ""; + + // '#' character indicates this is a reference to a string in titles.txt, and not the string itself + if ( msg[0] == '#' ) + { + // this is a message name, so look up the real message + client_textmessage_t *clmsg = TextMessageGet( msg+1 ); + + if ( !clmsg || !(clmsg->pMessage) ) + return (char*)msg; // lookup failed, so return the original string + + if ( msg_dest ) + { + // check to see if titles.txt info overrides msg destination + // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination + if ( clmsg->effect < 0 ) // + *msg_dest = -clmsg->effect; + } + + return (char*)clmsg->pMessage; + } + else + { // nothing special about this message, so just return the same string + return (char*)msg; + } +} + +void StripEndNewlineFromString( char *str ) +{ + int s = strlen( str ) - 1; + if ( str[s] == '\n' || str[s] == '\r' ) + str[s] = 0; +} + +// converts all '\r' characters to '\n', so that the engine can deal with the properly +// returns a pointer to str +char* ConvertCRtoNL( char *str ) +{ + for ( char *ch = str; *ch != 0; ch++ ) + if ( *ch == '\r' ) + *ch = '\n'; + return str; +} + +// Message handler for text messages +// displays a string, looking them up from the titles.txt file, which can be localised +// parameters: +// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) +// string: message +// optional parameters: +// string: message parameter 1 +// string: message parameter 2 +// string: message parameter 3 +// string: message parameter 4 +// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt +// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') +int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int msg_dest = READ_BYTE(); + + static char szBuf[6][128]; + char *msg_text = LookupString( READ_STRING(), &msg_dest ); + msg_text = strcpy( szBuf[0], msg_text ); + + // keep reading strings and using C format strings for subsituting the strings into the localised text string + char *sstr1 = LookupString( READ_STRING() ); + sstr1 = strcpy( szBuf[1], sstr1 ); + StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines + char *sstr2 = LookupString( READ_STRING() ); + sstr2 = strcpy( szBuf[2], sstr2 ); + StripEndNewlineFromString( sstr2 ); + char *sstr3 = LookupString( READ_STRING() ); + sstr3 = strcpy( szBuf[3], sstr3 ); + StripEndNewlineFromString( sstr3 ); + char *sstr4 = LookupString( READ_STRING() ); + sstr4 = strcpy( szBuf[4], sstr4 ); + StripEndNewlineFromString( sstr4 ); + char *psz = szBuf[5]; + + switch ( msg_dest ) + { + case HUD_PRINTCENTER: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + CenterPrint( ConvertCRtoNL( psz ) ); + break; + + case HUD_PRINTNOTIFY: + psz[0] = 1; // mark this message to go into the notify buffer + sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 ); + ConsolePrint( ConvertCRtoNL( psz ) ); + break; + + case HUD_PRINTTALK: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); + break; + + case HUD_PRINTCONSOLE: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + ConsolePrint( ConvertCRtoNL( psz ) ); + break; + } + + return 1; +} diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h new file mode 100644 index 00000000..f178c55b --- /dev/null +++ b/cl_dll/tf_defs.h @@ -0,0 +1,1389 @@ +/*** +* +* 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. +* +****/ + +#ifndef __TF_DEFS_H +#define __TF_DEFS_H + +//=========================================================================== +// OLD OPTIONS.QC +//=========================================================================== +#define DEFAULT_AUTOZOOM FALSE +#define WEINER_SNIPER // autoaiming for sniper rifle +#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. + +//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server +#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active +#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active + +//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time +//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server +#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into +#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) +#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies + +#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. + // 60 is a mild setting, and won't make too much difference + // increasing it _decreases_ the amount of help the losing team gets + // Minimum setting is 1, which would really help the losing team + +#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to + // appear whenever a player connects +#define NEVER_TEAMFRAGS FALSE // teamfrags options always off +#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on +#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast +#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds + +#define MAPBRIEFING_MAXTEXTLENGTH 512 +#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed + +// Debug Options +//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res + // mode and/or piping the output from the server to a file. +#ifdef MAP_DEBUG + #define MDEBUG(x) x +#else + #define MDEBUG(x) +#endif +//#define VERBOSE // Verbose Debugging on/off + +//=========================================================================== +// OLD QUAKE Defs +//=========================================================================== +// items +#define IT_AXE 4096 +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_EXTRA_WEAPON 128 + +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 + +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 + +#define IT_KEY1 131072 +#define IT_KEY2 262144 + +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_HOOK 8388608 + +#define IT_KEY3 16777216 // Stomp invisibility +#define IT_KEY4 33554432 // Stomp invulnerability + +//=========================================================================== +// TEAMFORTRESS Defs +//=========================================================================== +// TeamFortress State Flags +#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade +#define TFSTATE_RELOADING 2 // Whether the player is reloading +#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE +#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn +#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon +#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) +#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) +#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) +#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) +#define TFSTATE_BURNING 512 // Is on fire +#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade +#define TFSTATE_AIMING 2048 // is using the laser sight +#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating +#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised +#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health + +// Defines used by TF_T_Damage (see combat.qc) +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) +#define TF_TD_NOTSELF 4 // Doesn't damage self + +#define TF_TD_OTHER 0 // Ignore armorclass +#define TF_TD_SHOT 1 // Bullet damage +#define TF_TD_NAIL 2 // Nail damage +#define TF_TD_EXPLOSION 4 // Explosion damage +#define TF_TD_ELECTRICITY 8 // Electric damage +#define TF_TD_FIRE 16 // Fire damage +#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc + +/*==================================================*/ +/* Toggleable Game Settings */ +/*==================================================*/ +#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn + +#define TEAMPLAY_NORMAL 1 +#define TEAMPLAY_HALFDIRECT 2 +#define TEAMPLAY_NODIRECT 4 +#define TEAMPLAY_HALFEXPLOSIVE 8 +#define TEAMPLAY_NOEXPLOSIVE 16 +#define TEAMPLAY_LESSPLAYERSHELP 32 +#define TEAMPLAY_LESSSCOREHELP 64 +#define TEAMPLAY_HALFDIRECTARMOR 128 +#define TEAMPLAY_NODIRECTARMOR 256 +#define TEAMPLAY_HALFEXPARMOR 512 +#define TEAMPLAY_NOEXPARMOR 1024 +#define TEAMPLAY_HALFDIRMIRROR 2048 +#define TEAMPLAY_FULLDIRMIRROR 4096 +#define TEAMPLAY_HALFEXPMIRROR 8192 +#define TEAMPLAY_FULLEXPMIRROR 16384 + +#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) +// FortressMap stuff +#define TEAM1_CIVILIANS 1 +#define TEAM2_CIVILIANS 2 +#define TEAM3_CIVILIANS 4 +#define TEAM4_CIVILIANS 8 + +// Defines for the playerclass +#define PC_UNDEFINED 0 + +#define PC_SCOUT 1 +#define PC_SNIPER 2 +#define PC_SOLDIER 3 +#define PC_DEMOMAN 4 +#define PC_MEDIC 5 +#define PC_HVYWEAP 6 +#define PC_PYRO 7 +#define PC_SPY 8 +#define PC_ENGINEER 9 + +// Insert new class definitions here + +// PC_RANDOM _MUST_ be the third last class +#define PC_RANDOM 10 // Random playerclass +#define PC_CIVILIAN 11 // Civilians are a special class. They cannot + // be chosen by players, only enforced by maps +#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops + // through the playerclass. + +#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors + +// These are just for the scanner +#define SCAN_SENTRY 13 +#define SCAN_GOALITEM 14 + +// Values returned by CheckArea +enum +{ + CAREA_CLEAR, + CAREA_BLOCKED, + CAREA_NOBUILD +}; + +/*==================================================*/ +/* Impulse Defines */ +/*==================================================*/ +// Alias check to see whether they already have the aliases +#define TF_ALIAS_CHECK 13 + +// CTF Support Impulses +#define HOOK_IMP1 22 +#define FLAG_INFO 23 +#define HOOK_IMP2 39 + +// Axe +#define AXE_IMP 40 + +// Camera Impulse +#define TF_CAM_TARGET 50 +#define TF_CAM_ZOOM 51 +#define TF_CAM_ANGLE 52 +#define TF_CAM_VEC 53 +#define TF_CAM_PROJECTILE 54 +#define TF_CAM_PROJECTILE_Z 55 +#define TF_CAM_REVANGLE 56 +#define TF_CAM_OFFSET 57 +#define TF_CAM_DROP 58 +#define TF_CAM_FADETOBLACK 59 +#define TF_CAM_FADEFROMBLACK 60 +#define TF_CAM_FADETOWHITE 61 +#define TF_CAM_FADEFROMWHITE 62 + +// Last Weapon impulse +#define TF_LAST_WEAPON 69 + +// Status Bar Resolution Settings. Same as CTF to maintain ease of use. +#define TF_STATUSBAR_RES_START 71 +#define TF_STATUSBAR_RES_END 81 + +// Clan Messages +#define TF_MESSAGE_1 82 +#define TF_MESSAGE_2 83 +#define TF_MESSAGE_3 84 +#define TF_MESSAGE_4 85 +#define TF_MESSAGE_5 86 + +#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu + +// Added to PC_??? to get impulse to use if this clashes with your +// own impulses, just change this value, not the PC_?? +#define TF_CHANGEPC 100 +// The next few impulses are all the class selections +//PC_SCOUT 101 +//PC_SNIPER 102 +//PC_SOLDIER 103 +//PC_DEMOMAN 104 +//PC_MEDIC 105 +//PC_HVYWEAP 106 +//PC_PYRO 107 +//PC_RANDOM 108 +//PC_CIVILIAN 109 // Cannot be used +//PC_SPY 110 +//PC_ENGINEER 111 + +// Help impulses +#define TF_DISPLAYLOCATION 118 +#define TF_STATUS_QUERY 119 + +#define TF_HELP_MAP 131 + +// Information impulses +#define TF_INVENTORY 135 +#define TF_SHOWTF 136 +#define TF_SHOWLEGALCLASSES 137 + +// Team Impulses +#define TF_TEAM_1 140 // Join Team 1 +#define TF_TEAM_2 141 // Join Team 2 +#define TF_TEAM_3 142 // Join Team 3 +#define TF_TEAM_4 143 // Join Team 4 +#define TF_TEAM_CLASSES 144 // Impulse to display team classes +#define TF_TEAM_SCORES 145 // Impulse to display team scores +#define TF_TEAM_LIST 146 // Impulse to display the players in each team. + +// Grenade Impulses +#define TF_GRENADE_1 150 // Prime grenade type 1 +#define TF_GRENADE_2 151 // Prime grenade type 2 +#define TF_GRENADE_T 152 // Throw primed grenade + +// Impulses for new items +//#define TF_SCAN 159 // Scanner Pre-Impulse +#define TF_AUTO_SCAN 159 // Scanner On/Off +#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies +#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies +//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) +#define TF_SCAN_SOUND 162 // Scanner sounds on/off +#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) +#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) +#define TF_DETPACK_5 165 // Detpack set to 5 seconds +#define TF_DETPACK_20 166 // Detpack set to 20 seconds +#define TF_DETPACK_50 167 // Detpack set to 50 seconds +#define TF_DETPACK 168 // Detpack Pre-Impulse +#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack +#define TF_PB_DETONATE 170 // Detonate Pipebombs + +// Special skill +#define TF_SPECIAL_SKILL 171 + +// Ammo Drop impulse +#define TF_DROP_AMMO 172 + +// Reload impulse +#define TF_RELOAD 173 + +// auto-zoom toggle +#define TF_AUTOZOOM 174 + +// drop/pass commands +#define TF_DROPKEY 175 + +// Select Medikit +#define TF_MEDIKIT 176 + +// Spy Impulses +#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color +#define TF_SPY_DIE 178 // Feign Death + +// Engineer Impulses +#define TF_ENGINEER_BUILD 179 +#define TF_ENGINEER_SANDBAG 180 + +// Medic +#define TF_MEDIC_HELPME 181 + +// Status bar +#define TF_STATUSBAR_ON 182 +#define TF_STATUSBAR_OFF 183 + +// Discard impulse +#define TF_DISCARD 184 + +// ID Player impulse +#define TF_ID 185 + +// Clan Battle impulses +#define TF_SHOWIDS 186 + +// More Engineer Impulses +#define TF_ENGINEER_DETDISP 187 +#define TF_ENGINEER_DETSENT 188 + +// Admin Commands +#define TF_ADMIN_DEAL_CYCLE 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 + +// Drop Goal Items +#define TF_DROPGOALITEMS 194 + +// More Admin Commands +#define TF_ADMIN_NEXT 195 + +// More Engineer Impulses +#define TF_ENGINEER_DETEXIT 196 +#define TF_ENGINEER_DETENTRANCE 197 + +// Yet MORE Admin Commands +#define TF_ADMIN_LISTIPS 198 + +// Silent Spy Feign +#define TF_SPY_SILENTDIE 199 + + +/*==================================================*/ +/* Defines for the ENGINEER's Building ability */ +/*==================================================*/ +// Ammo costs +#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell +#define AMMO_COST_NAILS 1 +#define AMMO_COST_ROCKETS 2 +#define AMMO_COST_CELLS 2 + +// Building types +#define BUILD_DISPENSER 1 +#define BUILD_SENTRYGUN 2 +#define BUILD_MORTAR 3 +#define BUILD_TELEPORTER_ENTRANCE 4 +#define BUILD_TELEPORTER_EXIT 5 + +// Building metal costs +#define BUILD_COST_DISPENSER 100 // Metal needed to built +#define BUILD_COST_SENTRYGUN 130 +#define BUILD_COST_MORTAR 150 +#define BUILD_COST_TELEPORTER 125 + +#define BUILD_COST_SANDBAG 20 // Built with a separate alias + +// Building times +#define BUILD_TIME_DISPENSER 2 // seconds to build +#define BUILD_TIME_SENTRYGUN 5 +#define BUILD_TIME_MORTAR 5 +#define BUILD_TIME_TELEPORTER 4 + +// Building health levels +#define BUILD_HEALTH_DISPENSER 150 // Health of the building +#define BUILD_HEALTH_SENTRYGUN 150 +#define BUILD_HEALTH_MORTAR 200 +#define BUILD_HEALTH_TELEPORTER 80 + +// Dispenser's maximum carrying capability +#define BUILD_DISPENSER_MAX_SHELLS 400 +#define BUILD_DISPENSER_MAX_NAILS 600 +#define BUILD_DISPENSER_MAX_ROCKETS 300 +#define BUILD_DISPENSER_MAX_CELLS 400 +#define BUILD_DISPENSER_MAX_ARMOR 500 + +// Build state sent down to client +#define BS_BUILDING (1<<0) +#define BS_HAS_DISPENSER (1<<1) +#define BS_HAS_SENTRYGUN (1<<2) +#define BS_CANB_DISPENSER (1<<3) +#define BS_CANB_SENTRYGUN (1<<4) +/*==================================================*/ +/* Ammo quantities for dropping & dispenser use */ +/*==================================================*/ +#define DROP_SHELLS 20 +#define DROP_NAILS 20 +#define DROP_ROCKETS 10 +#define DROP_CELLS 10 +#define DROP_ARMOR 40 + +/*==================================================*/ +/* Team Defines */ +/*==================================================*/ +#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. + // A new global to hold new team colors is needed, and more flags + // in the spawnpoint spawnflags may need to be used. + // Basically, don't change this unless you know what you're doing :) + +/*==================================================*/ +/* New Weapon Defines */ +/*==================================================*/ +#define WEAP_HOOK 1 +#define WEAP_BIOWEAPON 2 +#define WEAP_MEDIKIT 4 +#define WEAP_SPANNER 8 +#define WEAP_AXE 16 +#define WEAP_SNIPER_RIFLE 32 +#define WEAP_AUTO_RIFLE 64 +#define WEAP_SHOTGUN 128 +#define WEAP_SUPER_SHOTGUN 256 +#define WEAP_NAILGUN 512 +#define WEAP_SUPER_NAILGUN 1024 +#define WEAP_GRENADE_LAUNCHER 2048 +#define WEAP_FLAMETHROWER 4096 +#define WEAP_ROCKET_LAUNCHER 8192 +#define WEAP_INCENDIARY 16384 +#define WEAP_ASSAULT_CANNON 32768 +#define WEAP_LIGHTNING 65536 +#define WEAP_DETPACK 131072 +#define WEAP_TRANQ 262144 +#define WEAP_LASER 524288 +// still room for 12 more weapons +// but we can remove some by giving the weapons +// a weapon mode (like the rifle) + +// HL-compatible weapon numbers +#define WEAPON_HOOK 1 +#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) +#define WEAPON_MEDIKIT (WEAPON_HOOK+2) +#define WEAPON_SPANNER (WEAPON_HOOK+3) +#define WEAPON_AXE (WEAPON_HOOK+4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) +#define WEAPON_NAILGUN (WEAPON_HOOK+9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) +#define WEAPON_INCENDIARY (WEAPON_HOOK+14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) +#define WEAPON_LIGHTNING (WEAPON_HOOK+17) +#define WEAPON_DETPACK (WEAPON_HOOK+18) +#define WEAPON_TRANQ (WEAPON_HOOK+19) +#define WEAPON_LASER (WEAPON_HOOK+20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) +#define WEAPON_KNIFE (WEAPON_HOOK+22) +#define WEAPON_BENCHMARK (WEAPON_HOOK+23) + +/*==================================================*/ +/* New Weapon Related Defines */ +/*==================================================*/ +// shots per reload +#define RE_SHOTGUN 8 +#define RE_SUPER_SHOTGUN 16 // 8 shots +#define RE_GRENADE_LAUNCHER 6 +#define RE_ROCKET_LAUNCHER 4 + +// reload times +#define RE_SHOTGUN_TIME 2 +#define RE_SUPER_SHOTGUN_TIME 3 +#define RE_GRENADE_LAUNCHER_TIME 4 +#define RE_ROCKET_LAUNCHER_TIME 5 + +// Maximum velocity you can move and fire the Sniper Rifle +#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 + +// Medikit +#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit +#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense + +// Spanner +#define WEAP_SPANNER_REPAIR 10 + +// Detpack +#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack +#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack +#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering +#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into + +// Tranquiliser Gun +#define TRANQ_TIME 15 + +// Grenades +#define GR_PRIMETIME 3 +#define GR_CALTROP_PRIME 0.5 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 +#define GR_TYPE_CALTROP 9 +//#define GR_TYPE_FLASH 10 + +// Defines for WeaponMode +#define GL_NORMAL 0 +#define GL_PIPEBOMB 1 + +// Defines for OLD Concussion Grenade +#define GR_OLD_CONCUSS_TIME 5 +#define GR_OLD_CONCUSS_DEC 20 + +// Defines for Concussion Grenade +#define GR_CONCUSS_TIME 0.25 +#define GR_CONCUSS_DEC 10 +#define MEDIUM_PING 150 +#define HIGH_PING 200 + +// Defines for the Gas Grenade +#define GR_HALLU_TIME 0.3 +#define GR_OLD_HALLU_TIME 0.5 +#define GR_HALLU_DEC 2.5 + +// Defines for the BioInfection +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players + +/*==================================================*/ +/* New Items */ +/*==================================================*/ +#define NIT_SCANNER 1 + +#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 +#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 + +/*==================================================*/ +/* New Item Flags */ +/*==================================================*/ +#define NIT_SCANNER_ENEMY 1 // Detect enemies +#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) +#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. + +/*==================================================*/ +/* New Item Related Defines */ +/*==================================================*/ +#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner + // is multiplied by this to get the scanrange. +#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan +#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected + // by scanners that only detect movement + +/*==================================================*/ +/* Variables used for New Weapons and Reloading */ +/*==================================================*/ +// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. +#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% +#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% +#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% +#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% +#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% + +/*==========================================================================*/ +/* TEAMFORTRESS CLASS DETAILS */ +/*==========================================================================*/ +// Class Details for SCOUT +#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. +#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed +#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed +#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption +#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned +#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class +#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned +#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN +#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry +#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry +#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry +#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry +#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned +#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned +#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned +#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has + +#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range +#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse +#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range +#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan + +// Class Details for SNIPER +#define PC_SNIPER_SKIN 5 +#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXSPEED 300 +#define PC_SNIPER_MAXSTRAFESPEED 300 +#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_INITARMOR 0 +#define PC_SNIPER_MAXARMORTYPE 0.3 +#define PC_SNIPER_INITARMORTYPE 0.3 +#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL +#define PC_SNIPER_INITARMORCLASS 0 +#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN +#define PC_SNIPER_MAXAMMO_SHOT 75 +#define PC_SNIPER_MAXAMMO_NAIL 100 +#define PC_SNIPER_MAXAMMO_CELL 50 +#define PC_SNIPER_MAXAMMO_ROCKET 25 +#define PC_SNIPER_INITAMMO_SHOT 60 +#define PC_SNIPER_INITAMMO_NAIL 50 +#define PC_SNIPER_INITAMMO_CELL 0 +#define PC_SNIPER_INITAMMO_ROCKET 0 +#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE +#define PC_SNIPER_GRENADE_INIT_1 2 +#define PC_SNIPER_GRENADE_INIT_2 0 +#define PC_SNIPER_TF_ITEMS 0 + +// Class Details for SOLDIER +#define PC_SOLDIER_SKIN 6 +#define PC_SOLDIER_MAXHEALTH 100 +#define PC_SOLDIER_MAXSPEED 240 +#define PC_SOLDIER_MAXSTRAFESPEED 240 +#define PC_SOLDIER_MAXARMOR 200 +#define PC_SOLDIER_INITARMOR 100 +#define PC_SOLDIER_MAXARMORTYPE 0.8 +#define PC_SOLDIER_INITARMORTYPE 0.8 +#define PC_SOLDIER_ARMORCLASSES 31 // ALL +#define PC_SOLDIER_INITARMORCLASS 0 +#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER +#define PC_SOLDIER_MAXAMMO_SHOT 100 +#define PC_SOLDIER_MAXAMMO_NAIL 100 +#define PC_SOLDIER_MAXAMMO_CELL 50 +#define PC_SOLDIER_MAXAMMO_ROCKET 50 +#define PC_SOLDIER_INITAMMO_SHOT 50 +#define PC_SOLDIER_INITAMMO_NAIL 0 +#define PC_SOLDIER_INITAMMO_CELL 0 +#define PC_SOLDIER_INITAMMO_ROCKET 10 +#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +#define PC_SOLDIER_GRENADE_INIT_1 2 +#define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_TF_ITEMS 0 + +#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active +#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active +#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active +#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's +#define MAX_CONCUSSION_GRENS 3 +#define MAX_CALTROP_CANS 3 + +// Class Details for DEMOLITION MAN +#define PC_DEMOMAN_SKIN 1 +#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXSPEED 280 +#define PC_DEMOMAN_MAXSTRAFESPEED 280 +#define PC_DEMOMAN_MAXARMOR 120 +#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMORTYPE 0.6 +#define PC_DEMOMAN_INITARMORTYPE 0.6 +#define PC_DEMOMAN_ARMORCLASSES 31 // ALL +#define PC_DEMOMAN_INITARMORCLASS 0 +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_MAXAMMO_SHOT 75 +#define PC_DEMOMAN_MAXAMMO_NAIL 50 +#define PC_DEMOMAN_MAXAMMO_CELL 50 +#define PC_DEMOMAN_MAXAMMO_ROCKET 50 +#define PC_DEMOMAN_MAXAMMO_DETPACK 1 +#define PC_DEMOMAN_INITAMMO_SHOT 30 +#define PC_DEMOMAN_INITAMMO_NAIL 0 +#define PC_DEMOMAN_INITAMMO_CELL 0 +#define PC_DEMOMAN_INITAMMO_ROCKET 20 +#define PC_DEMOMAN_INITAMMO_DETPACK 1 +#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_INIT_1 2 +#define PC_DEMOMAN_GRENADE_INIT_2 2 +#define PC_DEMOMAN_TF_ITEMS 0 + +// Class Details for COMBAT MEDIC +#define PC_MEDIC_SKIN 3 +#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXARMOR 100 +#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMORTYPE 0.6 +#define PC_MEDIC_INITARMORTYPE 0.3 +#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION +#define PC_MEDIC_INITARMORCLASS 0 +#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN +#define PC_MEDIC_MAXAMMO_SHOT 75 +#define PC_MEDIC_MAXAMMO_NAIL 150 +#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_ROCKET 25 +#define PC_MEDIC_MAXAMMO_MEDIKIT 100 +#define PC_MEDIC_INITAMMO_SHOT 50 +#define PC_MEDIC_INITAMMO_NAIL 50 +#define PC_MEDIC_INITAMMO_CELL 0 +#define PC_MEDIC_INITAMMO_ROCKET 0 +#define PC_MEDIC_INITAMMO_MEDIKIT 50 +#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_INIT_1 2 +#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_TF_ITEMS 0 +#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. +#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. + +// Class Details for HVYWEAP +#define PC_HVYWEAP_SKIN 2 +#define PC_HVYWEAP_MAXHEALTH 100 +#define PC_HVYWEAP_MAXSPEED 230 +#define PC_HVYWEAP_MAXSTRAFESPEED 230 +#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_INITARMOR 150 +#define PC_HVYWEAP_MAXARMORTYPE 0.8 +#define PC_HVYWEAP_INITARMORTYPE 0.8 +#define PC_HVYWEAP_ARMORCLASSES 31 // ALL +#define PC_HVYWEAP_INITARMORCLASS 0 +#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN +#define PC_HVYWEAP_MAXAMMO_SHOT 200 +#define PC_HVYWEAP_MAXAMMO_NAIL 200 +#define PC_HVYWEAP_MAXAMMO_CELL 50 +#define PC_HVYWEAP_MAXAMMO_ROCKET 25 +#define PC_HVYWEAP_INITAMMO_SHOT 200 +#define PC_HVYWEAP_INITAMMO_NAIL 0 +#define PC_HVYWEAP_INITAMMO_CELL 30 +#define PC_HVYWEAP_INITAMMO_ROCKET 0 +#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_INIT_1 2 +#define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon + + + +// Class Details for PYRO +#define PC_PYRO_SKIN 21 +#define PC_PYRO_MAXHEALTH 100 +#define PC_PYRO_MAXSPEED 300 +#define PC_PYRO_MAXSTRAFESPEED 300 +#define PC_PYRO_MAXARMOR 150 +#define PC_PYRO_INITARMOR 50 +#define PC_PYRO_MAXARMORTYPE 0.6 +#define PC_PYRO_INITARMORTYPE 0.6 +#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE +#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN +#define PC_PYRO_MAXAMMO_SHOT 40 +#define PC_PYRO_MAXAMMO_NAIL 50 +#define PC_PYRO_MAXAMMO_CELL 200 +#define PC_PYRO_MAXAMMO_ROCKET 20 +#define PC_PYRO_INITAMMO_SHOT 20 +#define PC_PYRO_INITAMMO_NAIL 0 +#define PC_PYRO_INITAMMO_CELL 120 +#define PC_PYRO_INITAMMO_ROCKET 5 +#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_INIT_1 2 +#define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot + +// Class Details for SPY +#define PC_SPY_SKIN 22 +#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXSPEED 300 +#define PC_SPY_MAXSTRAFESPEED 300 +#define PC_SPY_MAXARMOR 100 +#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_SPY_INITARMORCLASS 0 +#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_MAXAMMO_SHOT 40 +#define PC_SPY_MAXAMMO_NAIL 100 +#define PC_SPY_MAXAMMO_CELL 30 +#define PC_SPY_MAXAMMO_ROCKET 15 +#define PC_SPY_INITAMMO_SHOT 40 +#define PC_SPY_INITAMMO_NAIL 50 +#define PC_SPY_INITAMMO_CELL 10 +#define PC_SPY_INITAMMO_ROCKET 0 +#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_INIT_1 2 +#define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_TF_ITEMS 0 +#define PC_SPY_CELL_REGEN_TIME 5 +#define PC_SPY_CELL_REGEN_AMOUNT 1 +#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible +#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover + +// Class Details for ENGINEER +#define PC_ENGINEER_SKIN 22 // Not used anymore +#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXSPEED 300 +#define PC_ENGINEER_MAXSTRAFESPEED 300 +#define PC_ENGINEER_MAXARMOR 50 +#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMORTYPE 0.6 +#define PC_ENGINEER_INITARMORTYPE 0.3 +#define PC_ENGINEER_ARMORCLASSES 31 // ALL +#define PC_ENGINEER_INITARMORCLASS 0 +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_MAXAMMO_SHOT 50 +#define PC_ENGINEER_MAXAMMO_NAIL 50 +#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal +#define PC_ENGINEER_MAXAMMO_ROCKET 30 +#define PC_ENGINEER_INITAMMO_SHOT 20 +#define PC_ENGINEER_INITAMMO_NAIL 25 +#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal +#define PC_ENGINEER_INITAMMO_ROCKET 0 +#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_INIT_1 2 +#define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_TF_ITEMS 0 + +// Class Details for CIVILIAN +#define PC_CIVILIAN_SKIN 22 +#define PC_CIVILIAN_MAXHEALTH 50 +#define PC_CIVILIAN_MAXSPEED 240 +#define PC_CIVILIAN_MAXSTRAFESPEED 240 +#define PC_CIVILIAN_MAXARMOR 0 +#define PC_CIVILIAN_INITARMOR 0 +#define PC_CIVILIAN_MAXARMORTYPE 0 +#define PC_CIVILIAN_INITARMORTYPE 0 +#define PC_CIVILIAN_ARMORCLASSES 0 +#define PC_CIVILIAN_INITARMORCLASS 0 +#define PC_CIVILIAN_WEAPONS WEAP_AXE +#define PC_CIVILIAN_MAXAMMO_SHOT 0 +#define PC_CIVILIAN_MAXAMMO_NAIL 0 +#define PC_CIVILIAN_MAXAMMO_CELL 0 +#define PC_CIVILIAN_MAXAMMO_ROCKET 0 +#define PC_CIVILIAN_INITAMMO_SHOT 0 +#define PC_CIVILIAN_INITAMMO_NAIL 0 +#define PC_CIVILIAN_INITAMMO_CELL 0 +#define PC_CIVILIAN_INITAMMO_ROCKET 0 +#define PC_CIVILIAN_GRENADE_TYPE_1 0 +#define PC_CIVILIAN_GRENADE_TYPE_2 0 +#define PC_CIVILIAN_GRENADE_INIT_1 0 +#define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_TF_ITEMS 0 + + +/*==========================================================================*/ +/* TEAMFORTRESS GOALS */ +/*==========================================================================*/ +// For all these defines, see the tfortmap.txt that came with the zip +// for complete descriptions. +// Defines for Goal Activation types : goal_activation (in goals) +#define TFGA_TOUCH 1 // Activated when touched +#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion +#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met +#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner +#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning + +// Defines for Goal Effects types : goal_effect +#define TFGE_AP 1 // AP is affected. Default. +#define TFGE_AP_TEAM 2 // All of the AP's team. +#define TFGE_NOT_AP_TEAM 4 // All except AP's team. +#define TFGE_NOT_AP 8 // All except AP. +#define TFGE_WALL 16 // If set, walls stop the Radius effects +#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected +#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects + +// Defines for Goal Result types : goal_result +#define TFGR_SINGLE 1 // Goal can only be activated once +#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses +#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level +#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results +#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy +#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point +#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys + +// Defines for Goal Group Result types : goal_group +// None! +// But I'm leaving this variable in there, since it's fairly likely +// that some will show up sometime. + +// Defines for Goal Item types, : goal_activation (in items) +#define TFGI_GLOW 1 // Players carrying this GoalItem will glow +#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed +#define TFGI_DROP 4 // Players dying with this item will drop it +#define TFGI_RETURN_DROP 8 // Return if a player with it dies +#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation +#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE +#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details +#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped +#define TFGI_KEEP 256 // Players keep this item even when they die +#define TFGI_ITEMGLOWS 512 // Item glows when on the ground +#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning +#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players +#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc + +// Defines for methods of GoalItem returning +#define GI_RET_DROP_DEAD 0 // Dropped by a dead player +#define GI_RET_DROP_LIVING 1 // Dropped by a living player +#define GI_RET_GOAL 2 // Returned by a Goal +#define GI_RET_TIME 3 // Returned due to timeout + +// Defines for TeamSpawnpoints : goal_activation (in teamspawns) +#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times +#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times + +// Defines for TeamSpawnpoints : goal_effects (in teamspawns) +#define TFSP_REMOVESELF 1 // Remove itself after being spawned on + +// Defines for Goal States +#define TFGS_ACTIVE 1 +#define TFGS_INACTIVE 2 +#define TFGS_REMOVED 3 +#define TFGS_DELAYED 4 + +// Defines for GoalItem Removing from Player Methods +#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player +#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal +#define GI_DROP_PLAYERDROP 2 // Dropped by a player + +// Legal Playerclass Handling +#define TF_ILL_SCOUT 1 +#define TF_ILL_SNIPER 2 +#define TF_ILL_SOLDIER 4 +#define TF_ILL_DEMOMAN 8 +#define TF_ILL_MEDIC 16 +#define TF_ILL_HVYWEP 32 +#define TF_ILL_PYRO 64 +#define TF_ILL_RANDOMPC 128 +#define TF_ILL_SPY 256 +#define TF_ILL_ENGINEER 512 + +// Addition classes +#define CLASS_TFGOAL 128 +#define CLASS_TFGOAL_TIMER 129 +#define CLASS_TFGOAL_ITEM 130 +#define CLASS_TFSPAWN 131 + +/*==========================================================================*/ +/* Flamethrower */ +/*==========================================================================*/ +#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player +#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) +#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade +#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player +#define FLAME_NUMLIGHTS 1 // maximum number of light flame +#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' +#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode +#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames +#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. +#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn +#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players + +/*==================================================*/ +/* CTF Support defines */ +/*==================================================*/ +#define CTF_FLAG1 1 +#define CTF_FLAG2 2 +#define CTF_DROPOFF1 3 +#define CTF_DROPOFF2 4 +#define CTF_SCORE1 5 +#define CTF_SCORE2 6 + +//.float hook_out; + +/*==================================================*/ +/* Camera defines */ +/*==================================================*/ +/* +float live_camera; +.float camdist; +.vector camangle; +.entity camera_list; +*/ + +/*==================================================*/ +/* QuakeWorld defines */ +/*==================================================*/ +/* +float already_chosen_map; + +// grappling hook variables +.entity hook; +.float on_hook; +.float fire_held_down;// flag - TRUE if player is still holding down the + // fire button after throwing a hook. +*/ +/*==================================================*/ +/* Server Settings */ +/*==================================================*/ +// Admin modes +#define ADMIN_MODE_NONE 0 +#define ADMIN_MODE_DEAL 1 + +/*==================================================*/ +/* Death Message defines */ +/*==================================================*/ +#define DMSG_SHOTGUN 1 +#define DMSG_SSHOTGUN 2 +#define DMSG_NAILGUN 3 +#define DMSG_SNAILGUN 4 +#define DMSG_GRENADEL 5 +#define DMSG_ROCKETL 6 +#define DMSG_LIGHTNING 7 +#define DMSG_GREN_HAND 8 +#define DMSG_GREN_NAIL 9 +#define DMSG_GREN_MIRV 10 +#define DMSG_GREN_PIPE 11 +#define DMSG_DETPACK 12 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 +#define DMSG_FLAME 15 +#define DMSG_DETPACK_DIS 16 +#define DMSG_AXE 17 +#define DMSG_SNIPERRIFLE 18 +#define DMSG_AUTORIFLE 19 +#define DMSG_ASSAULTCANNON 20 +#define DMSG_HOOK 21 +#define DMSG_BACKSTAB 22 +#define DMSG_MEDIKIT 23 +#define DMSG_GREN_GAS 24 +#define DMSG_TRANQ 25 +#define DMSG_LASERBOLT 26 +#define DMSG_SENTRYGUN_BULLET 27 +#define DMSG_SNIPERLEGSHOT 28 +#define DMSG_SNIPERHEADSHOT 29 +#define DMSG_GREN_EMP 30 +#define DMSG_GREN_EMP_AMMO 31 +#define DMSG_SPANNER 32 +#define DMSG_INCENDIARY 33 +#define DMSG_SENTRYGUN_ROCKET 34 +#define DMSG_GREN_FLASH 35 +#define DMSG_TRIGGER 36 +#define DMSG_MIRROR 37 +#define DMSG_SENTRYDEATH 38 +#define DMSG_DISPENSERDEATH 39 +#define DMSG_GREN_AIRPIPE 40 +#define DMSG_CALTROP 41 + +/*==================================================*/ +// TOGGLEFLAGS +/*==================================================*/ +// Some of the toggleflags aren't used anymore, but the bits are still +// there to provide compatability with old maps +#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit +#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit +#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit +//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE +#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade +#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE +#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE +#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. +#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore +#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set + // In a map. Cannot be toggled by players. +#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only +#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off +//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags +#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps +#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation + +#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only + +/*======================*/ +// Menu stuff // +/*======================*/ + +#define MENU_DEFAULT 1 +#define MENU_TEAM 2 +#define MENU_CLASS 3 +#define MENU_MAPBRIEFING 4 +#define MENU_INTRO 5 +#define MENU_CLASSHELP 6 +#define MENU_CLASSHELP2 7 +#define MENU_REPEATHELP 8 + +#define MENU_SPECHELP 9 + + +#define MENU_SPY 12 +#define MENU_SPY_SKIN 13 +#define MENU_SPY_COLOR 14 +#define MENU_ENGINEER 15 +#define MENU_ENGINEER_FIX_DISPENSER 16 +#define MENU_ENGINEER_FIX_SENTRYGUN 17 +#define MENU_ENGINEER_FIX_MORTAR 18 +#define MENU_DISPENSER 19 +#define MENU_CLASS_CHANGE 20 +#define MENU_TEAM_CHANGE 21 + +#define MENU_REFRESH_RATE 25 + +#define MENU_VOICETWEAK 50 + +//============================ +// Timer Types +#define TF_TIMER_ANY 0 +#define TF_TIMER_CONCUSSION 1 +#define TF_TIMER_INFECTION 2 +#define TF_TIMER_HALLUCINATION 3 +#define TF_TIMER_TRANQUILISATION 4 +#define TF_TIMER_ROTHEALTH 5 +#define TF_TIMER_REGENERATION 6 +#define TF_TIMER_GRENPRIME 7 +#define TF_TIMER_CELLREGENERATION 8 +#define TF_TIMER_DETPACKSET 9 +#define TF_TIMER_DETPACKDISARM 10 +#define TF_TIMER_BUILD 11 +#define TF_TIMER_CHECKBUILDDISTANCE 12 +#define TF_TIMER_DISGUISE 13 +#define TF_TIMER_DISPENSERREFILL 14 + +// Non Player timers +#define TF_TIMER_RETURNITEM 100 +#define TF_TIMER_DELAYEDGOAL 101 +#define TF_TIMER_ENDROUND 102 + +//============================ +// Teamscore printing +#define TS_PRINT_SHORT 1 +#define TS_PRINT_LONG 2 +#define TS_PRINT_LONG_TO_ALL 3 + +#ifndef TF_DEFS_ONLY + +typedef struct +{ + int topColor; + int bottomColor; +} team_color_t; + + +/*==================================================*/ +/* GLOBAL VARIABLES */ +/*==================================================*/ +// FortressMap stuff +extern float number_of_teams; // number of teams supported by the map +extern int illegalclasses[5]; // Illegal playerclasses for all teams +extern int civilianteams; // Bitfield holding Civilian teams +extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams + +extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams + +extern int teamscores[5]; // Goal Score of each team +extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers +extern int teamfrags[5]; // Total Frags for each team +extern int teamlives[5]; // Number of lives each team's players have +extern int teammaxplayers[5]; // Max number of players allowed in each team +extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set + // stores the damage ratio players take/give +extern int teamallies[5]; // Keeps track of which teams are allied +extern string_t team_names[5]; + +extern BOOL CTF_Map; +extern BOOL birthday; +extern BOOL christmas; + +extern float num_world_flames; + +// Clan Battle stuff +extern float clan_scores_dumped; +extern float cb_prematch_time; +extern float fOldPrematch; +extern float fOldCeaseFire; +extern float cb_ceasefire_time; +extern float last_id; +extern float spy_off; +extern float old_grens; +extern float flagem_checked; +extern float flNextEqualisationCalc; +extern BOOL cease_fire; +extern BOOL no_cease_fire_text; +extern BOOL initial_cease_fire; +extern BOOL last_cease_fire; +// Autokick stuff +extern float autokick_kills; + +extern float deathmsg; // Global, which is set before every T_Damage, to indicate + // the death message that should be used. + +extern char *sTeamSpawnNames[]; +extern char *sClassNames[]; +extern char *sNewClassModelFiles[]; +extern char *sOldClassModelFiles[]; +extern char *sClassModels[]; +extern char *sClassCfgs[]; +extern char *sGrenadeNames[]; +extern string_t team_menu_string; + +extern int toggleflags; // toggleable flags + +extern CBaseEntity* g_pLastSpawns[5]; +extern BOOL g_bFirstClient; + +extern float g_fNextPrematchAlert; + +typedef struct +{ + int ip; + edict_t *pEdict; +} ip_storage_t; + +extern ip_storage_t g_IpStorage[32]; + +class CGhost; +/*==========================================================================*/ +BOOL ClassIsRestricted(float tno, int pc); +char* GetTeamName(int tno); +int TeamFortress_GetNoPlayers(); +void DestroyBuilding(CBaseEntity *eng, char *bld); +void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); +float anglemod( float v ); + +// Team Funcs +BOOL TeamFortress_TeamIsCivilian(float tno); +void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); +BOOL TeamFortress_TeamPutPlayerInTeam(); +void TeamFortress_TeamSetColor(int tno); +void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); +int TeamFortress_TeamGetScoreFrags(int tno); +int TeamFortress_TeamGetNoPlayers(int tno); +float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); +BOOL IsSpawnPointValid( Vector &pos ); +BOOL TeamFortress_SortTeams( void ); +void DumpClanScores( void ); +void CalculateTeamEqualiser(); + +// mapscript funcs +void ParseTFServerSettings(); +void ParseTFMapSettings(); +CBaseEntity* Finditem(int ino); +CBaseEntity* Findgoal(int gno); +CBaseEntity* Findteamspawn(int gno); +void RemoveGoal(CBaseEntity *Goal); +void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); +void dremove( CBaseEntity *te ); +void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); +void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); +void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); +void tfgoalitem_checkgoalreturn(CBaseEntity *Item); +void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); +void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); +void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); +// hooks into the mapscript for all entities +BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); +BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); + +// prematch & ceasefire +void Display_Prematch(); +void Check_Ceasefire(); + +// admin +void KickPlayer( CBaseEntity *pTarget ); +void BanPlayer( CBaseEntity *pTarget ); +CGhost *FindGhost( int iGhostID ); +int GetBattleID( edict_t *pEntity ); + +extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) +extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. +extern cvar_t tfc_spam_limit; // at this many points, gag the spammer +extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; +extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; +extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; +extern cvar_t allow_spectators; + +/*==========================================================================*/ +class CTFFlame : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT FlameThink( void ); + static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); + void FlameDestroy( void ); + + float m_flNextDamageTime; +}; + +/*==========================================================================*/ +// MAPSCRIPT CLASSES +class CTFGoal : public CBaseAnimating +{ +public: + void Spawn( void ); + void StartGoal( void ); + void EXPORT PlaceGoal( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int Classify ( void ) { return CLASS_TFGOAL; } + + void SetObjectCollisionBox( void ); +}; + +class CTFGoalItem : public CTFGoal +{ +public: + void Spawn( void ); + void StartItem( void ); + void EXPORT PlaceItem( void ); + int Classify ( void ) { return CLASS_TFGOAL_ITEM; } + + float m_flDroppedAt; +}; + +class CTFTimerGoal : public CTFGoal +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL_TIMER; } +}; + +class CTFSpawn : public CBaseEntity +{ +public: + void Spawn( void ); + void Activate( void ); + int Classify ( void ) { return CLASS_TFSPAWN; } + BOOL CheckTeam( int iTeamNo ); + + EHANDLE m_pTeamCheck; +}; + +class CTFDetect : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL; } +}; + +class CTelefragDeath : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT DeathTouch( CBaseEntity *pOther ); +}; + +class CTeamCheck : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + BOOL TeamMatches( int iTeam ); +}; + +class CTeamSet : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +#endif // TF_DEFS_ONLY +#endif // __TF_DEFS_H + + diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp new file mode 100644 index 00000000..d16a1046 --- /dev/null +++ b/cl_dll/train.cpp @@ -0,0 +1,85 @@ +/*** +* +* 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. +* +****/ +// +// Train.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Train, Train ) + + +int CHudTrain::Init(void) +{ + HOOK_MESSAGE( Train ); + + m_iPos = 0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int CHudTrain::VidInit(void) +{ + m_hSprite = 0; + + return 1; +}; + +int CHudTrain::Draw(float fTime) +{ + if ( !m_hSprite ) + m_hSprite = LoadSprite("sprites/%d_train.spr"); + + if (m_iPos) + { + int r, g, b, x, y; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + SPR_Set(m_hSprite, r, g, b ); + + // This should show up to the right and part way up the armor number + y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; + x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4; + + SPR_DrawAdditive( m_iPos - 1, x, y, NULL); + + } + + return 1; +} + + +int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update Train data + m_iPos = READ_BYTE(); + + if (m_iPos) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp new file mode 100644 index 00000000..02be4ef4 --- /dev/null +++ b/cl_dll/tri.cpp @@ -0,0 +1,128 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Triangle rendering, if any + +#include "hud.h" +#include "cl_util.h" + +// Triangle rendering apis are in gEngfuncs.pTriAPI + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "triangleapi.h" + +#ifdef _WIN32 +#define DLLEXPORT __declspec( dllexport ) +#else +#define DLLEXPORT +#endif + +extern "C" +{ + void DLLEXPORT HUD_DrawNormalTriangles( void ); + void DLLEXPORT HUD_DrawTransparentTriangles( void ); +}; + +//#define TEST_IT +#if defined( TEST_IT ) + +/* +================= +Draw_Triangles + +Example routine. Draws a sprite offset from the player origin. +================= +*/ +void Draw_Triangles( void ) +{ + cl_entity_t *player; + vec3_t org; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + org = player->origin; + + org.x += 50; + org.y += 50; + + if (gHUD.m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + gHUD.m_hsprCursor = SPR_Load( sz ); + } + + if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) + { + return; + } + + // Create a triangle, sigh + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + // Overload p->color with index into tracer palette, p->packedColor with brightness + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + // UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); + + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +} + +#endif + +/* +================= +HUD_DrawNormalTriangles + +Non-transparent triangles-- add them here +================= +*/ +void DLLEXPORT HUD_DrawNormalTriangles( void ) +{ + + gHUD.m_Spectator.DrawOverview(); + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} + +/* +================= +HUD_DrawTransparentTriangles + +Render any triangles with transparent rendermode needs here +================= +*/ +void DLLEXPORT HUD_DrawTransparentTriangles( void ) +{ + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} \ No newline at end of file diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp new file mode 100644 index 00000000..69d8871c --- /dev/null +++ b/cl_dll/util.cpp @@ -0,0 +1,133 @@ +/*** +* +* 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 +// +// implementation of class-less helper functions +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern vec3_t vec3_origin; + +double sqrt(double x); + +float Length(const float *v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +void VectorAngles( const float *forward, float *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; +} + +float VectorNormalize (float *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 ( float *v ) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (const float *in, float scale, float *out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + +HSPRITE LoadSprite(const char *pszName) +{ + int i; + char sz[256]; + + if (ScreenWidth < 640) + i = 320; + else + i = 640; + + sprintf(sz, pszName, i); + + return SPR_Load(sz); +} + diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h new file mode 100644 index 00000000..0e2aaaa3 --- /dev/null +++ b/cl_dll/util_vector.h @@ -0,0 +1,121 @@ +/*** +* +* 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. +* +****/ +// Vector.h +// A subset of the extdll.h in the project HL Entity DLL +// + +// 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 func_t; // +typedef int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +//========================================================= +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +//========================================================= +class Vector2D +{ +public: + inline Vector2D(void) { } + inline Vector2D(float X, float Y) { 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 (float)sqrt(x*x + y*y ); } + + inline Vector2D Normalize ( void ) const + { + Vector2D vec2; + + float flLen = Length(); + if ( flLen == 0 ) + { + return Vector2D( (float)0, (float)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) { } + inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { 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 (float)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 (float)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 ); } + +#define vec3_t Vector diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp new file mode 100644 index 00000000..d547496e --- /dev/null +++ b/cl_dll/view.cpp @@ -0,0 +1,1693 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// view/refresh setup functions + +#include "hud.h" +#include "cl_util.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" + +#include "entity_state.h" +#include "cl_entity.h" +#include "ref_params.h" +#include "in_defs.h" // PITCH YAW ROLL +#include "pm_movevars.h" +#include "pm_shared.h" +#include "pm_defs.h" +#include "event_api.h" +#include "pmtrace.h" +#include "screenfade.h" +#include "shake.h" +#include "hltv.h" + +// Spectator Mode +extern "C" +{ + float vecNewViewAngles[3]; + int iHasNewViewAngles; + float vecNewViewOrigin[3]; + int iHasNewViewOrigin; + int iIsSpectator; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern "C" +{ + int CL_IsThirdPerson( void ); + void CL_CameraOffset( float *ofs ); + + void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); + + void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); + int PM_GetVisEntInfo( int ent ); + int PM_GetPhysEntInfo( int ent ); + void InterpolateAngles( float * start, float * end, float * output, float frac ); + void NormalizeAngles( float * angles ); + float Distance(const float * v1, const float * v2); + float AngleBetweenVectors( const float * v1, const float * v2 ); + + float vJumpOrigin[3]; + float vJumpAngles[3]; +} + +void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void VectorAngles( const float *forward, float *angles ); + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +/* +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. +*/ + +extern cvar_t *cl_forwardspeed; +extern cvar_t *chase_active; +extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; +extern cvar_t *cl_vsmoothing; + +#define CAM_MODE_RELAX 1 +#define CAM_MODE_FOCUS 2 + +vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; +float v_frametime, v_lastDistance; +float v_cameraRelaxAngle = 5.0f; +float v_cameraFocusAngle = 35.0f; +int v_cameraMode = CAM_MODE_FOCUS; +qboolean v_resetCamera = 1; + +vec3_t ev_punchangle; + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + +cvar_t *cl_bobcycle; +cvar_t *cl_bob; +cvar_t *cl_bobup; +cvar_t *cl_waterdist; +cvar_t *cl_chasedist; + +// These cvars are not registered (so users can't cheat), so set the ->value field directly +// Register these cvars in V_Init() if needed for easy tweaking +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; + +float v_idlescale; // used by TFC for concussion grenade effect + +//============================================================================= +/* +void V_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; + } + } +} + +/* +=================== +V_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 V_InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + V_NormalizeAngles( start ); + V_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; + } + + V_NormalizeAngles( output ); +} */ + +// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear +float V_CalcBob ( struct ref_params_s *pparams ) +{ + static double bobtime; + static float bob; + float cycle; + static float lasttime; + vec3_t vel; + + + if ( pparams->onground == -1 || + pparams->time == lasttime ) + { + // just use old value + return bob; + } + + lasttime = pparams->time; + + bobtime += pparams->frametime; + cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + + if ( cycle < cl_bobup->value ) + { + cycle = M_PI * cycle / cl_bobup->value; + } + else + { + cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); + } + + // bob is proportional to simulated velocity in the xy plane + // (don't count Z, or jumping messes it up) + VectorCopy( pparams->simvel, vel ); + vel[2] = 0; + + bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; + bob = bob * 0.3 + bob * 0.7 * sin(cycle); + bob = min( bob, 4 ); + bob = max( bob, -7 ); + return bob; + +} + +/* +=============== +V_CalcRoll +Used by view and sv_user +=============== +*/ +float V_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; +} + +typedef struct pitchdrift_s +{ + float pitchvel; + int nodrift; + float driftmove; + double laststop; +} pitchdrift_t; + +static pitchdrift_t pd; + + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. +=============== +*/ + +/* +============================================================================== + VIEW RENDERING +============================================================================== +*/ + +/* +================== +V_CalcGunAngle +================== +*/ +void V_CalcGunAngle ( struct ref_params_s *pparams ) +{ + cl_entity_t *viewent; + + viewent = gEngfuncs.GetViewModel(); + if ( !viewent ) + return; + + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; + viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. + viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); + viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle ( struct ref_params_s *pparams ) +{ + pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll ( struct ref_params_s *pparams ) +{ + float side; + cl_entity_t *viewentity; + + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( !viewentity ) + return; + + side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + + pparams->viewangles[ROLL] += side; + + if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + { + // only roll the view if the player is dead and the viewheight[2] is nonzero + // this is so deadcam in multiplayer will work. + pparams->viewangles[ROLL] = 80; // dead view angle + return; + } +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + float old; + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + VectorCopy ( pparams->simorg, pparams->vieworg ); + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + view->model = NULL; + + // allways idle in intermission + old = v_idlescale; + v_idlescale = 1; + + V_AddIdle ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV we must go to 'intermission' position by ourself + VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); + VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); + } + + v_idlescale = old; + + v_cl_angles = pparams->cl_viewangles; + v_origin = pparams->vieworg; + v_angles = pparams->viewangles; +} + +#define ORIGIN_BACKUP 64 +#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) + +typedef struct +{ + float Origins[ ORIGIN_BACKUP ][3]; + float OriginTime[ ORIGIN_BACKUP ]; + + float Angles[ ORIGIN_BACKUP ][3]; + float AngleTime[ ORIGIN_BACKUP ]; + + int CurrentOrigin; + int CurrentAngle; +} viewinterp_t; + +/* +================== +V_CalcRefdef + +================== +*/ +void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + vec3_t camAngles, camForward, camRight, camUp; + cl_entity_t *pwater; + + if ( gEngfuncs.IsSpectateOnly() ) + { + ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + } + else + { + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + } + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // transform the view offset by the model's matrix to get the offset from + // model origin for the view + bob = V_CalcBob ( pparams ); + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += ( bob ); + VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + // never let view origin sit exactly on a node line, because a water plane can + // dissapear when viewed with the eye exactly on it. + // FIXME, we send origin at 1/128 now, change this? + // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + + pparams->vieworg[0] += 1.0/32; + pparams->vieworg[1] += 1.0/32; + pparams->vieworg[2] += 1.0/32; + + // Check for problems around water, move the viewer artificially if necessary + // -- this prevents drawing errors in GL due to waves + + waterOffset = 0; + if ( pparams->waterlevel >= 2 ) + { + int i, contents, waterDist, waterEntity; + vec3_t point; + waterDist = cl_waterdist->value; + + if ( pparams->hardware ) + { + waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); + if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + { + pwater = gEngfuncs.GetEntityByIndex( waterEntity ); + if ( pwater && ( pwater->model != NULL ) ) + { + waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height + } + } + } + else + { + waterEntity = 0; // Don't need this in software + } + + VectorCopy( pparams->vieworg, point ); + + // Eyes are above water, make sure we're above the waves + if ( pparams->waterlevel == 2 ) + { + point[2] -= waterDist; + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents > CONTENTS_WATER ) + break; + point[2] += 1; + } + waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + } + else + { + // eyes are under water. Make sure we're far enough under + point[2] += waterDist; + + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents <= CONTENTS_WATER ) + break; + point[2] -= 1; + } + waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + } + } + + pparams->vieworg[2] += waterOffset; + + V_CalcViewRoll ( pparams ); + + V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + // don't allow cheats in multiplayer + if ( pparams->maxclients <= 1 ) + { + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + } + + // Treating cam_ofs[2] as the distance + if( CL_IsThirdPerson() ) + { + vec3_t ofs; + + ofs[0] = ofs[1] = ofs[2] = 0.0; + + CL_CameraOffset( (float *)&ofs ); + + VectorCopy( ofs, camAngles ); + camAngles[ ROLL ] = 0; + + AngleVectors( camAngles, camForward, camRight, camUp ); + + for ( i = 0; i < 3; i++ ) + { + pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + } + } + + // Give gun our viewangles + VectorCopy ( pparams->cl_viewangles, view->angles ); + + // set up gun position + V_CalcGunAngle ( pparams ); + + // Use predicted origin as view origin. + VectorCopy ( pparams->simorg, view->origin ); + view->origin[2] += ( waterOffset ); + VectorAdd( view->origin, pparams->viewheight, view->origin ); + + // Let the viewmodel shake at about 10% of the amplitude + gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); + + for ( i = 0; i < 3; i++ ) + { + view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + } + view->origin[2] += bob; + + // throw in a little tilt. + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; + view->angles[PITCH] -= bob * 0.3; + + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the + // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem + // with view model distortion, this may be a cause. (SJB). + view->origin[2] -= 1; + + // fudge position around to keep amount of weapon visible + // roughly equal with different FOV + if (pparams->viewsize == 110) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 100) + { + view->origin[2] += 2; + } + else if (pparams->viewsize == 90) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 80) + { + view->origin[2] += 0.5; + } + + // Add in the punchangle, if any + VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + + // Include client side punch, too + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + + V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + v_lastAngles = pparams->viewangles; +// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! + if ( CL_IsThirdPerson() ) + { + VectorCopy( camAngles, pparams->viewangles); + float pitch = camAngles[ 0 ]; + + // Normalize angles + if ( pitch > 180 ) + pitch -= 360.0; + else if ( pitch < -180 ) + pitch += 360; + + // Player pitch is inverted + pitch /= -3.0; + + // Slam local player's pitch value + ent->angles[ 0 ] = pitch; + ent->curstate.angles[ 0 ] = pitch; + ent->prevstate.angles[ 0 ] = pitch; + ent->latched.prevangles[ 0 ] = pitch; + } + + // override all previous settings if the viewent isn't the client + if ( pparams->viewentity > pparams->maxclients ) + { + cl_entity_t *viewentity; + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( viewentity ) + { + VectorCopy( viewentity->origin, pparams->vieworg ); + VectorCopy( viewentity->angles, pparams->viewangles ); + + // Store off overridden viewangles + v_angles = pparams->viewangles; + } + } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; +} + +void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) +{ + float absd,frac,d,threshhold; + + NormalizeAngles( startAngle ); + NormalizeAngles( endAngle ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = endAngle[i] - startAngle[i]; + + if ( d > 180.0f ) + { + d -= 360.0f; + } + else if ( d < -180.0f ) + { + d += 360.0f; + } + + absd = fabs(d); + + if ( absd > 0.01f ) + { + frac = degreesPerSec * v_frametime; + + threshhold= degreesPerSec / 4; + + if ( absd < threshhold ) + { + float h = absd / threshhold; + h *= h; + frac*= h; // slow down last degrees + } + + if ( frac > absd ) + { + finalAngle[i] = endAngle[i]; + } + else + { + if ( d>0) + finalAngle[i] = startAngle[i] + frac; + else + finalAngle[i] = startAngle[i] - frac; + } + } + else + { + finalAngle[i] = endAngle[i]; + } + + } + + NormalizeAngles( finalAngle ); +} + +// Get the origin of the Observer based around the target's position and angles +void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) +{ + vec3_t vecEnd; + vec3_t forward; + vec3_t vecStart; + pmtrace_t * trace; + int maxLoops = 8; + + int ignoreent = -1; // first, ignore no entity + + cl_entity_t * ent = NULL; + + // Trace back from the target using the player's view angles + AngleVectors(angles, forward, NULL, NULL); + + VectorScale(forward,-1,forward); + + VectorCopy( origin, vecStart ); + + VectorMA(vecStart, distance , forward, vecEnd); + + while ( maxLoops > 0) + { + trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); + + // WARNING! trace->ent is is the number in physent list not the normal entity number + + if ( trace->ent <= 0) + break; // we hit the world or nothing, stop trace + + ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); + + if ( ent == NULL ) + break; + + // hit non-player solid BSP , stop here + if ( ent->curstate.solid == SOLID_BSP && !ent->player ) + break; + + // if close enought to end pos, stop, otherwise continue trace + if( Distance(trace->endpos, vecEnd ) < 1.0f ) + { + break; + } + else + { + ignoreent = trace->ent; // ignore last hit entity + VectorCopy( trace->endpos, vecStart); + } + + maxLoops--; + } + +/* if ( ent ) + { + gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); + } */ + + VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); + + v_lastDistance = Distance(trace->endpos, origin); // real distance without offset +} + +/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + float distance = 168.0f; + + v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back + + if ( v_resetCamera ) + v_lastDistance = 64.0f; + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + + // get new angle towards second target + if ( ent2 ) + { + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + } + else + { + // if no second target is given, look down to dead player + newAngle[0] = 90.0f; + newAngle[1] = 0.0f; + newAngle[2] = 0; + } + + // and smooth view + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + + VectorCopy(angle, v_lastAngles); +}*/ + +void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + // see is target is a dead player + qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + else if ( deadPlayer ) + distance*=1.5f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + { + if ( deadPlayer ) + newOrigin[2]+= 2; //laying on ground + else + newOrigin[2]+= 17; // head level of living player + + } + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // we have no second target, choose view direction based on + // show front of primary target + VectorCopy(ent1->angles, newAngle); + + // show dead players from front, normal players back + if ( flags & DRC_FLAG_FACEPLAYER ) + newAngle[1]+= 180.0f; + + + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + // if final scene (bomb), show from real high pos + if ( flags & DRC_FLAG_FINAL ) + newAngle[0] = 22.5f; + + // choose side of object/player + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + // HACK, if player is dead don't clip against his dead body, can't check this + V_GetChaseOrigin( angle, newOrigin, distance, origin ); +} + +float MaxAngleBetweenAngles( float * a1, float * a2 ) +{ + float d, maxd = 0.0f; + + NormalizeAngles( a1 ); + NormalizeAngles( a2 ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = a2[i] - a1[i]; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + d = fabs(d); + + if ( d > maxd ) + maxd=d; + } + + return maxd; +} + +void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; float tempVec[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // get new angle towards second target + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + + // set angle diffrent in Dramtaic scenes + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); + + if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) + { + // difference is to small and we are in relax camera mode, keep viewangles + VectorCopy(v_lastAngles, newAngle ); + } + else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) + { + // we catched up with our target, relax again + v_cameraMode = CAM_MODE_RELAX; + } + else + { + // target move too far away, focus camera again + v_cameraMode = CAM_MODE_FOCUS; + } + + // and smooth view, if not a scene cut + if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) + { + VectorCopy( newAngle, angle ); + } + else + { + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); + } + + V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); + + // move position up, if very close at target + if ( v_lastDistance < 64.0f ) + origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); + + // calculate angle to second target + VectorSubtract( ent2->origin, origin, tempVec ); + VectorAngles( tempVec, tempVec ); + tempVec[0] = -tempVec[0]; + + /* take middle between two viewangles + InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ + + + +} + +void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + + if ( v_resetCamera ) + { + v_lastDistance = 4096.0f; + // v_cameraMode = CAM_MODE_FOCUS; + } + + if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) + { + // we have no second target or player just died + V_GetSingleTargetCam(ent1, angle, origin); + } + else if ( ent2 ) + { + // keep both target in view + V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); + } + else + { + // second target disappeard somehow (dead) + + // keep last good viewangle + float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + } + + VectorCopy(angle, v_lastAngles); +} + +void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) +{ + cl_entity_t * ent = NULL; + + if ( target ) + { + ent = gEngfuncs.GetEntityByIndex( target ); + }; + + if (!ent) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + } + + + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + if ( g_iUser3 ) + V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), + angles, origin ); + else + V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, + angles, origin ); + } + else + { + if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) + { + VectorCopy ( ent->angles, angles); + angles[0]*=-1; + } + else + VectorCopy ( cl_angles, angles); + + + VectorCopy ( ent->origin, origin); + + origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset + + V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); + } + + v_resetCamera = false; +} + +void V_ResetChaseCam() +{ + v_resetCamera = true; +} + + +void V_GetInEyePos(int target, float * origin, float * angles ) +{ + if ( !target) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + }; + + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( !ent ) + return; + + VectorCopy ( ent->origin, origin ); + VectorCopy ( ent->angles, angles ); + + angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + + if ( ent->curstate.solid == SOLID_NOT ) + { + angles[ROLL] = 80; // dead view angle + origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + } + else if (ent->curstate.usehull == 1 ) + origin[2]+= 12; // VEC_DUCK_VIEW; + else + // exacty eye position can't be caluculated since it depends on + // client values like cl_bobcycle, this offset matches the default values + origin[2]+= 28; // DEFAULT_VIEWHEIGHT +} + +void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) +{ + vec3_t forward; + vec3_t zScaledTarget; + + VectorCopy(cl_angles, angles); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; + zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; + zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); + + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); +} + +void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) +{ + vec3_t forward; + + if ( target ) + { + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + // this is done to get the angles made by director mode + V_GetChasePos(target, cl_angles, origin, angles); + VectorCopy(ent->origin, origin); + + // keep fix chase angle horizontal + angles[0] = 45.0f; + } + else + { + VectorCopy(cl_angles, angles); + VectorCopy(ent->origin, origin); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + } + else + { + // keep out roaming position, but modify angles + VectorCopy(cl_angles, angles); + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + + origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); + angles[2] = 0.0f; // don't roll angle (if chased player is dead) + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(origin, -1536, forward, origin); +} + +int V_FindViewModelByWeaponModel(int weaponindex) +{ + + static char * modelmap[][2] = { + { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, + { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, + { "models/p_egon.mdl", "models/v_egon.mdl" }, + { "models/p_gauss.mdl", "models/v_gauss.mdl" }, + { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, + { "models/p_grenade.mdl", "models/v_grenade.mdl" }, + { "models/p_hgun.mdl", "models/v_hgun.mdl" }, + { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, + { "models/p_357.mdl", "models/v_357.mdl" }, + { "models/p_rpg.mdl", "models/v_rpg.mdl" }, + { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, + { "models/p_squeak.mdl", "models/v_squeak.mdl" }, + { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, + { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, + { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { NULL, NULL } }; + + struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); + + if ( weaponModel ) + { + int len = strlen( weaponModel->name ); + int i = 0; + + while ( modelmap[i] != NULL ) + { + if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) + { + return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); + } + i++; + } + + return 0; + } + else + return 0; + +} + + +/* +================== +V_CalcSpectatorRefdef + +================== +*/ +void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) +{ + static vec3_t velocity ( 0.0f, 0.0f, 0.0f); + + static int lastWeaponModelIndex = 0; + static int lastViewModelIndex = 0; + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + + pparams->onlyClientDraw = false; + + // refresh position + VectorCopy ( pparams->simorg, v_sim_org ); + + // get old values + VectorCopy ( pparams->cl_viewangles, v_cl_angles ); + VectorCopy ( pparams->viewangles, v_angles ); + VectorCopy ( pparams->vieworg, v_origin ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) + { + // calculate player velocity + float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; + + if ( timeDiff > 0 ) + { + vec3_t distance; + VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); + VectorScale(distance, 1/timeDiff, distance ); + + velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; + velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; + velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; + + VectorCopy(velocity, pparams->simvel); + } + + // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) + if ( gEngfuncs.IsSpectateOnly() ) + { + V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); + + pparams->health = 1; + + cl_entity_t * gunModel = gEngfuncs.GetViewModel(); + + if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) + { + // weapon model changed + + lastWeaponModelIndex = ent->curstate.weaponmodel; + lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); + if ( lastViewModelIndex ) + { + gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation + } + else + { + // model not found + gunModel->model = NULL; // disable weapon model + lastWeaponModelIndex = lastViewModelIndex = 0; + } + } + + if ( lastViewModelIndex ) + { + gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); + gunModel->curstate.modelindex = lastViewModelIndex; + gunModel->curstate.frame = 0; + gunModel->curstate.colormap = 0; + gunModel->index = g_iUser2; + } + else + { + gunModel->model = NULL; // disable weaopn model + } + } + else + { + // only get viewangles from entity + VectorCopy ( ent->angles, pparams->cl_viewangles ); + pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + } + } + + v_frametime = pparams->frametime; + + if ( pparams->nextView == 0 ) + { + // first renderer cycle, full screen + + switch ( g_iUser1 ) + { + case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + break; + + case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case OBS_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case OBS_MAP_CHASE : pparams->onlyClientDraw = true; + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + } + + if ( gHUD.m_Spectator.m_pip->value ) + pparams->nextView = 1; // force a second renderer view + + gHUD.m_Spectator.m_iDrawCycle = 0; + + } + else + { + // second renderer cycle, inset window + + // set inset parameters + pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window + pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); + pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); + pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); + pparams->nextView = 0; // on further view + + // override some settings in certain modes + switch ( (int)gHUD.m_Spectator.m_pip->value ) + { + case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case INSET_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case INSET_MAP_CHASE : pparams->onlyClientDraw = true; + + if ( g_iUser1 == OBS_ROAMING ) + V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); + else + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + + break; + } + + gHUD.m_Spectator.m_iDrawCycle = 1; + } + + // write back new values into pparams + VectorCopy ( v_cl_angles, pparams->cl_viewangles ); + VectorCopy ( v_angles, pparams->viewangles ) + VectorCopy ( v_origin, pparams->vieworg ); + +} + + + +void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) +{ + // intermission / finale rendering + if ( pparams->intermission ) + { + V_CalcIntermissionRefdef ( pparams ); + } + else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode + { + V_CalcSpectatorRefdef ( pparams ); + } + else if ( !pparams->paused ) + { + V_CalcNormalRefdef ( pparams ); + } + +/* +// Example of how to overlay the whole screen with red at 50 % alpha +#define SF_TEST +#if defined SF_TEST + { + screenfade_t sf; + gEngfuncs.pfnGetScreenFade( &sf ); + + sf.fader = 255; + sf.fadeg = 0; + sf.fadeb = 0; + sf.fadealpha = 128; + sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; + + gEngfuncs.pfnSetScreenFade( &sf ); + } +#endif +*/ +} + +/* +============= +V_DropPunchAngle + +============= +*/ +void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +{ + float len; + + len = VectorNormalize ( ev_punchangle ); + len -= (10.0 + len * 0.5) * frametime; + len = max( len, 0.0 ); + VectorScale ( ev_punchangle, len, ev_punchangle ); +} + +/* +============= +V_PunchAxis + +Client side punch effect +============= +*/ +void V_PunchAxis( int axis, float punch ) +{ + ev_punchangle[ axis ] = punch; +} + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); + + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); + cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); +} + + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern float in_fov; +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + fov_x = 90; // error, set to 90 + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; + + return a; +} + +int hitent = -1; + +void V_Move( int mx, int my ) +{ + float fov; + float fx, fy; + float dx, dy; + float c_x, c_y; + float dX, dY; + vec3_t forward, up, right; + vec3_t newangles; + + vec3_t farpoint; + pmtrace_t tr; + + fov = CalcFov( in_fov, (float)ScreenWidth, (float)ScreenHeight ); + + c_x = (float)ScreenWidth / 2.0; + c_y = (float)ScreenHeight / 2.0; + + dx = (float)mx - c_x; + dy = (float)my - c_y; + + // Proportion we moved in each direction + fx = dx / c_x; + fy = dy / c_y; + + dX = fx * in_fov / 2.0 ; + dY = fy * fov / 2.0; + + newangles = v_angles; + + newangles[ YAW ] -= dX; + newangles[ PITCH ] += dY; + + // Now rotate v_forward around that point + AngleVectors ( newangles, forward, right, up ); + + farpoint = v_origin + 8192 * forward; + + // Trace + tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + if ( tr.fraction != 1.0 && tr.ent != 0 ) + { + hitent = PM_GetPhysEntInfo( tr.ent ); + PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); + } + else + { + hitent = -1; + } +} + +#endif diff --git a/cl_dll/view.h b/cl_dll/view.h new file mode 100644 index 00000000..acd0bfb0 --- /dev/null +++ b/cl_dll/view.h @@ -0,0 +1,15 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( VIEWH ) +#define VIEWH +#pragma once + +void V_StartPitchDrift( void ); +void V_StopPitchDrift( void ); + +#endif // !VIEWH \ No newline at end of file diff --git a/cl_dll/wrect.h b/cl_dll/wrect.h new file mode 100644 index 00000000..620b8163 --- /dev/null +++ b/cl_dll/wrect.h @@ -0,0 +1,16 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( WRECTH ) +#define WRECTH + +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; + +#endif \ No newline at end of file diff --git a/common/beamdef.h b/common/beamdef.h new file mode 100644 index 00000000..ebb2a525 --- /dev/null +++ b/common/beamdef.h @@ -0,0 +1,60 @@ +/*** +* +* 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 BEAMDEF_H +#define BEAMDEF_H + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +typedef struct beam_s BEAM; +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + +#endif//BEAMDEF_H \ No newline at end of file diff --git a/common/bspfile.h b/common/bspfile.h new file mode 100644 index 00000000..c06eae6a --- /dev/null +++ b/common/bspfile.h @@ -0,0 +1,246 @@ +/* +bspfile.h - BSP format included q1, hl1 support +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef BSPFILE_H +#define BSPFILE_H + +/* +============================================================================== + +BRUSH MODELS + +.bsp contain level static geometry with including PVS and lightning info +============================================================================== +*/ + +// header +#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28) +#define HLBSP_VERSION 30 // half-life regular version +#define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit + +#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH" +#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT + +#define DELUXEMAP_VERSION 1 +#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT" + +// worldcraft predefined angles +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +// bmodel limits +#define MAX_MAP_HULLS 4 // MAX_HULLS + +#define SURF_NOCULL BIT( 0 ) // two-sided polygon (e.g. 'water4b') +#define SURF_PLANEBACK BIT( 1 ) // plane should be negated +#define SURF_DRAWSKY BIT( 2 ) // sky surface +#define SURF_WATERCSG BIT( 3 ) // culled by csg (was SURF_DRAWSPRITE) +#define SURF_DRAWTURB BIT( 4 ) // warp surface +#define SURF_DRAWTILED BIT( 5 ) // face without lighmap +#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND) +#define SURF_UNDERWATER BIT( 7 ) // caustics +#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP) + +#define SURF_REFLECT BIT( 31 ) // reflect surface (mirror) + +// lightstyle management +#define LM_STYLES 4 // MAXLIGHTMAPS +#define LS_NORMAL 0x00 +#define LS_UNUSED 0xFE +#define LS_NONE 0xFF + +#define MAX_MAP_MODELS 1024 // can be increased up to 2048 if needed +#define MAX_MAP_BRUSHES 32768 // unsigned short limit +#define MAX_MAP_ENTITIES 8192 // can be increased up to 32768 if needed +#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough +#define MAX_MAP_PLANES 65536 // can be increased without problems +#define MAX_MAP_NODES 32767 // because negative shorts are leafs +#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents +#define MAX_MAP_LEAFS 32767 // signed short limit +#define MAX_MAP_VERTS 65535 // unsigned short limit +#define MAX_MAP_FACES 65535 // unsigned short limit +#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit +#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo +#define MAX_MAP_EDGES 0x100000 // can be increased but not needed +#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed +#define MAX_MAP_TEXTURES 2048 // can be increased but not needed +#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data +#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps) +#define MAX_MAP_VISIBILITY 0x800000 // 8 Mb visdata + +// quake lump ordering +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 // internal textures +#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 // internal submodels +#define HEADER_LUMPS 15 + +// version 31 +#define LUMP_CLIPNODES2 15 // hull0 goes into LUMP_NODES, hull1 goes into LUMP_CLIPNODES, +#define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3 +#define HEADER_LUMPS_31 17 + +#define LUMP_FACES_EXTRADATA 0 // extension of dface_t +#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t +#define LUMP_CUBEMAPS 2 // cubemap description + +#define EXTRA_LUMPS 8 // g-cont. just for future expansions + +// texture flags +#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision + +// ambient sound types +enum +{ + AMBIENT_WATER = 0, // waterfall + AMBIENT_SKY, // wind + AMBIENT_SLIME, // never used in quake + AMBIENT_LAVA, // never used in quake + NUM_AMBIENTS, // automatic ambient sounds +}; + +// +// BSP File Structures +// + +typedef struct +{ + int fileofs; + int filelen; +} dlump_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS_31]; +} dheader31_t; + +typedef struct +{ + int id; // must be little endian XASH + int version; + dlump_t lumps[EXTRA_LUMPS]; +} dextrahdr_t; + +typedef struct +{ + vec3_t mins; + vec3_t maxs; + vec3_t origin; // for sounds or lights + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface; + int numfaces; +} dmodel_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +typedef struct +{ + vec3_t point; +} dvertex_t; + +typedef struct +{ + vec3_t normal; + float dist; + int type; // PLANE_X - PLANE_ANYZ ? +} dplane_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs + 1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + word firstface; + word numfaces; // counting both sides +} dnode_t; + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + word firstmarksurface; + word nummarksurfaces; + + // automatic ambient sounds + byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255) +} dleaf_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +typedef struct +{ + float vecs[2][4]; // texmatrix [s/t][xyz offset] + int miptex; + int flags; +} dtexinfo_t; + +typedef word dmarkface_t; // leaf marksurfaces indexes +typedef int dsurfedge_t; // map surfedges + +// NOTE: that edge 0 is never used, because negative edge nums +// are used for counterclockwise use of the edge in a face +typedef struct +{ + word v[2]; // vertex numbers +} dedge_t; + +typedef struct +{ + word planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + + // lighting info + byte styles[LM_STYLES]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +#endif//BSPFILE_H \ No newline at end of file diff --git a/common/cl_entity.h b/common/cl_entity.h new file mode 100644 index 00000000..533106b8 --- /dev/null +++ b/common/cl_entity.h @@ -0,0 +1,105 @@ +/*** +* +* 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 CL_ENTITY_H +#define CL_ENTITY_H + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + +#include "entity_state.h" +#include "event_args.h" + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[HISTORY_MAX]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + +#endif//CL_ENTITY_H \ No newline at end of file diff --git a/common/com_model.h b/common/com_model.h new file mode 100644 index 00000000..7ad79c91 --- /dev/null +++ b/common/com_model.h @@ -0,0 +1,413 @@ +/* +com_model.h - cient model structures +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef COM_MODEL_H +#define COM_MODEL_H + +#include "bspfile.h" // we need some declarations from it + +typedef vec_t vec2_t[2]; +typedef vec_t vec4_t[4]; + +/* +============================================================================== + + ENGINE MODEL FORMAT +============================================================================== +*/ +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +#define ZISCALE ((float)0x8000) + +#define MIPLEVELS 4 +#define VERTEXSIZE 7 +#define MAXLIGHTMAPS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// model types +typedef enum +{ + mod_bad = -1, + mod_brush, + mod_sprite, + mod_alias, + mod_studio +} modtype_t; + +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for 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 int width, height; + int gl_texturenum; + struct msurface_s *texturechain; // for gl_texsort drawing + 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 short fb_texturenum; // auto-luma texturenum + unsigned short dt_texturenum; // detail-texture binding + unsigned int unused[3]; // reserved +} 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; + +// 73 bytes per VBO vertex +// FIXME: align to 32 bytes +typedef struct glvert_s +{ + vec3_t vertex; // position + vec3_t normal; // normal + vec2_t stcoord; // ST texture coords + vec2_t lmcoord; // ST lightmap coords + vec2_t sccoord; // ST scissor coords (decals only) - for normalmap coords migration + vec3_t tangent; // tangent + vec3_t binormal; // binormal + byte color[4]; // colors per vertex +} glvert_t; + +typedef struct glpoly_s +{ + struct glpoly_s *next; + struct glpoly_s *chain; + int numverts; + int flags; // for SURF_UNDERWATER + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} glpoly_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float 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 + float dx; // local texture coordinates + float dy; // + float scale; // Pixel scale + short texture; // Decal texture + byte flags; // Decal flags FDECAL_* + short entityIndex; // Entity this is attached to +// Xash3D added + vec3_t position; // location of the decal center in world space. + vec3_t saxis; // direction of the s axis in world space + struct msurfmesh_s *mesh; // decal mesh in local space + int reserved[4]; // for future expansions +}; + +typedef struct mleaf_s +{ +// common with node + int contents; + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; +// leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + byte *compressed_pas; + byte ambient_sound_level[NUM_AMBIENTS]; + +} mleaf_t; + +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + 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 + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + + mtexinfo_t *texinfo; + + // lighting info + 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. + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + struct msurface_s *lightmapchain; // for new dlights rendering (was cached_dlight) + + color24 *samples; // note: this is the actual lightmap data for this surface + decal_t *pdecals; +} msurface_t; + +typedef struct msurfmesh_s +{ + unsigned short numVerts; + unsigned short numElems; // ~ 20 000 vertex per one surface. Should be enough + unsigned int startVert; // user-variable. may be used for construct world single-VBO + unsigned int startElem; // user-variable. may be used for construct world single-VBO + + glvert_t *verts; // vertexes array + unsigned short *elems; // indices + + struct msurface_s *surf; // pointer to parent surface. Just for consistency + struct msurfmesh_s *next; // temporary chain of subdivided surfaces +} msurfmesh_t; + +// surface extradata stored in cache.data for all brushmodels +typedef struct mextrasurf_s +{ + vec3_t mins, maxs; + vec3_t origin; // surface origin + msurfmesh_t *mesh; // VBO\VA ready surface mesh. Not used by engine but can be used by mod-makers + + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + int mirrortexturenum; // gl texnum + float mirrormatrix[4][4]; + struct mextrasurf_s *mirrorchain; // for gl_texsort drawing + struct mextrasurf_s *detailchain; // for detail textures drawing + color24 *deluxemap; // note: this is the actual deluxemap data for this surface + + int reserved[32]; // just for future expansions or mod-makers +} mextrasurf_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; + +#ifndef CACHE_USER +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; // extradata +} cache_user_t; +#endif + +typedef struct model_s +{ + char name[64]; // model name + qboolean needload; // bmodels and sprites don't cache normally + + // shared modelinfo + modtype_t type; // model type + int numframes; // sprite's framecount + byte *mempool; // private mempool (was synctype) + int flags; // hl compatibility + +// +// volume occupied by the model +// + vec3_t mins, maxs; // bounding box at angles '0 0 0' + float radius; + + // brush model + int firstmodelsurface; + int nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; // or studio animations + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *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 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; + +#define MAX_SCOREBOARDNAME 32 +#define MAX_INFO_STRING 256 + +#include "custom.h" + +typedef struct player_info_s +{ + int userid; // User id on server + char userinfo[MAX_INFO_STRING]; // User info string + char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) + int spectator; // Spectator or not, unused + + int ping; + int packet_loss; + + // skin information + char model[64]; + 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; + +// +// sprite representation in memory +// +typedef enum { SPR_SINGLE = 0, SPR_GROUP, SPR_ANGLED } spriteframetype_t; + +typedef struct mspriteframe_s +{ + int width; + int height; + float up, down, left, right; + int gl_texturenum; +} mspriteframe_t; + +typedef struct +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +typedef struct +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +typedef struct +{ + short type; + short texFormat; + int maxwidth; + int maxheight; + int numframes; + int radius; + int facecull; + int synctype; + mspriteframedesc_t frames[1]; +} msprite_t; + +#endif//COM_MODEL_H \ No newline at end of file diff --git a/common/con_nprint.h b/common/con_nprint.h new file mode 100644 index 00000000..a0371933 --- /dev/null +++ b/common/con_nprint.h @@ -0,0 +1,25 @@ +/*** +* +* 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 CON_NPRINT_H +#define CON_NPRINT_H + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[3]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + +#endif//CON_NPRINT_H \ No newline at end of file diff --git a/common/const.h b/common/const.h new file mode 100644 index 00000000..9701fe07 --- /dev/null +++ b/common/const.h @@ -0,0 +1,780 @@ +/*** +* +* 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 CONST_H +#define CONST_H +// +// Constants shared by the engine and dlls +// This header file included by engine files and DLL files. +// Most came from server.h + +// edict->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_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 +#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water +#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection + +// UNDONE: Do we need these? +#define FL_IMMUNE_WATER (1<<17) +#define FL_IMMUNE_SLIME (1<<18) +#define FL_IMMUNE_LAVA (1<<19) + +#define FL_PROXY (1<<20) // This is a spectator proxy +#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#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_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 + +// Goes into globalvars_t.trace_flags +#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box +#define FTRACE_IGNORE_GLASS (1<<1) // traceline will be ignored entities with rendermode != kRenderNormal + +// 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 + +// 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_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_COMPOUND 14 // glue two entities together (simple movewith) + +// 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_CUSTOM 5 // call external callbacks for tracing + +// 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_RESPAWNABLE 3 +#define DEAD_DISCARDBODY 4 + +#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_INVLIGHT 16 // get lighting from ceiling +#define EF_NOINTERP 32 // don't interpolate the next frame +#define EF_LIGHT 64 // rocket flare glow sprite +#define EF_NODRAW 128 // don't draw entity + + + +#define EF_NOREFLECT (1<<24) // Entity won't reflecting in mirrors +#define EF_REFLECTONLY (1<<25) // Entity will be drawing only in mirrors +#define EF_NOWATERCSG (1<<26) // Do not remove sides for func_water entity +#define EF_FULLBRIGHT (1<<27) // Just get fullbright +#define EF_NOSHADOW (1<<28) // ignore shadow for this entity +#define EF_MERGE_VISIBILITY (1<<29) // this entity allowed to merge vis (e.g. env_sky or portal camera) +#define EF_REQUEST_PHS (1<<30) // This entity requested phs bitvector instead of pvsbitvector in AddToFullPack calls +// g-cont. one reserved bit here for me + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity + +// +// temp entity events +// +#define TE_BEAMPOINTS 0 // beam effect between two points +// coord coord coord (start position) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMENTPOINT 1 // beam effect between point and entity +// short (start entity) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#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 +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) +// byte (flags) +// +// The Explosion effect has some flags to control performance/aesthetic features: +#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles +#define TE_EXPLFLAG_DRAWALPHA 16 // sprite will be drawn alpha +#define TE_EXPLFLAG_ROTATE 32 // rotate the sprite randomly + +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +// coord coord coord (position) + +#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 +// coord, coord, coord (start) +// coord, coord, coord (end) + +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +// coord, coord, coord (start) +// coord, coord, coord (end) +// byte (life in 0.1's) +// byte (width in 0.1's) +// byte (amplitude in 0.01's) +// short (sprite model index) + +#define TE_BEAMENTS 8 +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +// coord coord coord (position) + +#define TE_LAVASPLASH 10 // Quake1 lava splash +// coord coord coord (position) + +#define TE_TELEPORT 11 // Quake1 teleport splash +// coord coord coord (position) + +#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound +// coord coord coord (position) +// byte (starting color) +// byte (num colors) + +#define TE_BSPDECAL 13 // Decal from the .BSP file +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// short (texture index of precached decal texture name) +// short (entity index) +// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) + +#define TE_IMPLOSION 14 // tracers moving toward a point +// coord, coord, coord (position) +// byte (radius) +// byte (count) +// byte (life in 0.1's) + +#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions +// coord, coord, coord (start) +// coord, coord, coord (end) +// short (sprite index) +// byte (count) +// byte (life in 0.1's) +// byte (scale in 0.1's) +// byte (velocity along vector in 10's) +// byte (randomness of velocity in 10's) + +#define TE_BEAM 16 // obsolete + +#define TE_SPRITE 17 // additive sprite, plays 1 cycle +// coord, coord, coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (brightness) + +#define TE_BEAMSPRITE 18 // A beam with a sprite at the end +// coord, coord, coord (start position) +// coord, coord, coord (end position) +// short (beam sprite index) +// short (end sprite index) + +#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving +// short (entity:attachment to follow) +// short (sprite index) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte,byte,byte (color) +// byte (brightness) + +#define TE_GLOWSPRITE 23 +// coord, coord, coord (pos) short (model index) byte (scale / 10) + +#define TE_BEAMRING 24 // connect a beam ring to two entities +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_STREAK_SPLASH 25 // oriented shower of tracers +// coord coord coord (start position) +// coord coord coord (direction vector) +// byte (color) +// short (count) +// short (base speed) +// short (random velocity) + +#define TE_BEAMHOSE 26 // obsolete + +#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect +// coord, coord, coord (pos) +// byte (radius in 10's) +// byte byte byte (color) +// byte (life in 10's) +// byte (decay rate in 10's) + +#define TE_ELIGHT 28 // point entity light, no world effect +// short (entity:attachment to follow) +// coord coord coord (initial position) +// coord (radius) +// byte byte byte (color) +// byte (life in 0.1's) +// coord (decay rate) + +#define TE_TEXTMESSAGE 29 +// short 1.2.13 x (-1 = center) +// short 1.2.13 y (-1 = center) +// byte Effect 0 = fade in/fade out +// 1 is flickery credits +// 2 is write out (training room) +// 4 bytes r,g,b,a color1 (text color) +// 4 bytes r,g,b,a color2 (effect color) +// ushort 8.8 fadein time +// ushort 8.8 fadeout time +// ushort 8.8 hold time +// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) +// string text message (512 chars max sz string) +#define TE_LINE 30 +// coord, coord, coord startpos +// coord, coord, coord endpos +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_BOX 31 +// coord, coord, coord boxmins +// coord, coord, coord boxmaxs +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_KILLBEAM 99 // kill all beams attached to entity +// short (entity) + +#define TE_LARGEFUNNEL 100 +// coord coord coord (funnel position) +// short (sprite index) +// short (flags) + +#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 +// coord coord coord (start position) +// coord coord coord (end position) + +#define TE_BLOOD 103 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_DECAL 104 // Decal applied to a brush entity (not the world) +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) +// short (entity index) + +#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards +// short (entity) +// short (sprite index) +// byte (density) + +#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// angle (initial yaw) +// short (model index) +// byte (bounce sound type) +// byte (life in 0.1's) + +#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set +// coord, coord, coord (origin) +// coord (velocity) +// short (model index) +// short (count) +// byte (life in 0.1's) + +#define TE_BREAKMODEL 108 // box of models or sprites +// coord, coord, coord (position) +// coord, coord, coord (size) +// coord, coord, coord (velocity) +// byte (random velocity in 10's) +// short (sprite or model index) +// byte (count) +// byte (life in 0.1 secs) +// byte (flags) + +#define TE_GUNSHOTDECAL 109 // decal and ricochet sound +// coord, coord, coord (position) +// short (entity index???) +// byte (decal???) + +#define TE_SPRITE_SPRAY 110 // spay of alpha sprites +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (sprite index) +// byte (count) +// byte (speed) +// byte (noise) + +#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. +// coord, coord, coord (position) +// byte (scale in 0.1's) + +#define TE_PLAYERDECAL 112 // ??? +// byte (playerindex) +// coord, coord, coord (position) +// short (entity???) +// byte (decal number???) +// [optional] short (model index???) + +#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) +// coord, coord, coord (position) +// short (sprite1 index) +// short (sprite2 index) +// byte (color) +// byte (scale) + +#define TE_WORLDDECAL 116 // Decal applied to the world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) + +#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) + +#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) +// short (entity index) + +#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (modelindex) +// byte (life) +// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). + +#define TE_SPRAY 120 // Throws a shower of sprites or models +// coord, coord, coord (position) +// coord, coord, coord (direction) +// short (modelindex) +// byte (count) +// byte (speed) +// byte (noise) +// byte (rendermode) + +#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) +// byte (playernum) +// short (sprite modelindex) +// byte (count) +// byte (variance) (0 = no variance in size) (10 = 10% variance in size) + +#define TE_PARTICLEBURST 122 // very similar to lavasplash. +// coord (origin) +// short (radius) +// byte (particle color) +// byte (duration * 10) (will be randomized a bit) + +#define TE_FIREFIELD 123 // makes a field of fire. +// coord (origin) +// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) +// short (modelindex) +// byte (count) +// byte (flags) +// byte (duration (in seconds) * 10) (will be randomized a bit) +// +// to keep network traffic low, this message has associated flags that fit into a byte: +#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate +#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) +#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. +#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque +#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. + +#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) +// byte (entity index of player) +// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) +// short (model index) +// short (life * 10 ); + +#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. +// byte (entity index of player) + +#define TE_MULTIGUNSHOT 126 // much more compact shotgun message +// This message is used to make a client approximate a 'spray' of gunfire. +// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is +// a good candidate for MULTIGUNSHOT use. (shotguns) +// +// NOTE: This effect makes the client do traces for each bullet, these client traces ignore +// entities that have studio models.Traces are 4096 long. +// +// coord (origin) +// coord (origin) +// coord (origin) +// coord (direction) +// coord (direction) +// coord (direction) +// coord (x noise * 100) +// coord (y noise * 100) +// byte (count) +// byte (bullethole decal texture index) + +#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. +// coord (origin) +// coord (origin) +// coord (origin) +// coord (velocity) +// coord (velocity) +// coord (velocity) +// byte ( life * 10 ) +// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) +// byte ( length * 10 ) + +#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 + +// 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 +// 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_TRANSLUCENT -15 + +#define CONTENTS_LADDER -16 + +#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_SLIME -4 +#define CONTENT_LAVA -5 +#define CONTENT_SKY -6 + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#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 +#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM (float)0.8 +#define ATTN_IDLE (float)2 +#define ATTN_STATIC (float)1.25 + +// pitch values +#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 + +// volume values +#define VOL_NORM 1.0 + +// plats +#define PLAT_LOW_TRIGGER 1 + +// Trains +#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 + +// buttons +#define IN_ATTACK (1<<0) +#define IN_JUMP (1<<1) +#define IN_DUCK (1<<2) +#define IN_FORWARD (1<<3) +#define IN_BACK (1<<4) +#define IN_USE (1<<5) +#define IN_CANCEL (1<<6) +#define IN_LEFT (1<<7) +#define IN_RIGHT (1<<8) +#define IN_MOVELEFT (1<<9) +#define IN_MOVERIGHT (1<<10) +#define IN_ATTACK2 (1<<11) +#define IN_RUN (1<<12) +#define IN_RELOAD (1<<13) +#define IN_ALT1 (1<<14) +#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down + +// Break Model Defines +#define BREAK_TYPEMASK 0x4F +#define BREAK_GLASS 0x01 +#define BREAK_METAL 0x02 +#define BREAK_FLESH 0x04 +#define BREAK_WOOD 0x08 +#define BREAK_SMOKE 0x10 +#define BREAK_TRANS 0x20 +#define BREAK_CONCRETE 0x40 +#define BREAK_2 0x80 + +// Colliding temp entity sounds +#define BOUNCE_GLASS BREAK_GLASS +#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_SHOTSHELL 0x80 + +// Temp entity bounce sound types +#define TE_BOUNCE_NULL 0 +#define TE_BOUNCE_SHELL 1 +#define TE_BOUNCE_SHOTSHELL 2 + +// Rendering constants +enum +{ + kRenderNormal, // src + kRenderTransColor, // c*a+dest*(1-a) + kRenderTransTexture, // src*a+dest*(1-a) + kRenderGlow, // src*a+dest -- No Z buffer checks + kRenderTransAlpha, // src*srca+dest*(1-srca) + kRenderTransAdd, // src*a+dest + kRenderWorldGlow, // Same as kRenderGlow but not fixed size in screen space +}; + +enum +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, // Distort/scale/translate flicker + kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! + kRenderFxGlowShell, // Glowing Shell + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) +}; + +typedef int func_t; +typedef int string_t; + +typedef unsigned char byte; +typedef unsigned short word; + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum { false, true } qboolean; +#else +typedef int qboolean; +#endif + +typedef struct +{ + byte r, g, b; +} color24; + +typedef struct +{ + unsigned r, g, b, a; +} colorVec; + +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + +typedef struct edict_s edict_t; + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + 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 +} trace_t; + +#endif//CONST_H \ No newline at end of file diff --git a/common/cvardef.h b/common/cvardef.h new file mode 100644 index 00000000..ee5588b6 --- /dev/null +++ b/common/cvardef.h @@ -0,0 +1,37 @@ +/*** +* +* 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 + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; + +#endif//CVARDEF_H \ No newline at end of file diff --git a/common/demo_api.h b/common/demo_api.h new file mode 100644 index 00000000..c414e4ae --- /dev/null +++ b/common/demo_api.h @@ -0,0 +1,27 @@ +/*** +* +* 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 DEMO_API_H +#define DEMO_API_H + +typedef struct demo_api_s +{ + int (*IsRecording)( void ); + int (*IsPlayingback)( void ); + int (*IsTimeDemo)( void ); + void (*WriteBuffer)( int size, unsigned char *buffer ); +} demo_api_t; + +#endif//DEMO_API_H \ No newline at end of file diff --git a/common/dlight.h b/common/dlight.h new file mode 100644 index 00000000..848d2182 --- /dev/null +++ b/common/dlight.h @@ -0,0 +1,31 @@ +/*** +* +* 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 DLIGHT_H +#define DLIGHT_H + +typedef struct dlight_s +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + +#endif//DLIGHT_H \ No newline at end of file diff --git a/common/entity_state.h b/common/entity_state.h new file mode 100644 index 00000000..2e0f129d --- /dev/null +++ b/common/entity_state.h @@ -0,0 +1,186 @@ +/*** +* +* 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 ENTITY_STATE_H +#define ENTITY_STATE_H + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +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; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + +// Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // 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; +}; + +#include "pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + int pushmsec; + int deadflag; + char physinfo[MAX_PHYSINFO_STRING]; + + // 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; + +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[64]; +} local_state_t; + +#endif//ENTITY_STATE_H \ No newline at end of file diff --git a/common/entity_types.h b/common/entity_types.h new file mode 100644 index 00000000..fcdd4c2c --- /dev/null +++ b/common/entity_types.h @@ -0,0 +1,25 @@ +/*** +* +* 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 ENTITY_TYPES_H +#define ENTITY_TYPES_H + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +#define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes + +#endif//ENTITY_TYPES_H \ No newline at end of file diff --git a/common/event_api.h b/common/event_api.h new file mode 100644 index 00000000..d29aac99 --- /dev/null +++ b/common/event_api.h @@ -0,0 +1,54 @@ +/*** +* +* 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 EVENT_API_H +#define EVENT_API_H + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound )( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound )( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal )( int playernum ); + int ( *EV_LocalPlayerDucking )( void ); + void ( *EV_LocalPlayerViewheight )( float * ); + void ( *EV_LocalPlayerBounds )( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace)( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent )( int idx ); + void ( *EV_SetUpPlayerPrediction )( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates )( void ); + void ( *EV_PopPMStates )( void ); + void ( *EV_SetSolidPlayers )( int playernum ); + void ( *EV_SetTraceHull )( int hull ); + void ( *EV_PlayerTrace )( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation )( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent )( int type, const char* psz ); + void ( *EV_PlaybackEvent )( 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 ); + const char *( *EV_TraceTexture )( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds )( int entnum, int entchannel ); + void ( *EV_KillEvents )( int entnum, const char *eventname ); + + // Xash3D extension + unsigned short (*EV_IndexForEvent)( const char *name ); + const char *(*EV_EventForIndex)( unsigned short index ); + void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr ); + const char *(*EV_SoundForIndex)( int index ); + struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend ); +} event_api_t; + +#endif//EVENT_API_H \ No newline at end of file diff --git a/common/event_args.h b/common/event_args.h new file mode 100644 index 00000000..ed553aa9 --- /dev/null +++ b/common/event_args.h @@ -0,0 +1,47 @@ +/*** +* +* 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 EVENT_ARGS_H +#define EVENT_ARGS_H + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + +#endif//EVENT_ARGS_H \ No newline at end of file diff --git a/common/event_flags.h b/common/event_flags.h new file mode 100644 index 00000000..58460379 --- /dev/null +++ b/common/event_flags.h @@ -0,0 +1,45 @@ +/*** +* +* 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 EVENT_FLAGS_H +#define EVENT_FLAGS_H + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + +#endif//EVENT_FLAGS_H \ No newline at end of file diff --git a/common/gameinfo.h b/common/gameinfo.h new file mode 100644 index 00000000..020e920a --- /dev/null +++ b/common/gameinfo.h @@ -0,0 +1,49 @@ +/* +gameinfo.h - current game info +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef GAMEINFO_H +#define GAMEINFO_H + +#define GFL_NOMODELS (1<<0) + +/* +======================================================================== + +GAMEINFO stuff + +internal shared gameinfo structure (readonly for engine parts) +======================================================================== +*/ +typedef struct +{ + // filesystem info + char gamefolder[64]; // used for change game '-game x' + char startmap[64]; // map to start singleplayer game + char trainmap[64]; // map to start hazard course (if specified) + char title[64]; // Game Main Title + char version[14]; // game version (optional) + short flags; // game flags + + // about mod info + char game_url[256]; // link to a developer's site + char update_url[256]; // link to updates page + char type[64]; // single, toolkit, multiplayer etc + char date[64]; + char size[64]; // displayed mod size + + int gamemode; +} GAMEINFO; + +#endif//GAMEINFO_H \ No newline at end of file diff --git a/common/hltv.h b/common/hltv.h new file mode 100644 index 00000000..f85b6241 --- /dev/null +++ b/common/hltv.h @@ -0,0 +1,59 @@ +/*** +* +* 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 HLTV_H +#define HLTV_H + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_COMMENTATOR 3 // client is a commentator +#define TYPE_DEMO 4 // client is a demo file + +// sub commands of svc_hltv: +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_LISTEN 2 // tell client to listen to a multicast stream + +// sub commands of svc_director: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director command +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // sets camera registers +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // status info about broadcast +#define DRC_CMD_BANNER 9 // banner file name for HLTV gui +#define DRC_CMD_FADE 10 // send screen fade command +#define DRC_CMD_SHAKE 11 // send screen shake command +#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command + +#define DRC_CMD_LAST 12 + +// HLTV_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + +#define MAX_DIRECTOR_CMD_PARAMETERS 4 +#define MAX_DIRECTOR_CMD_STRING 128 + +#endif//HLTV_H \ No newline at end of file diff --git a/common/ivoicetweak.h b/common/ivoicetweak.h new file mode 100644 index 00000000..9c7b6963 --- /dev/null +++ b/common/ivoicetweak.h @@ -0,0 +1,40 @@ +/*** +* +* 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 IVOICETWEAK_H +#define IVOICETWEAK_H + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume = 0, // values 0-1. + OtherSpeakerScale // values 0-1. Scales how loud other players are. +} VoiceTweakControl; + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)( void ); // Returns 0 on error. + void (*EndVoiceTweakMode)( void ); + + // Get/set control values. + void (*SetControlFloat)( VoiceTweakControl iControl, float value ); + float (*GetControlFloat)( VoiceTweakControl iControl ); + + int (*GetSpeakingVolume)( void ); +} IVoiceTweak; + +#endif//IVOICETWEAK_H \ No newline at end of file diff --git a/common/lightstyle.h b/common/lightstyle.h new file mode 100644 index 00000000..af4add8b --- /dev/null +++ b/common/lightstyle.h @@ -0,0 +1,29 @@ +/* +lightstyle.h - lighstyle description +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef LIGHTSTYLE_H +#define LIGHTSTYLE_H + +typedef struct +{ + char pattern[256]; + float map[256]; + int length; + float value; + qboolean interp; // allow to interpolate this lightstyle + float time; // local time is gurantee what new style begins from the start, not mid or end of the sequence +} lightstyle_t; + +#endif//LIGHTSTYLE_H \ No newline at end of file diff --git a/common/mathlib.h b/common/mathlib.h new file mode 100644 index 00000000..d90f5f7a --- /dev/null +++ b/common/mathlib.h @@ -0,0 +1,95 @@ +/*** +* +* 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 + +#include + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; // x,y,z,w + +#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); + +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]); + +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/common/net_api.h b/common/net_api.h new file mode 100644 index 00000000..72afdf75 --- /dev/null +++ b/common/net_api.h @@ -0,0 +1,97 @@ +/*** +* +* 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 NET_API_H +#define NET_API_H + +#include "netadr.h" + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +typedef void (*net_api_response_func_t) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + // Context ID + int context; + // Type + int type; + // Server that is responding to the request + netadr_t remote_address; + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void (*InitNetworking)( void ); + void (*Status )( struct net_status_s *status ); + void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void (*CancelRequest)( int context ); + void (*CancelAllRequests)( void ); + char *(*AdrToString)( struct netadr_s *a ); + int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr)( char *s, struct netadr_s *a ); + const char *(*ValueForKey)( const char *s, const char *key ); + void (*RemoveKey)( char *s, const char *key ); + void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + +#endif//NET_APIH \ No newline at end of file diff --git a/common/netadr.h b/common/netadr.h new file mode 100644 index 00000000..16aafe30 --- /dev/null +++ b/common/netadr.h @@ -0,0 +1,37 @@ +/*** +* +* 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 NETADR_H +#define NETADR_H + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + +#endif//NETADR_H \ No newline at end of file diff --git a/common/particledef.h b/common/particledef.h new file mode 100644 index 00000000..a5083ee6 --- /dev/null +++ b/common/particledef.h @@ -0,0 +1,54 @@ +/*** +* +* 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 PARTICLEDEF_H +#define PARTICLEDEF_H + +typedef enum +{ + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom, // Must have callback function specified + pt_tracer // Always have callback +} ptype_t; + +typedef struct particle_s +{ + vec3_t org; + short color; + short packedColor; + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // For deathfunc, etc. + unsigned char context; +} particle_t; + +#endif//PARTICLEDEF_H \ No newline at end of file diff --git a/common/pmtrace.h b/common/pmtrace.h new file mode 100644 index 00000000..e2779ad6 --- /dev/null +++ b/common/pmtrace.h @@ -0,0 +1,41 @@ +/*** +* +* 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_TRACE_H +#define PM_TRACE_H + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + +#endif//PM_TRACE_H \ No newline at end of file diff --git a/common/qfont.h b/common/qfont.h new file mode 100644 index 00000000..8489dffc --- /dev/null +++ b/common/qfont.h @@ -0,0 +1,38 @@ +/*** +* +* 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 QFONT_H +#define QFONT_H + +// Font stuff + +#define NUM_GLYPHS 256 + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[NUM_GLYPHS]; + byte data[4]; +} qfont_t; + +#endif//QFONT_H \ No newline at end of file diff --git a/common/r_efx.h b/common/r_efx.h new file mode 100644 index 00000000..d21cba27 --- /dev/null +++ b/common/r_efx.h @@ -0,0 +1,195 @@ +/*** +* +* 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 R_EFX_H +#define R_EFX_H + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) +#define FTENT_SCALE 0x00100000 // An experiment + +typedef struct tempent_s TEMPENTITY; +typedef struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ); + void (*callback)( struct tempent_s *ent, float frametime, float currenttime ); + TEMPENTITY *next; + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +} TEMPENTITY; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + 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 ); + void (*R_BloodStream)( float *org, float *dir, int pcolor, int speed ); + void (*R_BreakModel)( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void (*R_Bubbles)( float *mins, float *maxs, float height, int modelIndex, int count, float speed ); + void (*R_BubbleTrail)( float *start, float *end, float height, int modelIndex, int count, float speed ); + void (*R_BulletImpactParticles)( float *pos ); + void (*R_EntityParticles)( struct cl_entity_s *ent ); + void (*R_Explosion)( float *pos, int model, float scale, float framerate, int flags ); + void (*R_FizzEffect)( struct cl_entity_s *pent, int modelIndex, int density ); + void (*R_FireField)( float *org, int radius, int modelIndex, int count, int flags, float life ); + void (*R_FlickerParticles)( float *org ); + void (*R_FunnelSprite)( float *org, int modelIndex, int reverse ); + void (*R_Implosion)( float *end, float radius, int count, float life ); + void (*R_LargeFunnel)( float *org, int reverse ); + void (*R_LavaSplash)( float *org ); + void (*R_MultiGunshot)( float *org, float *dir, float *noise, int count, int decalCount, int *decalIndices ); + void (*R_MuzzleFlash)( float *pos1, int type ); + void (*R_ParticleBox)( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_ParticleBurst)( float *pos, int size, int color, float life ); + void (*R_ParticleExplosion)( float *org ); + void (*R_ParticleExplosion2)( float *org, int colorStart, int colorLength ); + void (*R_ParticleLine)( float *start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_PlayerSprites)( int client, int modelIndex, int count, int size ); + void (*R_Projectile)( float *origin, float *velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void (*R_RicochetSound)( float *pos ); + void (*R_RicochetSprite)( float *pos, struct model_s *pmodel, float duration, float scale ); + void (*R_RocketFlare)( float *pos ); + void (*R_RocketTrail)( float *start, float *end, int type ); + void (*R_RunParticleEffect)( float *org, float *dir, int color, int count ); + void (*R_ShowLine)( float *start, float *end ); + void (*R_SparkEffect)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_SparkShower)( float *pos ); + void (*R_SparkStreaks)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void (*R_Sprite_Explode)( TEMPENTITY *pTemp, float scale, int flags ); + void (*R_Sprite_Smoke)( TEMPENTITY *pTemp, float scale ); + void (*R_Sprite_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int iRand ); + void (*R_Sprite_Trail)( int type, float *start, float *end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void (*R_Sprite_WallPuff)( TEMPENTITY *pTemp, float scale ); + void (*R_StreakSplash)( float *pos, float *dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void (*R_TracerEffect)( float *start, float *end ); + void (*R_UserTracerParticle)( float *org, float *vel, float life, int colorIndex, float length, unsigned char deathcontext, void (*deathfunc)( struct particle_s *particle )); + particle_t *(*R_TracerParticles)( float *org, float *vel, float life ); + void (*R_TeleportSplash)( float *org ); + void (*R_TempSphereModel)( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *(*R_TempModel)( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *(*R_DefaultSprite)( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *(*R_TempSprite)( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int (*Draw_DecalIndex)( int id ); + int (*Draw_DecalIndexFromName)( char *name ); + void (*R_DecalShoot)( int textureIndex, int entity, int modelIndex, float *position, int flags ); + void (*R_AttachTentToPlayer)( int client, int modelIndex, float zoffset, float life ); + void (*R_KillAttachedTents)( int client ); + BEAM *(*R_BeamCirclePoints)( int type, float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEntPoint)( int startEnt, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEnts)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamFollow)( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void (*R_BeamKill)( int deadEntity ); + BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *(*CL_AllocDlight)( int key ); + dlight_t *(*CL_AllocElight)( int key ); + TEMPENTITY *(*CL_TempEntAlloc)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TempEntAllocNoModel)( float *org ); + TEMPENTITY *(*CL_TempEntAllocHigh)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TentEntAllocCustom)( float *origin, struct model_s *model, int high, void (*callback)( struct tempent_s *ent, float frametime, float currenttime )); + void (*R_GetPackedColor)( short *packed, short color ); + short (*R_LookupColor)( unsigned char r, unsigned char g, unsigned char b ); + void (*R_DecalRemoveAll)( int textureIndex ); // textureIndex points to the decal index in the array, not the actual texture index. + void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale ); +}; + +#endif//R_EFX_H \ No newline at end of file diff --git a/common/r_studioint.h b/common/r_studioint.h new file mode 100644 index 00000000..8c5598e1 --- /dev/null +++ b/common/r_studioint.h @@ -0,0 +1,154 @@ +/*** +* +* 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 R_STUDIOINT_H +#define R_STUDIOINT_H + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex )( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity )( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo )( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState )( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity )( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes )( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar )( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite )( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters )( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale )( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform )( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform )( void ); + float ***( *StudioGetRotationMatrix )( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox )( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight )( struct alight_s *plight ); + void ( *StudioSetupLighting )( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints )( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls )( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox )( void ); + // Draws bones + void ( *StudioDrawBones )( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin )( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors )( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel )( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents )( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags )( void ); + void ( *SetForceFaceFlags )( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader )( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel )( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer )( int rendermode ); + void ( *RestoreRenderer )( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin )( void ); + + // True if using D3D/OpenGL + int ( *IsHardware )( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow )( void ); + void ( *GL_SetRenderMode )( int mode ); + + void ( *StudioSetRenderamt )( int iRenderamt ); + void ( *StudioSetCullState )( int iCull ); + void ( *StudioRenderShadow )( int iSprite, float *p1, float *p2, float *p3, float *p4 ); +} engine_studio_api_t; + +typedef struct server_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); +} server_studio_api_t; + +// client blending +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel )( int flags ); + int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +// server blending +#define SV_BLENDING_INTERFACE_VERSION 1 + +typedef struct sv_blending_interface_s +{ + 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 ); +} sv_blending_interface_t; + +#endif//R_STUDIOINT_H \ No newline at end of file diff --git a/common/ref_params.h b/common/ref_params.h new file mode 100644 index 00000000..a544925c --- /dev/null +++ b/common/ref_params.h @@ -0,0 +1,90 @@ +/*** +* +* 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 REF_PARAMS_H +#define REF_PARAMS_H + +typedef struct ref_params_s +{ + // output + vec3_t vieworg; + vec3_t viewangles; + + vec3_t forward; + vec3_t right; + vec3_t up; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + vec3_t simvel; + vec3_t simorg; + + vec3_t viewheight; + float idealpitch; + + vec3_t cl_viewangles; + int health; + vec3_t crosshairangle; + float viewsize; + + vec3_t punchangle; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x, y, width, height + int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview + // so long in cycles until this value is 0 (multiple views) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions +// Xash3D extension + float fov_x, fov_y; // actual fov can be overrided on nextView +} ref_params_t; + +// same as ref_params but for overview mode +typedef struct ref_overview_s +{ + vec3_t origin; + qboolean rotated; + + float xLeft; + float xRight; + float xTop; + float xBottom; + float zFar; + float zNear; + float flZoom; +} ref_overview_t; + +#endif//REF_PARAMS_H \ No newline at end of file diff --git a/common/render_api.h b/common/render_api.h new file mode 100644 index 00000000..c454bc47 --- /dev/null +++ b/common/render_api.h @@ -0,0 +1,261 @@ +/* +render_api.h - Xash3D extension for client interface +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef RENDER_API_H +#define RENDER_API_H + +#include "lightstyle.h" +#include "dlight.h" + +// changes for version 28 +// replace decal_t from software declaration to hardware (matched to normal HL) +// mextrasurf_t->increased limit of reserved fields (up from 7 to 32) +// replace R_StoreEfrags with him extended version +// formed group for BSP decal manipulating +// move misc functions at end of the interface +// added new export for clearing studio decals + +#define CL_RENDER_INTERFACE_VERSION 35 +#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals + +#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces)) +#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data)) + +// render info parms +#define PARM_TEX_WIDTH 1 // all parms with prefix 'TEX_' receive arg as texnum +#define PARM_TEX_HEIGHT 2 // otherwise it's not used +#define PARM_TEX_SRC_WIDTH 3 +#define PARM_TEX_SRC_HEIGHT 4 +#define PARM_TEX_SKYBOX 5 // second arg as skybox ordering num +#define PARM_TEX_SKYTEXNUM 6 // skytexturenum for quake sky +#define PARM_TEX_LIGHTMAP 7 // second arg as number 0 - 128 +#define PARM_TEX_TARGET 8 +#define PARM_TEX_TEXNUM 9 +#define PARM_TEX_FLAGS 10 +#define PARM_TEX_TYPE 11 +#define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload +#define PARM_TEX_GLFORMAT 13 // get a texture GL-format +// reserved +#define PARM_WORLD_VERSION 16 // return the version of bsp +#define PARM_SKY_SPHERE 17 // sky is quake sphere ? +#define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs +#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata +#define PARM_MAX_ENTITIES 20 +#define PARM_WIDESCREEN 21 +#define PARM_FULLSCREEN 22 +#define PARM_SCREEN_WIDTH 23 +#define PARM_SCREEN_HEIGHT 24 +#define PARM_CLIENT_INGAME 25 +#define PARM_FEATURES 26 // same as movevars->features +#define PARM_ACTIVE_TMU 27 // for debug +#define PARM_CACHEFRAME 28 +#define PARM_MAX_IMAGE_UNITS 29 +#define PARM_CLIENT_ACTIVE 30 +#define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change + +enum +{ + // skybox ordering + SKYBOX_RIGHT = 0, + SKYBOX_BACK, + SKYBOX_LEFT, + SKYBOX_FORWARD, + SKYBOX_UP, + SKYBOX_DOWN, +}; + +typedef enum +{ + TEX_INVALID = 0, // free slot + TEX_SYSTEM, // generated by engine + TEX_NOMIP, // hud pics, menu etc + TEX_BRUSH, // a map texture + TEX_SPRITE, // sprite frames + TEX_STUDIO, // studio skins + TEX_LIGHTMAP, // lightmap textures + TEX_DECAL, // decals + TEX_VGUI, // vgui fonts or images + TEX_CUBEMAP, // cubemap textures (sky) + TEX_DETAIL, // detail textures + TEX_REMAP, // local copy of remap texture + TEX_SCREENCOPY, // keep screen copy e.g. for mirror + TEX_CUSTOM, // user created texture + TEX_DEPTHMAP // shadowmap texture +} texType_t; + +typedef enum +{ + TF_NEAREST = (1<<0), // disable texfilter + TF_KEEP_RGBDATA = (1<<1), // some images keep source + TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20 + TF_KEEP_8BIT = (1<<3), // keep original 8-bit image (if present) + TF_NOPICMIP = (1<<4), // ignore r_picmip resample rules + TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory + TF_CUBEMAP = (1<<6), // it's cubemap texture + TF_DEPTHMAP = (1<<7), // custom texture filter used + TF_INTENSITY = (1<<8), // monochrome intensity image + TF_LUMINANCE = (1<<9), // force image to grayscale + TF_SKYSIDE = (1<<10), // this is a part of skybox + TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range + TF_NOMIPMAP = (1<<12), // don't build mips for this image + TF_HAS_LUMA = (1<<13), // sets by GL_UploadTexture + TF_MAKELUMA = (1<<14), // create luma from quake texture (only q1 textures contain luma-pixels) + TF_NORMALMAP = (1<<15), // is a normalmap + TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture) + TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures) + TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D + TF_BORDER = (1<<19), // zero clamp for projected textures + TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D + TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine) + TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE + TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference) + TF_IMAGE_PROGRAM = (1<<24), // enable image program support like in Doom3 + TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage + TF_FLOAT = (1<<26), // float textures + TF_NOCOMPARE = (1<<27), // disable comparing for depth textures + TF_FLOATDATA = (1<<28), // incoming dataType has type GL_FLOAT +} texFlags_t; + +typedef struct beam_s BEAM; +typedef struct particle_s particle_t; + +// 12 bytes here +typedef struct modelstate_s +{ + short sequence; + short frame; // 10 bits multiple by 4, should be enough + byte blending[2]; + byte controller[4]; + byte body; + byte skin; +} modelstate_t; + +typedef struct decallist_s +{ + vec3_t position; + char name[64]; + short entityIndex; + byte depth; + byte flags; + float scale; + + // this is the surface plane that we hit so that + // we can move certain decals across + // transitions if they hit similar geometry + vec3_t impactPlaneNormal; + + modelstate_t studio_state; // studio decals only +} decallist_t; + +typedef struct render_api_s +{ + // Get renderer info (doesn't changes engine state at all) + int (*RenderGetParm)( int parm, int arg ); // generic + void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale ); + void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha ); + lightstyle_t* (*GetLightStyle)( int number ); + dlight_t* (*GetDynamicLight)( int number ); + dlight_t* (*GetEntityLight)( int number ); + byte (*TextureToTexGamma)( byte color ); // software gamma support + void (*GetBeamChains)( BEAM ***active_beams, BEAM ***free_beams, particle_t ***free_trails ); + + // Set renderer info (tell engine about changes) + void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel + void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged + void (*GL_SetWorldviewProjectionMatrix)( const float *glmatrix ); // update viewprojection matrix (tracers uses it) + void (*R_StoreEfrags)( struct efrag_s **ppefrag, int framecount );// store efrags for static entities + + // Texture tools + int (*GL_FindTexture)( const char *name ); + const char* (*GL_TextureName)( unsigned int texnum ); + const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL + int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags ); + int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags ); + void (*GL_SetTextureType)( unsigned int texnum, unsigned int type ); + void (*GL_TextureCacheFrame)( unsigned int texnum ); + void (*GL_FreeTexture)( unsigned int texnum ); + + // Decals manipulating (draw & remove) + void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa ); + float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount ); + void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only) + + // AVIkit support + void *(*AVI_LoadVideo)( const char *filename, int ignore_hwgamma ); + int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration ); + long (*AVI_GetVideoFrameNumber)( void *Avi, float time ); + byte *(*AVI_GetVideoFrame)( void *Avi, long frame ); + void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data ); + void (*AVI_FreeVideo)( void *Avi ); + int (*AVI_IsActive)( void *Avi ); + + // glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client) + void (*GL_Bind)( int tmu, unsigned int texnum ); + void (*GL_SelectTexture)( int tmu ); + void (*GL_LoadTextureMatrix)( const float *glmatrix ); + void (*GL_TexMatrixIdentity)( void ); + void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units + void (*GL_TexGen)( unsigned int coord, unsigned int mode ); + void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture + void (*GL_TexCoordArrayMode)( unsigned int texmode ); + void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility + void (*GL_Reserved1)( void ); + void (*GL_Reserved2)( void ); + void (*GL_Reserved3)( void ); + + // Misc renderer functions + void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags ); + void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder + int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare ); + void (*Host_Error)( const char *error, ... ); // cause Host Error + int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load + void (*TessPolygon)( struct msurface_s *surf, struct model_s *mod, float tessSize ); + struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e ); + const struct ref_overview_s *( *GetOverviewParms )( void ); + void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents) + void (*SetRandomSeed)( long lSeed ); // set custom seed for RANDOM_FLOAT\RANDOM_LONG for predictable random + // static allocations + void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); + // find in files + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); + // ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 35 +} render_api_t; + +// render callbacks +typedef struct render_interface_s +{ + int version; + // passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer) + int (*GL_RenderFrame)( const struct ref_params_s *pparams, qboolean drawWorld ); + // build all the lightmaps on new level or when gamma is changed + void (*GL_BuildLightmaps)( void ); + // setup map bounds for ortho-projection when we in dev_overview mode + void (*GL_OrthoBounds)( const float *mins, const float *maxs ); + // handle decals which hit mod_studio or mod_sprite + void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state ); + // prepare studio decals for save + int (*R_CreateStudioDecalList)( decallist_t *pList, int count, qboolean changelevel ); + // clear decals by engine request (e.g. for demo recording or vid_restart) + void (*R_ClearStudioDecals)( void ); + // grab r_speeds message + qboolean (*R_SpeedsMessage)( char *out, size_t size ); + // replace with built-in R_DrawCubemapView for make skyshots or envshots + qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size ); + // alloc or destroy studiomodel custom data + void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer ); +} render_interface_t; + +#endif//RENDER_API_H \ No newline at end of file diff --git a/common/screenfade.h b/common/screenfade.h new file mode 100644 index 00000000..872508b2 --- /dev/null +++ b/common/screenfade.h @@ -0,0 +1,29 @@ +/*** +* +* 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 SCREENFADE_H +#define SCREENFADE_H + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + +#endif//SCREENFADE_H \ No newline at end of file diff --git a/common/studio_event.h b/common/studio_event.h new file mode 100644 index 00000000..bd451817 --- /dev/null +++ b/common/studio_event.h @@ -0,0 +1,27 @@ +/*** +* +* 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 STUDIO_EVENT_H +#define STUDIO_EVENT_H + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + +#endif//STUDIO_EVENT_H \ No newline at end of file diff --git a/common/triangleapi.h b/common/triangleapi.h new file mode 100644 index 00000000..d975a26e --- /dev/null +++ b/common/triangleapi.h @@ -0,0 +1,62 @@ +/*** +* +* 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 TRIANGLEAPI_H +#define TRIANGLEAPI_H + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 +#define TRI_POINTS 7 // Xash3D added + +typedef struct triangleapi_s +{ + int version; + + void (*RenderMode)( int mode ); + void (*Begin)( int primitiveCode ); + void (*End)( void ); + + void (*Color4f)( float r, float g, float b, float a ); + void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void (*TexCoord2f)( float u, float v ); + void (*Vertex3fv)( float *worldPnt ); + void (*Vertex3f)( float x, float y, float z ); + void (*Brightness)( float brightness ); + void (*CullFace)( TRICULLSTYLE style ); + int (*SpriteTexture)( struct model_s *pSpriteModel, int frame ); + int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped + void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. + void (*ScreenToWorld)( float *screen, float *world ); + void (*GetMatrix)( const int pname, float *matrix ); + int (*BoxInPVS)( float *mins, float *maxs ); + void (*LightAtPoint)( float *pos, float *value ); + void (*Color4fRendermode)( float r, float g, float b, float a, int rendermode ); + void (*FogParams)( float flDensity, int iFogSkybox ); +} triangleapi_t; + +#endif//TRIANGLEAPI_H \ No newline at end of file diff --git a/common/usercmd.h b/common/usercmd.h new file mode 100644 index 00000000..c23b9173 --- /dev/null +++ b/common/usercmd.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 USERCMD_H +#define USERCMD_H + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles + + // intended velocities + float forwardmove; // Forward velocity + float sidemove; // Sideways velocity + float upmove; // Upward velocity + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack and move buttons + byte impulse; // Impulse command issued + byte weaponselect; // Current weapon id + + // Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + +#endif//USERCMD_H \ No newline at end of file diff --git a/common/wadfile.h b/common/wadfile.h new file mode 100644 index 00000000..80d54a8f --- /dev/null +++ b/common/wadfile.h @@ -0,0 +1,79 @@ +/*** +* +* 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 WADFILE_H +#define WADFILE_H + +/* +======================================================================== +.WAD archive format (WhereAllData - WAD) + +List of compressed files, that can be identify only by TYPE_* + + +header: dwadinfo_t[dwadinfo_t] +file_1: byte[dwadinfo_t[num]->disksize] +file_2: byte[dwadinfo_t[num]->disksize] +file_3: byte[dwadinfo_t[num]->disksize] +... +file_n: byte[dwadinfo_t[num]->disksize] +infotable dlumpinfo_t[dwadinfo_t->numlumps] +======================================================================== +*/ + +#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') + +// dlumpinfo_t->compression +#define CMP_NONE 0 // compression none +#define CMP_LZSS 1 // LZSS compression + +// dlumpinfo_t->type +#define TYP_QPAL 64 // quake palette +#define TYP_QTEX 65 // probably was never used +#define TYP_QPIC 66 // quake1 and hl pic (lmp_t) +#define TYP_MIPTEX 67 // half-life (mip_t) previous was TYP_SOUND but never used in quake1 +#define TYP_QMIP 68 // quake1 (mip_t) (replaced with TYPE_MIPTEX while loading) +#define TYP_RAW 69 // raw data +#define TYP_QFONT 70 // half-life font (qfont_t) + +/* +======================================================================== + +.LMP image format (Half-Life gfx.wad lumps) + +======================================================================== +*/ +typedef struct lmp_s +{ + unsigned int width; + unsigned int height; +} lmp_t; + +/* +======================================================================== + +.MIP image format (half-Life textures) + +======================================================================== +*/ +typedef struct mip_s +{ + char name[16]; + unsigned int width; + unsigned int height; + unsigned int offsets[4]; // four mip maps stored +} mip_t; + +#endif//WADFILE_H \ No newline at end of file diff --git a/common/weaponinfo.h b/common/weaponinfo.h new file mode 100644 index 00000000..f1810a0c --- /dev/null +++ b/common/weaponinfo.h @@ -0,0 +1,50 @@ +/*** +* +* 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 WEAPONINFO_H +#define WEAPONINFO_H + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + +#endif//WEAPONINFO_H \ No newline at end of file diff --git a/common/wrect.h b/common/wrect.h new file mode 100644 index 00000000..83bcbd75 --- /dev/null +++ b/common/wrect.h @@ -0,0 +1,24 @@ +/* +wrect.h - rectangle definition +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef WRECT_H +#define WRECT_H + +typedef struct wrect_s +{ + int left, right, top, bottom; +} wrect_t; + +#endif//WRECT_H \ No newline at end of file diff --git a/debug.bat b/debug.bat new file mode 100644 index 00000000..eb702325 --- /dev/null +++ b/debug.bat @@ -0,0 +1,42 @@ +@echo off + +set MSDEV=BuildConsole +set CONFIG=/ShowTime /ShowAgent /nologo /cfg= +set MSDEV=msdev +set CONFIG=/make +set build_type=debug +set BUILD_ERROR= +call vcvars32 + +%MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Debug" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +%MSDEV% mainui/mainui.dsp %CONFIG%"mainui - Win32 Debug" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +if "%BUILD_ERROR%"=="" goto build_ok + +echo ********************* +echo ********************* +echo *** Build Errors! *** +echo ********************* +echo ********************* +echo press any key to exit +echo ********************* +pause>nul +goto done + + +@rem +@rem Successful build +@rem +:build_ok + +rem //delete log files +if exist engine\engine.plg del /f /q engine\engine.plg +if exist mainui\mainui.plg del /f /q mainui\mainui.plg + +echo +echo Build succeeded! +echo +:done \ No newline at end of file diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/dlls/AI_BaseNPC_Schedule.cpp new file mode 100644 index 00000000..75886699 --- /dev/null +++ b/dlls/AI_BaseNPC_Schedule.cpp @@ -0,0 +1,1514 @@ +/*** +* +* 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; + + ResetThink(); + 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/dlls/Android.mk b/dlls/Android.mk new file mode 100644 index 00000000..3c0f5748 --- /dev/null +++ b/dlls/Android.mk @@ -0,0 +1,134 @@ +#HLSDK server Android port +#Copyright (c) nicknekit + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := server + +include $(XASH3D_CONFIG) + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard) +LOCAL_MODULE_FILENAME = libserver_hardfp +endif + +LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \ + -fno-exceptions -w -fpermissive + +LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti -fpermissive + +LOCAL_C_INCLUDES := $(SDL_PATH)/include \ + $(LOCAL_PATH)/. \ + $(LOCAL_PATH)/wpn_shared \ + $(LOCAL_PATH)/../common \ + $(LOCAL_PATH)/../engine/common \ + $(LOCAL_PATH)/../engine \ + $(LOCAL_PATH)/../public \ + $(LOCAL_PATH)/../pm_shared \ + $(LOCAL_PATH)/../game_shared + +LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ + aflock.cpp \ + animating.cpp \ + animation.cpp \ + apache.cpp \ + barnacle.cpp \ + barney.cpp \ + bigmomma.cpp \ + bloater.cpp \ + bmodels.cpp \ + bullsquid.cpp \ + buttons.cpp \ + cbase.cpp \ + client.cpp \ + combat.cpp \ + controller.cpp \ + crossbow.cpp \ + crowbar.cpp \ + defaultai.cpp \ + doors.cpp \ + effects.cpp \ + egon.cpp \ + explode.cpp \ + flyingmonster.cpp \ + func_break.cpp \ + func_tank.cpp \ + game.cpp \ + gamerules.cpp \ + gargantua.cpp \ + gauss.cpp \ + genericmonster.cpp \ + ggrenade.cpp \ + globals.cpp \ + gman.cpp \ + h_ai.cpp \ + h_battery.cpp \ + h_cine.cpp \ + h_cycler.cpp \ + h_export.cpp \ + handgrenade.cpp \ + hassassin.cpp \ + headcrab.cpp \ + healthkit.cpp \ + hgrunt.cpp \ + hornet.cpp \ + hornetgun.cpp \ + houndeye.cpp \ + ichthyosaur.cpp \ + islave.cpp \ + items.cpp \ + leech.cpp \ + lights.cpp \ + maprules.cpp \ + monstermaker.cpp \ + monsters.cpp \ + monsterstate.cpp \ + mortar.cpp \ + mp5.cpp \ + multiplay_gamerules.cpp \ + nihilanth.cpp \ + nodes.cpp \ + osprey.cpp \ + pathcorner.cpp \ + plane.cpp \ + plats.cpp \ + player.cpp \ + python.cpp \ + rat.cpp \ + roach.cpp \ + rpg.cpp \ + satchel.cpp \ + schedule.cpp \ + scientist.cpp \ + scripted.cpp \ + shotgun.cpp \ + singleplay_gamerules.cpp \ + skill.cpp \ + sound.cpp \ + soundent.cpp \ + spectator.cpp \ + squadmonster.cpp \ + squeakgrenade.cpp \ + subs.cpp \ + talkmonster.cpp \ + teamplay_gamerules.cpp \ + tempmonster.cpp \ + tentacle.cpp \ + triggers.cpp \ + tripmine.cpp \ + turret.cpp \ + util.cpp \ + weapons.cpp \ + world.cpp \ + xen.cpp \ + zombie.cpp \ + prop.cpp \ + ../pm_shared/pm_debug.c \ + ../pm_shared/pm_math.c \ + ../pm_shared/pm_shared.c \ + ../game_shared/voice_gamemgr.cpp + +LOCAL_LDLIBS := -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/dlls/Makefile b/dlls/Makefile new file mode 100644 index 00000000..374be650 --- /dev/null +++ b/dlls/Makefile @@ -0,0 +1,186 @@ +# +# 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) -w -m486 -O1 + +#full optimization +#CFLAGS=$(BASE_CFLAGS) -w -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 $< + +############################################################################# +# 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_CC) + +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 $(DLL_OBJDIR) + -mkdir $(WPN_SHARED_OBJDIR) + -mkdir $(GAME_SHARED_OBJDIR) + -mkdir $(PM_SHARED_OBJDIR) +clean: + -rm -f $(OBJ) + -rm -f $(DLLNAME)_$(ARCH).$(SHLIBEXT) +spotless: clean + -rm -r $(DLL_OBJDIR) + -rm -r $(WPN_SHARED_OBJDIR) + -rm -r $(GAME_SHARED_OBJDIR) + -rm -r $(PM_SHARED_OBJDIR) + diff --git a/dlls/Wxdebug.cpp b/dlls/Wxdebug.cpp new file mode 100644 index 00000000..d3902d6c --- /dev/null +++ b/dlls/Wxdebug.cpp @@ -0,0 +1,395 @@ +//==========================================================================; +// +// 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/dlls/activity.h b/dlls/activity.h new file mode 100644 index 00000000..37c82b6e --- /dev/null +++ b/dlls/activity.h @@ -0,0 +1,109 @@ +/*** +* +* 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; + char *name; +} activity_map_t; + +extern activity_map_t activity_map[]; + + +#endif //ACTIVITY_H diff --git a/dlls/activitymap.h b/dlls/activitymap.h new file mode 100644 index 00000000..b72c4e4d --- /dev/null +++ b/dlls/activitymap.h @@ -0,0 +1,97 @@ +/*** +* +* 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/dlls/aflock.cpp b/dlls/aflock.cpp new file mode 100644 index 00000000..45824287 --- /dev/null +++ b/dlls/aflock.cpp @@ -0,0 +1,910 @@ +/*** +* +* 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. +* +****/ +//========================================================= +//========================================================= +#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( 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 ( 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; + ResetThink(); + } + } +} + +//========================================================= +//========================================================= +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( 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( FlockLeaderThink ); + } + else + { + SetThink( 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( 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 + int cProcessed = 0;// keep track of how many other boids we've processed + 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 ( 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/dlls/agrunt.cpp b/dlls/agrunt.cpp new file mode 100644 index 00000000..ff31e8ce --- /dev/null +++ b/dlls/agrunt.cpp @@ -0,0 +1,1186 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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() +{ + int 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 != NULL ) + { + 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 ); + } + } + + 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 != NULL ) + { + // 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/dlls/airtank.cpp b/dlls/airtank.cpp new file mode 100644 index 00000000..a356744b --- /dev/null +++ b/dlls/airtank.cpp @@ -0,0 +1,118 @@ +/*** +* +* 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( TankTouch ); + SetThink( 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/dlls/animating.cpp b/dlls/animating.cpp new file mode 100644 index 00000000..6afc3956 --- /dev/null +++ b/dlls/animating.cpp @@ -0,0 +1,318 @@ +/*** +* +* 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/dlls/animation.cpp b/dlls/animation.cpp new file mode 100644 index 00000000..246586b3 --- /dev/null +++ b/dlls/animation.cpp @@ -0,0 +1,525 @@ +/*** +* +* 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 + +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 "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; + +#pragma warning( disable : 4244 ) + + + +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; + + int events = 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; + + 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 (int 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 = 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 = 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; +} \ No newline at end of file diff --git a/dlls/animation.h b/dlls/animation.h new file mode 100644 index 00000000..77281673 --- /dev/null +++ b/dlls/animation.h @@ -0,0 +1,47 @@ +/*** +* +* 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/dlls/apache.cpp b/dlls/apache.cpp new file mode 100644 index 00000000..233599f4 --- /dev/null +++ b/dlls/apache.cpp @@ -0,0 +1,1050 @@ +/*** +* +* 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. +* +****/ +#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( StartupUse ); + } + else + { + SetThink( HuntThink ); + SetTouch( 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( HuntThink ); + SetTouch( FlyTouch ); + pev->nextthink = gpGlobals->time + 0.1; + ResetUse(); +} + +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( DyingThink ); + SetTouch( 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( 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) + { + ResetTouch(); + 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 != NULL) + { + // 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 != NULL) + { + // 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; + static int count; + + 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( IgniteThink ); + SetTouch( 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( 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 \ No newline at end of file diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp new file mode 100644 index 00000000..4042d7da --- /dev/null +++ b/dlls/barnacle.cpp @@ -0,0 +1,449 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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_flCachedLength; // tongue cached length + 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; + + // FIXME: need a custom barnacle model with non-generic hitgroup + // otherwise we can apply to damage to tongue instead of body +#ifdef BARNACLE_FIX_VISIBILITY + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -16, -16, -m_flCachedLength ); + pev->absmax = pev->origin + Vector( 16, 16, 0 ); + } +#endif +}; +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 ), + DEFINE_FIELD( CBarnacle, m_flCachedLength, 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_flCachedLength = 32; // mins.z + m_cGibs = 0; + m_fLiftingPrey = FALSE; + m_flTongueAdj = -100; + + InitBoneControllers(); + + SetActivity ( ACT_IDLE ); + + SetThink ( 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; + +#ifdef BARNACLE_FIX_VISIBILITY + if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength )) + { + // recalc collision box here to avoid barnacle disappears bug + m_flCachedLength = (m_flAltitude + m_flTongueAdj); + UTIL_SetOrigin( pev, pev->origin ); + } +#endif + pev->nextthink = gpGlobals->time + 0.1; + + if ( m_hEnemy != NULL ) + { +// 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 != NULL && 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 != NULL ) + { + 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 ( 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(); + ResetThink(); + } +} + +//========================================================= +// 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/dlls/barney.cpp b/dlls/barney.cpp new file mode 100644 index 00000000..1d3e23ad --- /dev/null +++ b/dlls/barney.cpp @@ -0,0 +1,841 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL && (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 != NULL ) + { + 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( 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 == NULL ) + { + // 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 ); + + CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); + } + + ResetUse(); + 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 != NULL ) + { + // 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 == NULL && 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; + } + + 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 char *m_szPoses[3]; +}; + +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/dlls/basemonster.h b/dlls/basemonster.h new file mode 100644 index 00000000..04fbce91 --- /dev/null +++ b/dlls/basemonster.h @@ -0,0 +1,339 @@ +/*** +* +* 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. +* +****/ + +#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 ( 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 ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. +}; + + + +#endif // BASEMONSTER_H diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp new file mode 100644 index 00000000..ca7a1bf8 --- /dev/null +++ b/dlls/bigmomma.cpp @@ -0,0 +1,1251 @@ +/*** +* +* 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. +* +****/ +#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 == NULL ) + 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 == NULL ) + 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 != NULL && (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; + float distance = vecGrenadeVel.Length(); + + // 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 ( 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/dlls/bloater.cpp b/dlls/bloater.cpp new file mode 100644 index 00000000..889b866e --- /dev/null +++ b/dlls/bloater.cpp @@ -0,0 +1,219 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/bmodels.cpp b/dlls/bmodels.cpp new file mode 100644 index 00000000..0937c1f8 --- /dev/null +++ b/dlls/bmodels.cpp @@ -0,0 +1,958 @@ +/*** +* +* 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 = atof(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( 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( 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( 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 ( 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 ? vecAVel.x : (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(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(vecAVel.x) >= abs(pev->movedir.x * pev->speed) && + abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) && + abs(vecAVel.z) >= abs(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( 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, m_pitch); + + SetThink( 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 ( 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 ( 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 ( 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( 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( SUB_CallUseToggle ); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->speed = 0; + SetUse( PendulumUse ); + + if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) + { + SetTouch ( 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( Stop ); + } + else + { + pev->speed = 0; // Dead stop + ResetThink(); + 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( Swing ); + m_dampSpeed = m_maxSpeed; + } +} + + +void CPendulum :: Stop( void ) +{ + pev->angles = m_start; + pev->speed = 0; + ResetThink(); + 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; + ResetThink(); + 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/dlls/bullsquid.cpp b/dlls/bullsquid.cpp new file mode 100644 index 00000000..c8518b62 --- /dev/null +++ b/dlls/bullsquid.cpp @@ -0,0 +1,1275 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ( 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 ( 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 != NULL ) + { + 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 != NULL && 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 != NULL ) + { + 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 ) +{ + int 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 != NULL && 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; + } + } + + 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 != NULL && ( 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 = NULL; + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + break; + } + } + + m_IdealMonsterState = CBaseMonster :: GetIdealState(); + + return m_IdealMonsterState; +} + diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp new file mode 100644 index 00000000..5153d7ba --- /dev/null +++ b/dlls/buttons.cpp @@ -0,0 +1,1276 @@ +/*** +* +* 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" + + +#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(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(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 ) +{ + 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(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. + ResetTouch(); + + m_hActivator = CBaseEntity::Instance( pevAttacker ); + if ( m_hActivator == NULL ) + 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( ) +{ + 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 ( 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( ButtonTouch ); + } + else + { + ResetTouch(); + SetUse ( ButtonUse ); + } +} + + +// Button sound table. +// Also used by CBaseDoor to get 'touched' door lock/unlock sounds + +char *ButtonSound( int sound ) +{ + 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 ( 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. + ResetTouch(); + + 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( 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 + ResetTouch(); + } + else + SetTouch( ButtonTouch ); + } + else + { + pev->nextthink = pev->ltime + m_flWait; + SetThink( 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( 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 + ResetTouch(); + } + else + SetTouch( ButtonTouch ); + +// reset think for a sparking button + if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) + { + SetThink ( 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 ) +{ + 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 ) ) + { + ResetTouch(); + SetUse ( ButtonUse ); + } + else // touchable button + SetTouch( 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) ); + + 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 ); + UpdateTarget( pev->ideal_yaw ); +} + +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( 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( Return ); + pev->nextthink = pev->ltime + 0.1; + m_direction = -1; + } + else + ResetThink(); +} + +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; + ResetThink(); + } + 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) +{ + ResetThink(); + ResetUse(); + + if (FBitSet(pev->spawnflags, 32)) // Use for on/off + { + if (FBitSet(pev->spawnflags, 64)) // Start on + { + SetThink(SparkThink); // start sparking + SetUse(SparkStop); // set up +USE to stop sparking + } + else + SetUse(SparkStart); + } + else + SetThink(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(SparkStop); + SetThink(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(SparkStart); + ResetThink(); +} + +#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/dlls/cbase.cpp b/dlls/cbase.cpp new file mode 100644 index 00000000..73c63ae3 --- /dev/null +++ b/dlls/cbase.cpp @@ -0,0 +1,774 @@ +/*** +* +* 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( 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 ); + +#ifndef _WIN32 +extern "C" { +#endif +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; +} + +#ifndef _WIN32 +} +#endif + + +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( 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/dlls/cbase.h b/dlls/cbase.h new file mode 100644 index 00000000..1381c88a --- /dev/null +++ b/dlls/cbase.h @@ -0,0 +1,804 @@ +/*** +* +* 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 "saverestore.h" +#include "schedule.h" + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +// C functions for external declarations that call the appropriate C++ methods + +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#else +#define EXPORT /* */ +#endif + +extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); +extern "C" EXPORT int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ); + +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, 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 _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((unsigned long)(pFunction)) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)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( 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) +#define ResetThink( ) m_pfnThink = static_cast (NULL) +#define ResetTouch( ) m_pfnTouch = static_cast (NULL) +#define ResetUse( ) m_pfnUse = static_cast (NULL) +#define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) + + +#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" + + +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/dlls/cdll_dll.h b/dlls/cdll_dll.h new file mode 100644 index 00000000..2293a27e --- /dev/null +++ b/dlls/cdll_dll.h @@ -0,0 +1,46 @@ +/*** +* +* 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 \ No newline at end of file diff --git a/dlls/client.cpp b/dlls/client.cpp new file mode 100644 index 00000000..a78efd99 --- /dev/null +++ b/dlls/client.cpp @@ -0,0 +1,1804 @@ +/*** +* +* 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" + +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 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]; + sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); + 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; +} + +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + +//// 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 + for ( char *pc = p; pc != NULL && *pc != 0; pc++ ) + { + if ( !isspace( *pc ) ) + { + pc = NULL; // we've found an alphanumeric character, so text is valid + break; + } + } + if ( pc != NULL ) + return; // no character found, so say nothing + +// turn on color set 2 (color on, no sound) + 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 ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) + 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 ); + + 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, "fire") ) + { + if ( g_flWeaponCheat != 0.0) + { + CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); + if (CMD_ARGC() > 1) + { + FireTargets(CMD_ARGV(1), pPlayer, pPlayer, USE_TOGGLE, 0); + } + else + { + TraceResult tr; + UTIL_MakeVectors(pev->v_angle); + UTIL_TraceLine( + pev->origin + pev->view_ofs, + pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, + dont_ignore_monsters, pEntity, &tr + ); + + if (tr.pHit) + { + CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); + if (pHitEnt) + { + pHitEnt->Use(pPlayer, pPlayer, USE_TOGGLE, 0); + ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); + } + } + } + } + } + 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" ) && (pev->flags & FL_PROXY) ) // added for proxy support + { + CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + + edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); + } + 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 if ( FStrEq(pcmd, "VModEnable") ) + { + // clear 'Unknown command: VModEnable' in singleplayer + return; + } + 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 ); + + 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 ) +{ +// ALERT( at_console, "ServerDeactivate()\n" ); + + // 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; + +// ALERT( at_console, "ServerActivate()\n" ); + + // 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 ) +{ +// ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + entvars_t *pev = &pEntity->v; + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->PreThink( ); +} + +/* +================ +PlayerPostThink + +Called every frame after physics are run +================ +*/ +void PlayerPostThink( edict_t *pEntity ) +{ +// ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + entvars_t *pev = &pEntity->v; + 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 ) +{ +// ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + 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 ) +{ + entvars_t *pev = &pEntity->v; + 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 ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorConnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has left the game +================ +*/ +void SpectatorDisconnect( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorDisconnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has sent a usercmd +================ +*/ +void SpectatorThink( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + 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; + } + + if( pView->v.effects & EF_MERGE_VISIBILITY ) + { + if( FClassnameIs( pView, "env_sky" )) + { + org = pView->v.origin; + } + else return; // don't merge pvs + } + else + { + 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 ) ) + { + // env_sky is visible always + if( !FClassnameIs( ent, "env_sky" )) + { + 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 & 4 ) return 0; // it's a portal pass + 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 ) ); + memcpy( state->velocity, ent->v.velocity, 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 = ent->v.renderamt; + state->renderfx = ent->v.renderfx; + state->rendercolor.r = ent->v.rendercolor.x; + state->rendercolor.g = ent->v.rendercolor.y; + state->rendercolor.b = 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; + } + } + + state->onground = 0; + if ( ent->v.groundentity ) + { + state->onground = ENTINDEX( ent->v.groundentity ); + } + + // 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 = 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, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, player_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 = ( 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 = (CBasePlayerWeapon *)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 struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + cd->flags = ent->v.flags; + cd->health = ent->v.health; + + cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + + cd->waterlevel = ent->v.waterlevel; + cd->watertype = ent->v.watertype; + cd->weapons = ent->v.weapons; + + // Vectors + cd->origin = ent->v.origin; + cd->velocity = ent->v.velocity; + cd->view_ofs = ent->v.view_ofs; + cd->punchangle = ent->v.punchangle; + + cd->bInDuck = ent->v.bInDuck; + cd->flTimeStepSound = ent->v.flTimeStepSound; + cd->flDuckTime = ent->v.flDuckTime; + cd->flSwimTime = ent->v.flSwimTime; + cd->waterjumptime = ent->v.teleport_time; + + strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); + + cd->maxspeed = ent->v.maxspeed; + cd->fov = ent->v.fov; + cd->weaponanim = ent->v.weaponanim; + + cd->pushmsec = ent->v.pushmsec; + +#if defined( CLIENT_WEAPONS ) + if ( sendweapons ) + { + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + 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 = ( 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 = ( 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 ) +{ + // Parse stuff from args + int max_buffer_size = *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 ) +{ + int iret = 0; + 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/dlls/client.h b/dlls/client.h new file mode 100644 index 00000000..2e0b38ed --- /dev/null +++ b/dlls/client.h @@ -0,0 +1,65 @@ +/*** +* +* 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/dlls/combat.cpp b/dlls/combat.cpp new file mode 100644 index 00000000..b56b7a2f --- /dev/null +++ b/dlls/combat.cpp @@ -0,0 +1,1706 @@ +/*** +* +* 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 ( StickyGibTouch ); + pGib->ResetThink(); + } + 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 ( 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; + BOOL fTriedDirection; + float flDot; + + fTriedDirection = FALSE; + 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 ) +{ + unsigned int cCount = 0; + BOOL fDone = FALSE; + + 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 ) + { + ResetTouch(); + 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 ( 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 ( 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 (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 ( 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 ( WaitTillLand ); + SetTouch ( 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 == NULL || 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, (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 ) +{ + static int tracerCount; + TraceResult tr; + Vector vecRight = gpGlobals->v_right; + Vector vecUp = gpGlobals->v_up; + float x, y, 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, (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/dlls/controller.cpp b/dlls/controller.cpp new file mode 100644 index 00000000..bad72429 --- /dev/null +++ b/dlls/controller.cpp @@ -0,0 +1,1427 @@ +/*** +* +* 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. +* +****/ +#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 != NULL) + { + 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: + { + Vector vecTmp = 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; + } + + 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_iTrail; + 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( HuntThink ); + SetTouch( 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 == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + ResetTouch(); + 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( 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( AnimateThink ); + SetTouch( 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) + { + ResetTouch(); + UTIL_Remove( this ); + } +} + + +void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) +{ + if (pOther->pev->takedamage) + { + TraceResult tr = UTIL_GetGlobalTrace( ); + + entvars_t *pevOwner; + if (m_hOwner != NULL) + { + 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/dlls/crossbow.cpp b/dlls/crossbow.cpp new file mode 100644 index 00000000..4a2ffd66 --- /dev/null +++ b/dlls/crossbow.cpp @@ -0,0 +1,564 @@ +/*** +* +* 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("crossbow_bolt"); // g-cont. enable save\restore + 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( BoltTouch ); + SetThink( 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 ) +{ + ResetTouch(); + ResetThink(); + + 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( 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; + } + else if ( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) + { + Vector vecDir = pev->velocity.Normalize( ); + UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); + pev->angles = UTIL_VecToAngles( vecDir ); + pev->solid = SOLID_NOT; + pev->velocity = Vector( 0, 0, 0 ); + pev->avelocity.z = 0; + pev->angles.z = RANDOM_LONG(0,360); + pev->nextthink = gpGlobals->time + 10.0; + + // g-cont. Setup movewith feature + pev->movetype = MOVETYPE_COMPOUND; // set movewith type + pev->aiment = ENT( pOther->pev ); // set parent + } + + if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) + { + UTIL_Sparks( pev->origin ); + } + } + + if ( g_pGameRules->IsMultiplayer() ) + { + SetThink( 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 = UTIL_WeaponTimeBase() + 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; + Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; + Vector vecDir = gpGlobals->v_forward; + +#ifndef CLIENT_DLL + 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 = UTIL_WeaponTimeBase() + 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; + } + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + } +} + + + +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 \ No newline at end of file diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp new file mode 100644 index 00000000..f301de7f --- /dev/null +++ b/dlls/crowbar.cpp @@ -0,0 +1,318 @@ +/*** +* +* 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( 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, 0.0 ); + + + if ( tr.flFraction >= 1.0 ) + { + if (fFirst) + { + // miss + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 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 = flVol * CROWBAR_WALLHIT_VOLUME; +#endif + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + + SetThink( Smack ); + pev->nextthink = UTIL_WeaponTimeBase() + 0.2; + + + } + return fDidHit; +} + + + diff --git a/dlls/decals.h b/dlls/decals.h new file mode 100644 index 00000000..0f8ff4ed --- /dev/null +++ b/dlls/decals.h @@ -0,0 +1,75 @@ +/*** +* +* 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 +{ + char *name; + int index; +} DLL_DECALLIST; + +extern DLL_DECALLIST gDecals[]; + +#endif // DECALS_H diff --git a/dlls/defaultai.cpp b/dlls/defaultai.cpp new file mode 100644 index 00000000..efc0087e --- /dev/null +++ b/dlls/defaultai.cpp @@ -0,0 +1,1232 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/defaultai.h b/dlls/defaultai.h new file mode 100644 index 00000000..271ac7aa --- /dev/null +++ b/dlls/defaultai.h @@ -0,0 +1,98 @@ +/*** +* +* 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. +* +****/ +#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/dlls/doors.cpp b/dlls/doors.cpp new file mode 100644 index 00000000..303d7385 --- /dev/null +++ b/dlls/doors.cpp @@ -0,0 +1,1079 @@ +/*** +* +* 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(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 if (FStrEq(pkvd->szKeyName, "locked_sound")) + { + m_bLockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(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 ) ) + { + ResetTouch(); + } + else // touchable button + SetTouch( 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 ) +{ + 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( )) + ResetTouch(); // 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 != NULL && 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 ) ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + + m_toggle_state = TS_GOING_UP; + + SetMoveDone( DoorHitTop ); + if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet + { + float sign = 1.0; + + if ( m_hActivator != NULL ) + { + 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( DoorTouch ); + } + else + { + // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open + pev->nextthink = pev->ltime + m_flWait; + SetThink( 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 ) ) + 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( 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 + ResetTouch(); + } + else // touchable door + SetTouch( 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 ( 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 ) ) + { + ResetTouch(); + } + else // touchable button + SetTouch( 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 EXPORT MomentaryMoveDone( 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[]; + + BYTE m_bMoveSnd; // sound a door makes while moving + BYTE m_bStopSnd; // sound a door makes when it stops +}; + +LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); + +TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = +{ + DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), + DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, 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; + } + ResetTouch(); + + 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; + } + +// 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; + } +} + +void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) +{ + + if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(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; + Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); + + Vector delta = move - pev->origin; + float speed = delta.Length() * 10; + + if ( speed != 0 ) + { + // 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 + if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + + LinearMove( move, speed ); + SetMoveDone( MomentaryMoveDone ); + } + +} + +void CMomentaryDoor::MomentaryMoveDone( void ) +{ + STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving)); + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); +} \ No newline at end of file diff --git a/dlls/doors.h b/dlls/doors.h new file mode 100644 index 00000000..55a853fc --- /dev/null +++ b/dlls/doors.h @@ -0,0 +1,33 @@ +/*** +* +* 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/dlls/effects.cpp b/dlls/effects.cpp new file mode 100644 index 00000000..8d6e29d1 --- /dev/null +++ b/dlls/effects.cpp @@ -0,0 +1,2268 @@ +/*** +* +* 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 ? pev->speed : -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( 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( FizzThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + else + { + ResetThink(); + 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( 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( SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; // Remove model & collisions + Precache( ); + + pev->dmgtime = gpGlobals->time; + + if ( ServerSide() ) + { + ResetThink(); + if ( pev->dmg > 0 ) + { + SetThink( 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( ToggleUse ); + } + } + else + { + m_active = 0; + if ( !FStringNull(pev->targetname) ) + { + SetUse( StrikeUse ); + } + if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) + { + SetThink( 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; + ResetThink(); + } + else + { + SetThink( StrikeThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + + if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) + ResetUse(); +} + + +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( 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( 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( SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; // Remove model & collisions + Precache( ); + + SetThink( 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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( 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( 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( 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( 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; + ResetThink(); + pev->nextthink = gpGlobals->time; + } + else + { + SetThink ( 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( 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; + ResetThink(); + } +} + + +void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( 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(), BloodAmount() ); + else + UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), 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(), pev->renderamt, fadeFlags ); + } + } + else + { + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), 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( 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 (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 ) ); + ResetThink(); + SetTouch ( 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; + ResetTouch(); + SetThink ( SUB_Remove ); + pev->nextthink = gpGlobals->time; +} \ No newline at end of file diff --git a/dlls/effects.h b/dlls/effects.h new file mode 100644 index 00000000..1464d6a6 --- /dev/null +++ b/dlls/effects.h @@ -0,0 +1,209 @@ +/*** +* +* 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(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 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 pev->renderamt; } + inline int GetFrame( void ) { return pev->frame; } + inline int GetScrollRate( void ) { return 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(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/dlls/egon.cpp b/dlls/egon.cpp new file mode 100644 index 00000000..98d246a7 --- /dev/null +++ b/dlls/egon.cpp @@ -0,0 +1,568 @@ +/*** +* +* 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; + + 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( 255 - (timeBlend*180) ); + m_pBeam->SetWidth( 40 - (timeBlend*20) ); + + if ( m_fireMode == FIRE_WIDE ) + m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + else + m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 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 > UTIL_WeaponTimeBase()) + 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 \ No newline at end of file diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h new file mode 100644 index 00000000..aad3724d --- /dev/null +++ b/dlls/enginecallback.h @@ -0,0 +1,158 @@ +/*** +* +* 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 +#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 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 \ No newline at end of file diff --git a/dlls/explode.cpp b/dlls/explode.cpp new file mode 100644 index 00000000..55dcb1c9 --- /dev/null +++ b/dlls/explode.cpp @@ -0,0 +1,273 @@ +/*** +* +* 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( 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/dlls/explode.h b/dlls/explode.h new file mode 100644 index 00000000..3d8c4107 --- /dev/null +++ b/dlls/explode.h @@ -0,0 +1,32 @@ +/*** +* +* 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/dlls/extdll.h b/dlls/extdll.h new file mode 100644 index 00000000..31e48554 --- /dev/null +++ b/dlls/extdll.h @@ -0,0 +1,88 @@ +/*** +* +* 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 +#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 + +// 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 +#define FALSE 0 +#define TRUE (!FALSE) +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef int BOOL; +#define MAX_PATH PATH_MAX +#include +#include +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#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 int func_t; // +typedef 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/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp new file mode 100644 index 00000000..9a0774f8 --- /dev/null +++ b/dlls/flyingmonster.cpp @@ -0,0 +1,281 @@ +/*** +* +* 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. +* +****/ +#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/dlls/flyingmonster.h b/dlls/flyingmonster.h new file mode 100644 index 00000000..752f56ec --- /dev/null +++ b/dlls/flyingmonster.h @@ -0,0 +1,53 @@ +/*** +* +* 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. +* +****/ +// 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/dlls/func_break.cpp b/dlls/func_break.cpp new file mode 100644 index 00000000..c15b6d9c --- /dev/null +++ b/dlls/func_break.cpp @@ -0,0 +1,1006 @@ +/*** +* +* 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 < 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( BreakTouch ); + if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger + ResetTouch(); + + // 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; + + 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; + } + 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; + char *rgpsz[6]; + int i; + 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) + { + ResetTouch(); + 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 ( Die ); + ResetTouch(); + + 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; + } + } + + 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 + CBaseEntity *pEntity = NULL; + 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(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; + } + + + 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( 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 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 ); + +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 = ( 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 = atof(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; + } + + // g-cont. fix pushable acceleration bug + if ( pOther->IsPlayer() ) + { + // Don't push unless the player is pushing forward and NOT use (pull) + if ( push && !(pevToucher->button & (IN_FORWARD|IN_MOVERIGHT|IN_MOVELEFT|IN_BACK)) ) + return; + if ( !push && !(pevToucher->button & (IN_BACK)) ) 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/dlls/func_break.h b/dlls/func_break.h new file mode 100644 index 00000000..2441f756 --- /dev/null +++ b/dlls/func_break.h @@ -0,0 +1,74 @@ +/*** +* +* 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/dlls/func_tank.cpp b/dlls/func_tank.cpp new file mode 100644 index 00000000..459d21af --- /dev/null +++ b/dlls/func_tank.cpp @@ -0,0 +1,1039 @@ +/*** +* +* 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 > 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; + + Vector offset = pevTest->origin - pev->origin; + + 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, lineOfSight; + Vector angles, direction, targetPosition, barrelEnd; + edict_t *pTarget; + + // 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 ); + + lineOfSight = FALSE; + // No line of sight, don't track + if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) + { + lineOfSight = TRUE; + + 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, pev->rendercolor.x, pev->rendercolor.y, 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 = (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 = (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 = (gpGlobals->time - m_fireLast) * m_fireRate; + if ( bulletCount > 0 ) + { + for ( i = 0; i < bulletCount; i++ ) + { + CBaseEntity *pRocket = 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 = (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/dlls/game.cpp b/dlls/game.cpp new file mode 100644 index 00000000..b4b6da75 --- /dev/null +++ b/dlls/game.cpp @@ -0,0 +1,887 @@ +/*** +* +* 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 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 (&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/dlls/game.h b/dlls/game.h new file mode 100644 index 00000000..7bd9dce4 --- /dev/null +++ b/dlls/game.h @@ -0,0 +1,45 @@ +/*** +* +* 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/dlls/gamerules.cpp b/dlls/gamerules.cpp new file mode 100644 index 00000000..34bb491c --- /dev/null +++ b/dlls/gamerules.cpp @@ -0,0 +1,347 @@ +/*** +* +* 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/dlls/gamerules.h b/dlls/gamerules.h new file mode 100644 index 00000000..2e853045 --- /dev/null +++ b/dlls/gamerules.h @@ -0,0 +1,360 @@ +/*** +* +* 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/dlls/gargantua.cpp b/dlls/gargantua.cpp new file mode 100644 index 00000000..c448d9e8 --- /dev/null +++ b/dlls/gargantua.cpp @@ -0,0 +1,1368 @@ +/*** +* +* 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. +* +****/ +#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 +#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime + +// 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 * STOMP_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 + (STOMP_FRAMETIME) * pev->framerate; + pev->framerate = pev->framerate + (STOMP_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( 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; + static float offset[2] = { 60, -60 }; + 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() +{ + int 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( 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( 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 \ No newline at end of file diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp new file mode 100644 index 00000000..45cdda8e --- /dev/null +++ b/dlls/gauss.cpp @@ -0,0 +1,621 @@ +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = ( 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; + + Vector vecSrc = vecOrigSrc; + Vector vecDest = vecSrc + vecDir * 8192; + edict_t *pentIgnore; + TraceResult tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + + pentIgnore = ENT( m_pPlayer->pev ); + +#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; + } + 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/dlls/genericmonster.cpp b/dlls/genericmonster.cpp new file mode 100644 index 00000000..8f40be61 --- /dev/null +++ b/dlls/genericmonster.cpp @@ -0,0 +1,140 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 NULL; +} + +//========================================================= +// 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/dlls/ggrenade.cpp b/dlls/ggrenade.cpp new file mode 100644 index 00000000..bed91293 --- /dev/null +++ b/dlls/ggrenade.cpp @@ -0,0 +1,488 @@ +/*** +* +* 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( (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( 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( (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( Detonate ); + pev->nextthink = gpGlobals->time; +} + +void CGrenade::PreDetonate( void ) +{ + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); + + SetThink( 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, 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, 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( 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( DangerSoundThink ); + pGrenade->pev->nextthink = gpGlobals->time; + + // Tumble in air + pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); + + // Explode on contact + pGrenade->SetTouch( 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( 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( 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( SUB_DoNothing ); + pGrenade->SetUse( DetonateUse ); + pGrenade->SetTouch( 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/dlls/globals.cpp b/dlls/globals.cpp new file mode 100644 index 00000000..be31ef9f --- /dev/null +++ b/dlls/globals.cpp @@ -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. +* +****/ +/* + +===== 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/dlls/glock.cpp b/dlls/glock.cpp new file mode 100644 index 00000000..769ab4ac --- /dev/null +++ b/dlls/glock.cpp @@ -0,0 +1,274 @@ +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/gman.cpp b/dlls/gman.cpp new file mode 100644 index 00000000..77a1bd8a --- /dev/null +++ b/dlls/gman.cpp @@ -0,0 +1,237 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 NULL; +} + +//========================================================= +// 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 == NULL) + { + 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 != NULL) + { + 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 != NULL && 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/dlls/h_ai.cpp b/dlls/h_ai.cpp new file mode 100644 index 00000000..f24a988e --- /dev/null +++ b/dlls/h_ai.cpp @@ -0,0 +1,199 @@ +/*** +* +* 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/dlls/h_battery.cpp b/dlls/h_battery.cpp new file mode 100644 index 00000000..3f2a9a29 --- /dev/null +++ b/dlls/h_battery.cpp @@ -0,0 +1,200 @@ +/*** +* +* 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 = 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(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 = gSkillData.suitchargerCapacity; + pev->frame = 0; + SetThink( 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 = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink(Recharge); + } + else + SetThink( SUB_DoNothing ); +} \ No newline at end of file diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp new file mode 100644 index 00000000..7f681922 --- /dev/null +++ b/dlls/h_cine.cpp @@ -0,0 +1,241 @@ +/*** +* +* 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. +* +****/ +/* + +===== 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( 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( 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( 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( CineThink ); + pev->nextthink = gpGlobals->time; +} + +// +// ********** Scientist DIE ********** +// +void CLegacyCineMonster :: Die( void ) +{ + SetThink( 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( BloodGush ); + pev->nextthink = gpGlobals->time;// now! +} + +void CCineBlood :: Spawn ( void ) +{ + pev->solid = SOLID_NOT; + SetUse ( BloodStart ); + pev->health = 20;//hacked health to count iterations +} + diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp new file mode 100644 index 00000000..a306359f --- /dev/null +++ b/dlls/h_cycler.cpp @@ -0,0 +1,471 @@ +/*** +* +* 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(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(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( 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 = 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/dlls/h_export.cpp b/dlls/h_export.cpp new file mode 100644 index 00000000..0d56d045 --- /dev/null +++ b/dlls/h_export.cpp @@ -0,0 +1,69 @@ +/*** +* +* 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; +server_physics_api_t g_physfuncs; + +#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; +} + +void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +{ + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; +} + + +#else + +extern "C" { + +void GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +{ + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; +} + +} + +#endif diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp new file mode 100644 index 00000000..007ad662 --- /dev/null +++ b/dlls/handgrenade.cpp @@ -0,0 +1,233 @@ +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/hassassin.cpp b/dlls/hassassin.cpp new file mode 100644 index 00000000..da8f677a --- /dev/null +++ b/dlls/hassassin.cpp @@ -0,0 +1,1015 @@ +/*** +* +* 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. +* +****/ +#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 == NULL) + { + 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 != NULL ) + { + 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 == NULL || 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; + } + + 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 \ No newline at end of file diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp new file mode 100644 index 00000000..809281aa --- /dev/null +++ b/dlls/headcrab.cpp @@ -0,0 +1,555 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL) + { + 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(); + ResetTouch(); + 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 ); + } + + ResetTouch(); +} + +//========================================================= +// 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 ( 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 != NULL ) + return slHCRangeAttack1Fast; + break; + + case SCHED_RANGE_ATTACK1: + { + return slHCRangeAttack1Fast; + } + break; + } + + return CHeadCrab::GetScheduleOfType( Type ); +} diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp new file mode 100644 index 00000000..73931f28 --- /dev/null +++ b/dlls/healthkit.cpp @@ -0,0 +1,264 @@ +/*** +* +* 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 = 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(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 = gSkillData.healthchargerCapacity; + pev->frame = 0; + SetThink( 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 = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink(Recharge); + } + else + SetThink( SUB_DoNothing ); +} \ No newline at end of file diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp new file mode 100644 index 00000000..0d2ca6c9 --- /dev/null +++ b/dlls/hgrunt.cpp @@ -0,0 +1,2517 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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, +} HGRUNT_SENTENCE_TYPES; + +//========================================================= +// 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 != NULL ) + { + 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; + + if ( m_hEnemy != NULL ) + { + 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 == NULL) + { + 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 == NULL) + { + 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; + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + 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 != NULL) && m_hEnemy->IsPlayer()) + // player + SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + else if ((m_hEnemy != NULL) && + (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 != NULL ) + { + // 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 ); + } + } + } + + // 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 != NULL ) + { + // 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( 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( 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 char *m_szPoses[3]; +}; + +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/dlls/hl.def b/dlls/hl.def new file mode 100644 index 00000000..c009191a --- /dev/null +++ b/dlls/hl.def @@ -0,0 +1,5 @@ +LIBRARY hl +EXPORTS + GiveFnptrsToDll @1 +SECTIONS + .data READ WRITE diff --git a/dlls/hl.dsp b/dlls/hl.dsp new file mode 100644 index 00000000..7985e2e6 --- /dev/null +++ b/dlls/hl.dsp @@ -0,0 +1,747 @@ +# 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 "hl - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +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 "..\temp\dlls\!release" +# PROP Intermediate_Dir "..\temp\dlls\!release" +# PROP Ignore_Export_Lib 1 +# 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 /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /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 /debug /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile /map +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\dlls\!release +InputPath=\Xash3D\src_main\temp\dlls\!release\hl.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" + +# 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 "..\temp\dlls\!debug" +# PROP Intermediate_Dir "..\temp\dlls\!debug" +# PROP Ignore_Export_Lib 1 +# 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 "..\dlls" /I "..\engine" /I "..\common" /I "..\game_shared" /I "..\pm_shared" /I "..\\" /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" +# SUBTRACT LINK32 /profile +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\dlls\!debug +InputPath=\Xash3D\src_main\temp\dlls\!debug\hl.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\hl___Win" +# PROP BASE Intermediate_Dir ".\hl___Win" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\temp\dlls\!profile" +# PROP Intermediate_Dir "..\temp\dlls\!profile" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /G5 /MT /W3 /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" +# SUBTRACT BASE LINK32 /profile +# 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 /profile /debug /machine:I386 /def:".\hl.def" +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\dlls\!profile +InputPath=\Xash3D\src_main\temp\dlls\!profile\hl.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "hl - Win32 Release" +# Name "hl - Win32 Debug" +# Name "hl - Win32 Profile" +# 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 +# End Source File +# Begin Source File + +SOURCE=.\agrunt.cpp +# End Source File +# Begin Source File + +SOURCE=.\airtank.cpp +# End Source File +# Begin Source File + +SOURCE=.\animating.cpp +# End Source File +# Begin Source File + +SOURCE=.\animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\apache.cpp +# End Source File +# Begin Source File + +SOURCE=.\barnacle.cpp +# End Source File +# Begin Source File + +SOURCE=.\barney.cpp +# End Source File +# Begin Source File + +SOURCE=.\bigmomma.cpp +# End Source File +# Begin Source File + +SOURCE=.\bloater.cpp +# End Source File +# Begin Source File + +SOURCE=.\bmodels.cpp +# End Source File +# Begin Source File + +SOURCE=.\bullsquid.cpp +# End Source File +# Begin Source File + +SOURCE=.\buttons.cpp +# End Source File +# Begin Source File + +SOURCE=.\cbase.cpp +# End Source File +# Begin Source File + +SOURCE=.\client.cpp +# End Source File +# Begin Source File + +SOURCE=.\combat.cpp +# End Source File +# Begin Source File + +SOURCE=.\controller.cpp +# End Source File +# Begin Source File + +SOURCE=.\crossbow.cpp +# End Source File +# Begin Source File + +SOURCE=.\crowbar.cpp +# End Source File +# Begin Source File + +SOURCE=.\defaultai.cpp +# End Source File +# Begin Source File + +SOURCE=.\doors.cpp +# End Source File +# Begin Source File + +SOURCE=.\effects.cpp +# End Source File +# Begin Source File + +SOURCE=.\egon.cpp +# End Source File +# Begin Source File + +SOURCE=.\explode.cpp +# End Source File +# Begin Source File + +SOURCE=.\flyingmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\func_break.cpp +# End Source File +# Begin Source File + +SOURCE=.\func_tank.cpp +# End Source File +# Begin Source File + +SOURCE=.\game.cpp +# End Source File +# Begin Source File + +SOURCE=.\gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\gargantua.cpp +# End Source File +# Begin Source File + +SOURCE=.\gauss.cpp +# End Source File +# Begin Source File + +SOURCE=.\genericmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\ggrenade.cpp +# End Source File +# Begin Source File + +SOURCE=.\globals.cpp +# End Source File +# Begin Source File + +SOURCE=.\glock.cpp +# End Source File +# Begin Source File + +SOURCE=.\gman.cpp +# End Source File +# Begin Source File + +SOURCE=.\h_ai.cpp +# End Source File +# Begin Source File + +SOURCE=.\h_battery.cpp +# End Source File +# Begin Source File + +SOURCE=.\h_cine.cpp +# End Source File +# Begin Source File + +SOURCE=.\h_cycler.cpp +# End Source File +# Begin Source File + +SOURCE=.\h_export.cpp +# End Source File +# Begin Source File + +SOURCE=.\handgrenade.cpp +# End Source File +# Begin Source File + +SOURCE=.\hassassin.cpp +# End Source File +# Begin Source File + +SOURCE=.\headcrab.cpp +# End Source File +# Begin Source File + +SOURCE=.\healthkit.cpp +# End Source File +# Begin Source File + +SOURCE=.\hgrunt.cpp +# End Source File +# Begin Source File + +SOURCE=.\hornet.cpp +# End Source File +# Begin Source File + +SOURCE=.\hornetgun.cpp +# End Source File +# Begin Source File + +SOURCE=.\houndeye.cpp +# End Source File +# Begin Source File + +SOURCE=.\ichthyosaur.cpp +# End Source File +# Begin Source File + +SOURCE=.\islave.cpp +# End Source File +# Begin Source File + +SOURCE=.\items.cpp +# End Source File +# Begin Source File + +SOURCE=.\leech.cpp +# End Source File +# Begin Source File + +SOURCE=.\lights.cpp +# End Source File +# Begin Source File + +SOURCE=.\maprules.cpp +# End Source File +# Begin Source File + +SOURCE=.\monstermaker.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsterstate.cpp +# End Source File +# Begin Source File + +SOURCE=.\mortar.cpp +# End Source File +# Begin Source File + +SOURCE=.\mp5.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\nihilanth.cpp +# End Source File +# Begin Source File + +SOURCE=.\nodes.cpp +# End Source File +# Begin Source File + +SOURCE=.\osprey.cpp +# End Source File +# Begin Source File + +SOURCE=.\pathcorner.cpp +# End Source File +# Begin Source File + +SOURCE=.\plane.cpp +# End Source File +# Begin Source File + +SOURCE=.\plats.cpp +# End Source File +# Begin Source File + +SOURCE=.\player.cpp +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_debug.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_math.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.c +# End Source File +# Begin Source File + +SOURCE=.\python.cpp +# End Source File +# Begin Source File + +SOURCE=.\rat.cpp +# End Source File +# Begin Source File + +SOURCE=.\roach.cpp +# End Source File +# Begin Source File + +SOURCE=.\rpg.cpp +# End Source File +# Begin Source File + +SOURCE=.\satchel.cpp +# End Source File +# Begin Source File + +SOURCE=.\schedule.cpp +# End Source File +# Begin Source File + +SOURCE=.\scientist.cpp +# End Source File +# Begin Source File + +SOURCE=.\scripted.cpp +# End Source File +# Begin Source File + +SOURCE=.\shotgun.cpp +# End Source File +# Begin Source File + +SOURCE=.\singleplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\skill.cpp +# End Source File +# Begin Source File + +SOURCE=.\sound.cpp +# End Source File +# Begin Source File + +SOURCE=.\soundent.cpp +# End Source File +# Begin Source File + +SOURCE=.\spectator.cpp +# End Source File +# Begin Source File + +SOURCE=.\squadmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\squeakgrenade.cpp +# End Source File +# Begin Source File + +SOURCE=.\subs.cpp +# End Source File +# Begin Source File + +SOURCE=.\talkmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\teamplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\tempmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\tentacle.cpp +# End Source File +# Begin Source File + +SOURCE=.\triggers.cpp +# End Source File +# Begin Source File + +SOURCE=.\tripmine.cpp +# End Source File +# Begin Source File + +SOURCE=.\turret.cpp +# End Source File +# Begin Source File + +SOURCE=.\util.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_gamemgr.cpp +# End Source File +# Begin Source File + +SOURCE=.\weapons.cpp +# End Source File +# Begin Source File + +SOURCE=.\world.cpp +# End Source File +# Begin Source File + +SOURCE=.\xen.cpp +# End Source File +# Begin Source File + +SOURCE=.\zombie.cpp +# 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/dlls/hornet.cpp b/dlls/hornet.cpp new file mode 100644 index 00000000..f27b79c5 --- /dev/null +++ b/dlls/hornet.cpp @@ -0,0 +1,419 @@ +/*** +* +* 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( DieTouch ); + SetThink( 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( TrackTouch ); + SetThink( TrackTarget ); + + pev->nextthink = gpGlobals->time + 0.1; +} + +//========================================================= +// StartDart - starts a hornet out just flying straight. +//========================================================= +void CHornet :: StartDart ( void ) +{ + IgniteTrail(); + + SetTouch( DartTouch ); + + SetThink( 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) + { + ResetTouch(); + SetThink( SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + return; + } + + // UNDONE: The player pointer should come back after returning from another level + if ( m_hEnemy == NULL ) + {// enemy is dead. + Look( 512 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if ( m_hEnemy != NULL && 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 != NULL && !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 ( SUB_Remove ); + pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! +} + diff --git a/dlls/hornet.h b/dlls/hornet.h new file mode 100644 index 00000000..f069c3dd --- /dev/null +++ b/dlls/hornet.h @@ -0,0 +1,58 @@ +/*** +* +* 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/dlls/hornetgun.cpp b/dlls/hornetgun.cpp new file mode 100644 index 00000000..76b48894 --- /dev/null +++ b/dlls/hornetgun.cpp @@ -0,0 +1,305 @@ +/*** +* +* 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 = m_flNextPrimaryAttack + 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 \ No newline at end of file diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp new file mode 100644 index 00000000..e8bfacfd --- /dev/null +++ b/dlls/houndeye.cpp @@ -0,0 +1,1304 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 *CHoundeye :: 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 ) +{ + int 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; + } + + 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; + } + } + + return CSquadMonster :: GetSchedule(); +} diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp new file mode 100644 index 00000000..b88abf15 --- /dev/null +++ b/dlls/ichthyosaur.cpp @@ -0,0 +1,1108 @@ +/*** +* +* 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. +* +****/ +#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 != NULL && 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( BiteTouch ); + SetUse( 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 ); + } + + 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 == NULL) + { + 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( ) +{ + int retValue = 0; + + 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 == NULL || 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 \ No newline at end of file diff --git a/dlls/islave.cpp b/dlls/islave.cpp new file mode 100644 index 00000000..037001c3 --- /dev/null +++ b/dlls/islave.cpp @@ -0,0 +1,866 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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( 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( 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 != NULL ) + { + 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 != NULL) + { + 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 != NULL) + { + 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 ); + CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); + 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 != NULL) + 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() +{ + int 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; + } + 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 ) +{ + Vector vecDest; + float flDist = 1.0; + + 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/dlls/items.cpp b/dlls/items.cpp new file mode 100644 index 00000000..b1200ee9 --- /dev/null +++ b/dlls/items.cpp @@ -0,0 +1,342 @@ +/*** +* +* 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(ItemTouch); + + if (DROP_TO_FLOOR(ENT(pev)) == 0) + { + ALERT(at_error, "Item %s fell out of level at %f,%f,%f\n", 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 ); + ResetTouch(); + + // 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 ) +{ + ResetTouch(); + pev->effects |= EF_NODRAW; + + UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. + + SetThink ( 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( 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/dlls/items.h b/dlls/items.h new file mode 100644 index 00000000..04905fc4 --- /dev/null +++ b/dlls/items.h @@ -0,0 +1,29 @@ +/*** +* +* 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/dlls/leech.cpp b/dlls/leech.cpp new file mode 100644 index 00000000..73e233e9 --- /dev/null +++ b/dlls/leech.cpp @@ -0,0 +1,723 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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( SwimThink ); + ResetUse(); + ResetTouch(); + 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 ) +{ + int 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 ) + { + ResetThink(); + 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( DeadThink ); +} + + diff --git a/dlls/lights.cpp b/dlls/lights.cpp new file mode 100644 index 00000000..147dfdf1 --- /dev/null +++ b/dlls/lights.cpp @@ -0,0 +1,199 @@ +/*** +* +* 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, (char *)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, (char *)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.0); + g = g * (v / 255.0); + b = b * (v / 255.0); + } + + // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling + r = pow( r / 114.0, 0.6 ) * 264; + g = pow( g / 114.0, 0.6 ) * 264; + b = pow( b / 114.0, 0.6 ) * 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/dlls/maprules.cpp b/dlls/maprules.cpp new file mode 100644 index 00000000..9402f319 --- /dev/null +++ b/dlls/maprules.cpp @@ -0,0 +1,918 @@ +/*** +* +* 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 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 pev->frags; } + inline int LimitValue( void ) { return 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/dlls/maprules.h b/dlls/maprules.h new file mode 100644 index 00000000..975dafa1 --- /dev/null +++ b/dlls/maprules.h @@ -0,0 +1,22 @@ +/*** +* +* 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/dlls/monsterevent.h b/dlls/monsterevent.h new file mode 100644 index 00000000..58357e18 --- /dev/null +++ b/dlls/monsterevent.h @@ -0,0 +1,34 @@ +/*** +* +* 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/dlls/monstermaker.cpp b/dlls/monstermaker.cpp new file mode 100644 index 00000000..1ee8b708 --- /dev/null +++ b/dlls/monstermaker.cpp @@ -0,0 +1,292 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ( CyclicUse );// drop one monster each time we fire + } + else + { + SetUse ( 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 ( MakerThink ); + } + else + {// wait to be activated. + m_fActive = FALSE; + SetThink ( SUB_DoNothing ); + } + } + else + {// no targetname, just start. + pev->nextthink = gpGlobals->time + m_flDelay; + m_fActive = TRUE; + SetThink ( 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 + ResetThink(); + ResetUse(); + } +} + +//========================================================= +// 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; + ResetThink(); + } + else + { + m_fActive = TRUE; + SetThink ( 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/dlls/monsters.cpp b/dlls/monsters.cpp new file mode 100644 index 00000000..8c734de3 --- /dev/null +++ b/dlls/monsters.cpp @@ -0,0 +1,3448 @@ +/*** +* +* 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. +* +****/ +/* + +===== 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 == NULL ) + 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 != NULL) + { + 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 != NULL && 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] == NULL) // 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] != NULL) + { + 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 ( 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( MonsterInitThink ); + pev->nextthink = gpGlobals->time + 0.1; + SetUse ( 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\n", 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 ( 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 != NULL ) + 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 != NULL && 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 ) + { + ResetThink(); + + 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( 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 == NULL && PopEnemy( )) + { + if ( m_pSchedule ) + { + if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + { + SetConditions(bits_COND_NEW_ENEMY); + } + } + } + + if ( m_hEnemy != NULL ) + { + // monster has an enemy. + return TRUE; + } + + return FALSE;// monster has no enemy +} + + +//========================================================= +// DropItem - dead monster drops named item +//========================================================= +CBaseEntity* CBaseMonster :: DropItem ( 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/dlls/monsters.h b/dlls/monsters.h new file mode 100644 index 00000000..75c945fd --- /dev/null +++ b/dlls/monsters.h @@ -0,0 +1,183 @@ +/*** +* +* 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. +* +****/ +#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/dlls/monsterstate.cpp b/dlls/monsterstate.cpp new file mode 100644 index 00000000..aca95b35 --- /dev/null +++ b/dlls/monsterstate.cpp @@ -0,0 +1,234 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL ) + { + m_hEnemy = NULL;// not allowed to have an enemy anymore. + ALERT ( at_aiconsole, "Stripped\n" ); + } + 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 != NULL ) + { + 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 == NULL ) + { + 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; + } + + return m_IdealMonsterState; +} + diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp new file mode 100644 index 00000000..e23d7b60 --- /dev/null +++ b/dlls/mortar.cpp @@ -0,0 +1,323 @@ +/*** +* +* 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( 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( 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( 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 \ No newline at end of file diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp new file mode 100644 index 00000000..8ee2ce89 --- /dev/null +++ b/dlls/mp5.cpp @@ -0,0 +1,385 @@ +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/mpstubb.cpp b/dlls/mpstubb.cpp new file mode 100644 index 00000000..36d0ff94 --- /dev/null +++ b/dlls/mpstubb.cpp @@ -0,0 +1,264 @@ +/*** +* +* 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 ) + { + ResetThink(); + + 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( 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 = ( 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; +} diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp new file mode 100644 index 00000000..2e2cab75 --- /dev/null +++ b/dlls/multiplay_gamerules.cpp @@ -0,0 +1,1698 @@ +/*** +* +* 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" + +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() ) + { + // dedicated server + char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + + if ( servercfgfile && servercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing dedicated server config file\n" ); + sprintf( szCommand, "exec %s\n", servercfgfile ); + SERVER_COMMAND( szCommand ); + } + } + 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 = 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 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( 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( 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( 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 *Killer = 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 + char *tau = "tau_cannon"; + 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/dlls/nihilanth.cpp b/dlls/nihilanth.cpp new file mode 100644 index 00000000..b054e125 --- /dev/null +++ b/dlls/nihilanth.cpp @@ -0,0 +1,1836 @@ +/*** +* +* 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. +* +****/ +#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( 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( HuntThink ); + pev->nextthink = gpGlobals->time + 0.1; + SetUse( 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( HuntThink); + SetUse( 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) + { + ResetTouch(); + 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 != NULL) + { + 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] != NULL && !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] == NULL) + { + 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] != NULL) + { + 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 == NULL && 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 != NULL) + { + // 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 != NULL && !m_hEnemy->IsAlive()) + { + m_hEnemy = NULL; + } + + if (m_flLastSeen + 15 < gpGlobals->time) + { + m_hEnemy = NULL; + } + + if (m_hEnemy == NULL) + { + Look( 4096 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if (m_hEnemy != NULL && 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( 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 != NULL && m_hRecharger == NULL) + { + 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; + + float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); + + // 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] != NULL) + { + 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] != NULL) + { + 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; + for (int i = 0; i < N_SPHERES; i++) + { + if (m_hSphere[i] != NULL) + { + pSphere = m_hSphere[i]->MyMonsterPointer(); + if (pSphere->m_hEnemy == NULL) + 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 != NULL) + { + 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 != NULL) + { + 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 != NULL) + { + if (!EmitSphere( )) + { + m_hRecharger = NULL; + } + } + } + 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 != NULL) + { + 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 && m_hEnemy != NULL ) + pTouch->Touch( m_hEnemy ); + } + 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( HoverThink ); + SetTouch( 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 != NULL) + { + 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( ZapThink ); + SetTouch( 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 == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + { + ResetTouch(); + 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 ) ); + + ResetTouch(); + 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( ); + } + */ + + ResetTouch(); + 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( TeleportThink ); + SetTouch( 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( RemoveTouch ); +} + + +void CNihilanthHVR :: TeleportThink( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + // check world boundaries + if (m_hEnemy == NULL || !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 != NULL) + m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); + + if ( m_hTouch != NULL && m_hEnemy != NULL ) + 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( 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 != NULL) + m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); + + if (m_hTouch != NULL && pEnemy != NULL ) + m_hTouch->Touch( pEnemy ); + } + else + { + m_pNihilanth->MakeFriend( pev->origin ); + } + + ResetTouch(); + 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 != NULL) + { + 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 \ No newline at end of file diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp new file mode 100644 index 00000000..c3f896ca --- /dev/null +++ b/dlls/nodes.cpp @@ -0,0 +1,3641 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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" + +#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 +#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 ) +{ + edict_t *pentWorld; + 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; + } + pentWorld = NULL; + +// 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; + + 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. + // + for ( int 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", j ); + } + + 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 ( SUB_Remove ); + pev->nextthink = gpGlobals->time; + } + else + { + SetThink ( 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 ( 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 cMaxInitialLinks = 0; + int cMaxValidLinks = 0; + + int iPoolIndex = 0; + 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 ( 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 ( 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 %f\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 %f\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 %f\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"); + } + + 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: %d 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. + // + for (int 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; + m_pNodes[0].m_iPreviousNode = iNodeCnt++; + for (int 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; + } + for (int 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. + // + // + for (int 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++) + { + for (int 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. + // + for (int 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) + { + for (int 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; + for (int 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 (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( 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/dlls/nodes.h b/dlls/nodes.h new file mode 100644 index 00000000..6b6739d6 --- /dev/null +++ b/dlls/nodes.h @@ -0,0 +1,374 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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; diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp new file mode 100644 index 00000000..6dc263d3 --- /dev/null +++ b/dlls/osprey.cpp @@ -0,0 +1,805 @@ +/*** +* +* 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. +* +****/ +#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( FindAllThink ); + SetUse( 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( 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( HoverThink ); + pev->nextthink = gpGlobals->time + 0.1; +} + + + +BOOL COsprey :: HasDead( ) +{ + for (int i = 0; i < m_iUnits; i++) + { + if (m_hGrunt[i] == NULL || !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] == NULL || !m_hGrunt[i]->IsAlive()) + { + if (m_hGrunt[i] != NULL && 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( 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] != NULL && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) + { + break; + } + } + + if (i == 4) + { + m_startTime = gpGlobals->time; + SetThink( 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( 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( DyingThink ); + SetTouch( 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) + { + ResetTouch(); + 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/dlls/pathcorner.cpp b/dlls/pathcorner.cpp new file mode 100644 index 00000000..b7216720 --- /dev/null +++ b/dlls/pathcorner.cpp @@ -0,0 +1,428 @@ +/*** +* +* 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/dlls/physcallback.h b/dlls/physcallback.h new file mode 100644 index 00000000..21296c63 --- /dev/null +++ b/dlls/physcallback.h @@ -0,0 +1,33 @@ +/*** +* +* 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 PHYSCALLBACK_H +#define PHYSCALLBACK_H +#pragma once + +#include "physint.h" + +// Must be provided by user of this code +extern server_physics_api_t g_physfuncs; + +// The actual physic callbacks +#define LINK_ENTITY (*g_physfuncs.pfnLinkEdict) +#define PHYSICS_TIME (*g_physfuncs.pfnGetServerTime) +#define HOST_FRAMETIME (*g_physfuncs.pfnGetFrameTime) +#define MODEL_HANDLE (*g_physfuncs.pfnGetModel) +#define GET_AREANODE (*g_physfuncs.pfnGetHeadnode) +#define GET_SERVER_STATE (*g_physfuncs.pfnServerState) +#define HOST_ERROR (*g_physfuncs.pfnHost_Error) + +#endif //PHYSCALLBACK_H \ No newline at end of file diff --git a/dlls/plane.cpp b/dlls/plane.cpp new file mode 100644 index 00000000..ff5518c7 --- /dev/null +++ b/dlls/plane.cpp @@ -0,0 +1,60 @@ +/*** +* +* 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/dlls/plane.h b/dlls/plane.h new file mode 100644 index 00000000..a54f2457 --- /dev/null +++ b/dlls/plane.h @@ -0,0 +1,43 @@ +/*** +* +* 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/dlls/plats.cpp b/dlls/plats.cpp new file mode 100644 index 00000000..418f64e9 --- /dev/null +++ b/dlls/plats.cpp @@ -0,0 +1,2285 @@ +/*** +* +* 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "stopsnd")) + { + m_bStopSnd = atof(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( 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()) + 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 + { + ResetUse(); + + 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(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(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( 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( 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( 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( 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( 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(); + ResetThink(); + } + } + 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(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( 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( 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( 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" ); + ResetThink(); + 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( Next ); + } +} + + +void CFuncTrackTrain::OverrideReset( void ) +{ + NextThink( pev->ltime + 0.1, FALSE ); + SetThink( 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 = 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( 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( 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( 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( 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 ); + ResetThink(); + 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( CallHitBottom ); + m_toggle_state = TS_GOING_DOWN; + AngularMove( m_start, pev->speed ); + } + else + { + CFuncPlat :: GoDown(); + SetMoveDone( 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( CallHitTop ); + AngularMove( m_end, pev->speed ); + } + else + { + // If ROTMOVE, move & rotate + CFuncPlat :: GoUp(); + SetMoveDone( 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 ); + } + ResetThink(); + 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 + ResetThink(); + 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( 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 ) +{ + ResetThink(); + + m_hTargetEnt = GetNextTarget(); + CBaseEntity *pTarget = m_hTargetEnt; + + if ( !pTarget ) + { + Stop(); + return; + } + SetMoveDone( 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( 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 == NULL ) + return; + pev->health = pev->max_health; + Next(); + } +} + + + diff --git a/dlls/player.cpp b/dlls/player.cpp new file mode 100644 index 00000000..3fc7d177 --- /dev/null +++ b/dlls/player.cpp @@ -0,0 +1,4791 @@ + /*** +* +* 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 "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( "HudText", -1 ); + 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 = 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, NULL, 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; + + 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 != NULL ) + { + 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(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 += 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(); + } + +// 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 ); + StartObserver( pSpot->v.origin, 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 ); + StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); + return; + } +} + +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) +{ + m_afPhysicsFlags |= PFLAG_OBSERVER; + + 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; + pev->modelindex = 0; + UTIL_SetOrigin( pev, vecPosition ); +} + +// +// PlayerUse - handles USE keypress +// +#define PLAYER_SEARCH_RADIUS (float)64 + +void CBasePlayer::PlayerUse ( void ) +{ + // 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 != NULL ) + { + // 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(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 = -pev->frags; // Sum will be 0 + } + } + } + + pev->frags += score; + + MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX(edict()) ); + WRITE_SHORT( 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 ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); + newSBarState[ SBAR_ID_TARGETARMOR ] = 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(); + + 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(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; + + static float gtbdPrev = 0.0; + + if (!(m_bitsDamageType & DMG_TIMEBASED)) + return; + + // only check for time based damage approx. every 2 seconds + if (abs(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(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 = 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 -= 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 -= 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 -= 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 != NULL ) + { // 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, 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(); + + // Track button info so we can detect 'pressed' and 'released' buttons next frame + m_afButtonLast = pev->button; + +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; + } + + +#else + return; +#endif +} + + +// 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_flFlashLightTime = 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, 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 ( 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 ( 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(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->ResetThink(); + 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, 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() +{ + static int fInSelect = FALSE; + + // check if the player is using a tank + if ( m_pTank != NULL ) + 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; + 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) + { + int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent + + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); + WRITE_BYTE( iHealth ); + MESSAGE_END(); + + m_iClientHealth = pev->health; + } + + + if (pev->armorvalue != m_iClientBattery) + { + m_iClientBattery = 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( pev->dmg_save ); + WRITE_BYTE( 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 = m_vecAutoAim.x; + m_lasty = 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 ) + { + g_pGameRules->GetNextBestWeapon( this, pWeapon ); + + 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 char *m_szPoses[4]; +}; + +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(), pev->renderamt, FFADE_OUT ); + pev->nextthink = gpGlobals->time + MessageTime(); + SetThink( MessageThink ); +} + + +void CRevertSaved :: MessageThink( void ) +{ + UTIL_ShowMessageAll( STRING(pev->message) ); + float nextThink = LoadTime() - MessageTime(); + if ( nextThink > 0 ) + { + pev->nextthink = gpGlobals->time + nextThink; + SetThink( 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/dlls/player.h b/dlls/player.h new file mode 100644 index 00000000..cbf95809 --- /dev/null +++ b/dlls/player.h @@ -0,0 +1,324 @@ +/*** +* +* 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: + 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, char *szName, int iMax ); + void SendAmmoUpdate(void); + + void WaterMove( void ); + void EXPORT PlayerDeathThink( void ); + void PlayerUse( void ); + + void CheckSuitUpdate(); + void SetSuitUpdate(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 CBasePlayer::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/dlls/playermonster.cpp b/dlls/playermonster.cpp new file mode 100644 index 00000000..bb0a86ac --- /dev/null +++ b/dlls/playermonster.cpp @@ -0,0 +1,122 @@ +//========= Copyright © 1996-2002, 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/dlls/prop.cpp b/dlls/prop.cpp new file mode 100644 index 00000000..3f4f0a98 --- /dev/null +++ b/dlls/prop.cpp @@ -0,0 +1,1146 @@ +/*** +* +* 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. +* +****/ +/* + +===== 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" +#include "player.h" +#include "explode.h" +#include "gamerules.h" + +#define SF_PROP_RESPAWN 8 // enable autorespawn +#define SF_PROP_BREAKABLE 16 // enable break/explode +#define SF_PROP_FIXED 32 // don't move untill touch +typedef enum { expRandom, expDirected} Explosions; +typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; + +//extern "C" void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +Vector UTIL_AngleVectorsF(const Vector &angles) +{ + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, rgflVecOut, NULL, NULL); + return Vector(rgflVecOut); +} +Vector UTIL_AngleVectorsR(const Vector &angles) +{ + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); + return Vector(rgflVecOut); +} +Vector UTIL_AngleVectorsU(const Vector &angles) +{ + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); + return Vector(rgflVecOut); +} +//===================grenade + +enum PropShape +{ + SHAPE_CYL_H = 0, + SHAPE_CYL_V, + SHAPE_BOX, + SHAPE_GENERIC, + SHAPE_SPHERE, + SHAPE_NOROTATE +}; + +class CProp : public CBaseEntity +{ +public: + void Spawn(void); + void Precache(); + + void EXPORT BounceTouch(CBaseEntity *pOther); + //void EXPORT SlideTouch(CBaseEntity *pOther); + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + virtual void Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + virtual int ObjectCaps(void) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE; } + virtual void BounceSound(void); + virtual int BloodColor(void) { return DONT_BLEED; } + virtual void Killed(entvars_t *pevAttacker, int iGib); + void CheckRotate(); + void RespawnThink(); + void AngleThink(); + void DeployThink(); + void DamageSound( void ); + void PropRespawn(); + void KeyValue( KeyValueData* pkvd); + + static const char *pSoundsWood[]; + static const char *pSoundsFlesh[]; + static const char *pSoundsGlass[]; + static const char *pSoundsMetal[]; + static const char *pSoundsConcrete[]; + static const char *pSpawnObjects[]; + + 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 ); + void EXPORT Die( void ); + + BOOL m_bBarrel; + float m_flFloorFriction; + float m_flCollideFriction; + + // hull sizes + Vector minsH, maxsH; + Vector minsV, maxsV; + + // spawn backup; + Vector spawnOrigin; + Vector spawnAngles; + + edict_t *m_owner2; + edict_t *m_attacker; + float m_flNextAttack; + float m_flRespawnTime; + PropShape m_shape; + PropShape m_oldshape; + CBasePlayer *m_pHolstered; + float m_flSpawnHealth; + int m_idShard; + float m_angle; + int m_iszGibModel; + Materials m_Material; + Explosions m_Explosion; + int m_iaCustomAnglesX[10]; + int m_iaCustomAnglesZ[10]; +}; +LINK_ENTITY_TO_CLASS(prop, CProp); + +const char *CProp::pSoundsWood[] = +{ + "debris/wood1.wav", + "debris/wood2.wav", + "debris/wood3.wav", +}; + +const char *CProp::pSoundsFlesh[] = +{ + "debris/flesh1.wav", + "debris/flesh2.wav", + "debris/flesh3.wav", + "debris/flesh5.wav", + "debris/flesh6.wav", + "debris/flesh7.wav", +}; + +const char *CProp::pSoundsMetal[] = +{ + "debris/metal1.wav", + "debris/metal2.wav", + "debris/metal3.wav", +}; + +const char *CProp::pSoundsConcrete[] = +{ + "debris/concrete1.wav", + "debris/concrete2.wav", + "debris/concrete3.wav", +}; + + +const char *CProp::pSoundsGlass[] = +{ + "debris/glass1.wav", + "debris/glass2.wav", + "debris/glass3.wav", +}; + +const char **CProp::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 CProp::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 CProp::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 CProp::Precache( void ) +{ + const char *pGibName; + + 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; + } + MaterialSoundPrecache( m_Material ); + if ( m_iszGibModel ) + pGibName = STRING(m_iszGibModel); + + m_idShard = PRECACHE_MODEL( (char *)pGibName ); + PRECACHE_MODEL( (char *)STRING(pev->model) ); +} + +void CProp::DamageSound( void ) +{ + int pitch; + float fvol; + char *rgpsz[6]; + int i; + 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 CProp::Die( void ) +{ + Vector vecSpot;// shard origin + Vector vecVelocity;// shard velocity + CBaseEntity *pEntity = NULL; + 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) + (fabs(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; + } + + + 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 ); + + if ( Explodable() ) + { + ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), TRUE ); + } +} + +void CProp::Killed(entvars_t *pevAttacker, int iGib) +{ + pev->takedamage = DAMAGE_NO; + pev->deadflag = DEAD_DEAD; + pev->solid = SOLID_NOT; + pev->effects |= EF_NODRAW; + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( CProp::RespawnThink ); + ResetTouch( ); + ResetUse( ); +} + +void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +{ + if (m_owner2 != pActivator->edict()) + { + if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + { + m_owner2 = m_attacker = pActivator->edict(); + } + else + return; + } + if( pActivator->IsPlayer() ) + { + m_pHolstered = (CBasePlayer *) pActivator; + if( m_pHolstered ) + { + + if ( m_pHolstered->m_pActiveItem ) + { + CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); + + + //m_Holstered->m_pActiveItem->Holster(); // strange bug here. ValveWHY? + + // HACK: prevent attack + if( weapon ) + { + weapon->m_flNextPrimaryAttack += 0.1; + weapon->m_flNextSecondaryAttack += 0.1; + } + m_pHolstered->m_iHideHUD |= HIDEHUD_WEAPONS; + m_pHolstered->pev->weaponmodel = 0; + m_pHolstered->pev->viewmodel = 0; + } + SetThink( CProp::DeployThink ); + pev->nextthink = gpGlobals->time + 0.2; + } + } + Vector target = pActivator->pev->origin + UTIL_GetAimVector(m_owner2, 1000) * 50; + target.z = target.z + 32; + pev->velocity = (target - VecBModelOrigin(pev)) * 10; + Vector atarget = UTIL_VecToAngles(UTIL_GetAimVector(m_owner2, 1000)); + pev->angles.x = UTIL_AngleMod(pev->angles.x); + pev->angles.y = UTIL_AngleMod(pev->angles.y); + pev->angles.z = UTIL_AngleMod(pev->angles.z); + atarget.x = UTIL_AngleMod(atarget.x); + atarget.y = UTIL_AngleMod(atarget.y); + atarget.z = UTIL_AngleMod(atarget.z); + pev->avelocity.x = UTIL_AngleDiff(atarget.x, pev->angles.x) * 10; + pev->avelocity.y = UTIL_AngleDiff(atarget.y, pev->angles.y) * 10; + pev->avelocity.z = UTIL_AngleDiff(atarget.z, pev->angles.z) * 10; + //pev->angles.z += (0 - pev->angles.z) * 0.06; + if ((pActivator->pev->button & (IN_ATTACK))) + { + pev->velocity = UTIL_GetAimVector(m_owner2, 1000) * 1000; + pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + } + if ((pActivator->pev->button & (IN_ATTACK2))) + { + //m_Horizontal = false; + //pev->angles.z = 0; + } + // m_Horizontal = (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || ( sin(pev->angles.x/180*M_PI) > 0.1); + // CheckRotate(); + //ALERT( at_console, "Prop use!\n"); +} + +void CProp::Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +{ + if (m_owner2 != pActivator->edict()) + { + if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + m_attacker = pActivator->edict(); + else + return; + } + + if ((pActivator->pev->button & (IN_ATTACK))) + { + pev->velocity = UTIL_GetAimVector(m_owner2, 3000) * 1000; + pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + } + if ((pActivator->pev->button & (IN_ATTACK2))) + { + //m_Horizontal = false; + //pev->angles.z = 0; + } + + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink(CProp::RespawnThink); +} + +void CProp::CheckRotate() +{ + if( m_shape != SHAPE_CYL_H && m_shape != SHAPE_CYL_V ) + { + UTIL_SetSize(pev, minsH, maxsH); + return; + } + if( (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || + (fabs(sin(pev->angles.x / 180 * M_PI)) > 0.3) ) + m_shape = SHAPE_CYL_H; + else + m_shape = SHAPE_CYL_V; + + if (m_oldshape != m_shape) + { + + if (m_shape == SHAPE_CYL_H) + { + pev->angles.y += 90; + + ALERT(at_console, "setHorizontal: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); + + UTIL_SetSize(pev, minsH, maxsH); + } + else if (m_shape == SHAPE_CYL_V) + { + Vector mins = pev->absmin; + Vector maxs = pev->absmax; + + mins.z = pev->absmax.z; + maxs.z += 10; + + // BUGBUG -- can only find 256 entities on a prop -- 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++ ) + { + pList[i]->pev->origin.z += 10; + } + } + pev->origin.z += 10; + //pev->angles.y -= 90; + UTIL_SetSize(pev, minsV, maxsV); + } + //DROP_TO_FLOOR(edict()); + //pev->origin.z += 0.5; + m_oldshape = m_shape; + } +} + +void CProp::DeployThink( void ) +{ + if( m_pHolstered ) + { + if( m_pHolstered->m_pActiveItem ) + { + m_pHolstered->m_pActiveItem->Deploy(); + CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); + if( weapon ) + { + weapon->m_flNextPrimaryAttack = 0; + weapon->m_flNextSecondaryAttack = 0; + } + } + m_pHolstered ->m_iHideHUD &= ~HIDEHUD_WEAPONS; + m_pHolstered = NULL; + } + if( m_pfnThink == &CProp::DeployThink ) + { + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( CProp::RespawnThink ); + } +} + +void CProp::BounceTouch(CBaseEntity *pOther) +{ + //ALERT( at_console, "BounceTouch: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); + // only do damage if we're moving fairly fast + DeployThink(); + + if ( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 300) + { + entvars_t *pevOwner = VARS(m_attacker); + if (pevOwner) + { + float dmg = 50 + pev->velocity.Length() / 40; + if (pOther->edict() == m_owner2) + { + dmg = 5; + if (pOther->pev->button & (IN_USE)) + { + dmg = 1; + } + } + TraceResult tr = UTIL_GetGlobalTrace(); + ClearMultiDamage(); + pOther->TraceAttack(pevOwner, dmg, gpGlobals->v_forward, &tr, DMG_CLUB); + ApplyMultiDamage(pev, pevOwner); + } + m_flNextAttack = gpGlobals->time + 1.0; // debounce + } + if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 700) ) + { + Killed( VARS(m_attacker), GIB_NORMAL ); + Die(); + } + + pev->velocity = pev->velocity + pOther->pev->velocity; + float dp = cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y)); + if (pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40) + { + CheckRotate(); + if (m_shape == SHAPE_CYL_H) + { + + pev->velocity.x *= fabs(dp) * 0.8 + 0.2; + pev->velocity.y *= fabs(dp) * 0.8 + 0.2; + pev->velocity.z -= 20; + pev->avelocity.x = -dp*pev->velocity.Length()* 1.5; + pev->avelocity.y = 0; + pev->avelocity.z = 0; + pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; + //AngleThink(); + } + else if (m_shape == SHAPE_CYL_V) + { + // pev->angles.z *= 0.3; + //pev->angles.x *= 0.3; + //AngleThink(); + //CheckRotate(); + pev->velocity.z *= m_flFloorFriction; + pev->velocity.x *= m_flFloorFriction; + pev->velocity.y *= m_flFloorFriction; + pev->velocity.z -= 10; + pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(30, -30); + } + else if( m_shape == SHAPE_SPHERE ) + { + pev->velocity.z -= 20; + pev->avelocity.x = -cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5; + pev->avelocity.y = -sin(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5;; + pev->avelocity.z = 0; + } + else if( m_shape == SHAPE_BOX || m_shape == SHAPE_GENERIC ) + { + pev->velocity.z *= m_flFloorFriction; + pev->velocity.x *= m_flFloorFriction; + pev->velocity.y *= m_flFloorFriction; + pev->velocity.z -= 10; + } + + } + else + { + { + pev->velocity.z *= 0.3; + pev->velocity.y *= m_flCollideFriction; + pev->velocity.x *= m_flCollideFriction; + if( m_shape != SHAPE_SPHERE ) + { + pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + } + } + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 1, -1 ); + BounceSound(); + } + pev->framerate = pev->velocity.Length() / 200.0; + if (pev->framerate > 1.0) + pev->framerate = 1; + else if (pev->framerate < 0.2) + { + CheckRotate(); + AngleThink(); + if (pev->angles.z == 0 || pev->angles.z == 90) + pev->framerate = 0; + else + pev->framerate = 0.2; + } +} + +void CProp::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 CProp::Spawn(void) +{ + + Precache(); + + if( !pev->model ) + pev->model = MAKE_STRING( "models/xash/barrel_brown.mdl" ); + + if( minsH == g_vecZero ) + { + // default barrel parameters + minsV = Vector(-10, -10, -17); + maxsV = Vector(10, 10, 18); + minsH = Vector(-10, -10, -10); + maxsH = Vector(10, 10, 13); + } + m_flCollideFriction = 0.7; + m_flFloorFriction = 0.5; + spawnOrigin = pev->origin; + spawnAngles = pev->angles; + m_flSpawnHealth = pev->health; + if( !m_flRespawnTime ) + m_flRespawnTime = 20; + pev->dmg = 100; + PropRespawn(); +} + +void CProp::PropRespawn() +{ + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_SLIDEBOX; + pev->angles = spawnAngles; + pev->takedamage = DAMAGE_YES; + pev->velocity = pev->avelocity = g_vecZero; + SET_MODEL( ENT(pev), STRING(pev->model) ); + UTIL_SetOrigin( pev, spawnOrigin ); + m_oldshape = (PropShape)-1; + CheckRotate(); + pev->health = m_flSpawnHealth; + SetTouch(CProp::BounceTouch); + SetUse(CProp::Use); + pev->effects &= ~EF_NODRAW; + pev->framerate = 1.0f; +} + +void CProp::RespawnThink() +{ + if( !(pev->spawnflags & SF_PROP_RESPAWN)) + return; + PropRespawn(); +} + + + +void CProp::AngleThink() +{ + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink(CProp::RespawnThink); + if (!(pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40)) + { + m_owner2 = m_attacker = 0; + return; + } + if (m_shape == SHAPE_CYL_H) + { + pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; + if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + { + SetThink(CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + //ALERT( at_console, "AngleThink: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); + pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_CYL_V) + { + if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + { + SetThink(CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.z += UTIL_AngleDiff(0, pev->angles.z) * 0.7; + //pev->angles.x += UTIL_AngleDiff( 0, pev->angles.x ) * 0.3; + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_BOX) + { + Vector iangles; + iangles.x = round( pev->angles.x / 90 ) * 90; + iangles.y = round( pev->angles.y / 90 ) * 90; + iangles.z = round( pev->angles.z / 90 ) * 90; + if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || + //fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + { + SetThink(CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; + //pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; + pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_NOROTATE) + { + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + Vector iangles = spawnAngles; + if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + { + SetThink(CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; + pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; + pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + } + else if (m_shape == SHAPE_GENERIC) + { + float ianglex = 0, ianglez = 0, imaxanglediff=360.0f; + // if first number is zero, it is angle + // all other zeroes is array end + for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesX[i] ); i++) + { + float anglediff = fabs(UTIL_AngleDiff(pev->angles.x, m_iaCustomAnglesX[i])); + if( imaxanglediff > anglediff ) + { + ianglex = m_iaCustomAnglesX[i]; + imaxanglediff = anglediff; + } + } + imaxanglediff=360.0f; + for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesZ[i] ); i++) + { + float anglediff = fabs(UTIL_AngleDiff(pev->angles.z, m_iaCustomAnglesZ[i])); + if( imaxanglediff > anglediff ) + { + ianglez = m_iaCustomAnglesZ[i]; + imaxanglediff = anglediff; + } + } + if (fabs(UTIL_AngleDiff(ianglex, pev->angles.x)) > 0.1 || + fabs(UTIL_AngleDiff(ianglez, pev->angles.z)) > 0.1 ) + { + SetThink(CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(ianglex, pev->angles.x) * 0.6; + pev->angles.z += UTIL_AngleDiff(ianglez, pev->angles.z) * 0.6; + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + pev->angles.x = UTIL_AngleMod(pev->angles.x); + pev->angles.y = UTIL_AngleMod(pev->angles.y); + pev->angles.z = UTIL_AngleMod(pev->angles.z); +} + + +int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +{ + Vector r = (pevInflictor->origin - pev->origin); + if (flDamage > 200 && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) + m_attacker = ENT(pevAttacker); + DeployThink(); + + pev->velocity = r * flDamage / -7; + pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + + // now some func_breakable code + + if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) + 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; + g_vecAttackDir = r.Normalize(); + + // do the damage + pev->health -= flDamage; + if (pev->health <= 0) + { + Killed( VARS(m_attacker), 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 CProp::KeyValue( KeyValueData* pkvd ) +{ + ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue); + // 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, "shape")) + { + int i = atoi( pkvd->szValue); + + if ((i < 0) || (i >= SHAPE_NOROTATE)) + m_shape = SHAPE_NOROTATE; + else + m_shape = (PropShape)i; + + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "gibmodel") ) + { + m_iszGibModel = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) + { + ExplosionSetMagnitude( atoi( pkvd->szValue ) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "respawntime") ) + { + m_flRespawnTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "customanglesx")) + { + UTIL_StringToIntArray( m_iaCustomAnglesX, ARRAYSIZE( m_iaCustomAnglesX ), pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "customanglesz")) + { + UTIL_StringToIntArray( m_iaCustomAnglesZ, ARRAYSIZE( m_iaCustomAnglesZ ), pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "hmin")) + { + UTIL_StringToVector( minsH, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "hmax")) + { + UTIL_StringToVector( maxsH, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "vmin")) + { + UTIL_StringToVector( minsV, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "vmax")) + { + UTIL_StringToVector( maxsV, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} diff --git a/dlls/python.cpp b/dlls/python.cpp new file mode 100644 index 00000000..37574488 --- /dev/null +++ b/dlls/python.cpp @@ -0,0 +1,320 @@ +/*** +* +* 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_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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_WeaponTimeBase() + 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 + + if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) + { + m_flSoundDelay = 1.5; + } +} + + +void CPython::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); + if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) + { + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); + m_flSoundDelay = 0; + } + + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0f, 1.0f ); + if (flRand <= 0.5) + { + iAnim = PYTHON_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (70.0/30.0); + } + else if (flRand <= 0.7) + { + iAnim = PYTHON_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/30.0); + } + else if (flRand <= 0.9) + { + iAnim = PYTHON_IDLE3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (88.0/30.0); + } + else + { + iAnim = PYTHON_FIDGET; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (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 \ No newline at end of file diff --git a/dlls/rat.cpp b/dlls/rat.cpp new file mode 100644 index 00000000..0d4c8fb6 --- /dev/null +++ b/dlls/rat.cpp @@ -0,0 +1,98 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/roach.cpp b/dlls/roach.cpp new file mode 100644 index 00000000..3c13bf1c --- /dev/null +++ b/dlls/roach.cpp @@ -0,0 +1,460 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/rpg.cpp b/dlls/rpg.cpp new file mode 100644 index 00000000..a14eaa3c --- /dev/null +++ b/dlls/rpg.cpp @@ -0,0 +1,618 @@ +/*** +* +* 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( Revive ); + pev->nextthink = gpGlobals->time + flSuspendTime; +} + +//========================================================= +// Revive - bring a suspended laser sight back. +//========================================================= +void CLaserSpot::Revive( void ) +{ + pev->effects &= ~EF_NODRAW; + + ResetThink(); +} + +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( IgniteThink ); + SetTouch( 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( 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; + + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; + } + else + { + PlayEmptySound( ); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; + } + 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 \ No newline at end of file diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp new file mode 100644 index 00000000..7c5ff451 --- /dev/null +++ b/dlls/satchel.cpp @@ -0,0 +1,494 @@ +/*** +* +* 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( SatchelSlide ); + SetUse( DetonateUse ); + SetThink( 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 ) +{ + entvars_t *pevOther = pOther->pev; + + // 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 = UTIL_WeaponTimeBase() + 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] ) + { + Vector vecSrc = m_pPlayer->pev->origin; + + Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; + +#ifndef CLIENT_DLL + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 \ No newline at end of file diff --git a/dlls/saverestore.h b/dlls/saverestore.h new file mode 100644 index 00000000..c774b62d --- /dev/null +++ b/dlls/saverestore.h @@ -0,0 +1,169 @@ +/*** +* +* 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 ); + ~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 ); +}; + + +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, const int *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; +}; + +extern CGlobalState gGlobalState; + +#endif //SAVERESTORE_H diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp new file mode 100644 index 00000000..75886699 --- /dev/null +++ b/dlls/schedule.cpp @@ -0,0 +1,1514 @@ +/*** +* +* 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; + + ResetThink(); + 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/dlls/schedule.h b/dlls/schedule.h new file mode 100644 index 00000000..f73e8953 --- /dev/null +++ b/dlls/schedule.h @@ -0,0 +1,290 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/scientist.cpp b/dlls/scientist.cpp new file mode 100644 index 00000000..b80623ff --- /dev/null +++ b/dlls/scientist.cpp @@ -0,0 +1,1428 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL ) + 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 == NULL ) + { + 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; + } + + 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( 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 ) +{ + ResetUse(); + 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; + } + + 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 = NULL; + return m_IdealMonsterState; + } + // Follow if only scared a little + if ( m_hTargetEnt != NULL ) + { + 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; + } + + return CTalkMonster::GetIdealState(); +} + + +BOOL CScientist::CanHeal( void ) +{ + if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (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 char *m_szPoses[7]; +}; +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 (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/dlls/scripted.cpp b/dlls/scripted.cpp new file mode 100644 index 00000000..3767a508 --- /dev/null +++ b/dlls/scripted.cpp @@ -0,0 +1,1260 @@ +/*** +* +* 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. +* +****/ +/* + + +===== 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( 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( 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( 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( 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 ) ) + { + ResetUse(); // BUGBUG -- This doesn't call Killed() + ResetThink(); // This will probably break some stuff + ResetTouch(); + } + 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( 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( 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( 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( FindThink ); +} + + +BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) +{ + if ( pMonster ) + { + if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) + { + if ( pMonster->m_hTargetEnt == NULL || !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 NULL; + } + + 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 ( 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/dlls/scripted.h b/dlls/scripted.h new file mode 100644 index 00000000..67a2eb13 --- /dev/null +++ b/dlls/scripted.h @@ -0,0 +1,107 @@ +/*** +* +* 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. +* +****/ +#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/dlls/scriptevent.h b/dlls/scriptevent.h new file mode 100644 index 00000000..9a02bd64 --- /dev/null +++ b/dlls/scriptevent.h @@ -0,0 +1,29 @@ +/*** +* +* 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/dlls/shotgun.cpp b/dlls/shotgun.cpp new file mode 100644 index 00000000..dfa084b8 --- /dev/null +++ b/dlls/shotgun.cpp @@ -0,0 +1,401 @@ +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp new file mode 100644 index 00000000..b71b96a1 --- /dev/null +++ b/dlls/singleplay_gamerules.cpp @@ -0,0 +1,328 @@ +/*** +* +* 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/dlls/skill.cpp b/dlls/skill.cpp new file mode 100644 index 00000000..7c0b8529 --- /dev/null +++ b/dlls/skill.cpp @@ -0,0 +1,47 @@ +/*** +* +* 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( char *pName ) +{ + int iCount; + float flValue; + char szBuffer[ 64 ]; + + iCount = 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/dlls/skill.h b/dlls/skill.h new file mode 100644 index 00000000..44340711 --- /dev/null +++ b/dlls/skill.h @@ -0,0 +1,147 @@ +/*** +* +* 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( char *pName ); + +extern DLL_GLOBAL int g_iSkillLevel; + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 diff --git a/dlls/sound.cpp b/dlls/sound.cpp new file mode 100644 index 00000000..174e5f97 --- /dev/null +++ b/dlls/sound.cpp @@ -0,0 +1,1978 @@ +/*** +* +* 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" + + +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( 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(RampThink); + pev->nextthink = 0; + + // allow on/off switching via 'use' function. + + SetUse ( 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 = 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 = 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) + 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]; + 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 ) +{ + char* szSoundFile = (char*) 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( SUB_Remove ); + return; + } + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + + + SetThink(SpeakerThink); + pev->nextthink = 0.0; + + // allow on/off switching via 'use' function. + + SetUse ( 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 ) +{ + char* szSoundFile; + 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 ); +} \ No newline at end of file diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp new file mode 100644 index 00000000..93c70a7e --- /dev/null +++ b/dlls/soundent.cpp @@ -0,0 +1,379 @@ +/*** +* +* 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; + 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; + + 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; +} \ No newline at end of file diff --git a/dlls/soundent.h b/dlls/soundent.h new file mode 100644 index 00000000..2393cb40 --- /dev/null +++ b/dlls/soundent.h @@ -0,0 +1,95 @@ +/*** +* +* 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/dlls/spectator.cpp b/dlls/spectator.cpp new file mode 100644 index 00000000..9d6bef9d --- /dev/null +++ b/dlls/spectator.cpp @@ -0,0 +1,149 @@ +/*** +* +* 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/dlls/spectator.h b/dlls/spectator.h new file mode 100644 index 00000000..f832621a --- /dev/null +++ b/dlls/spectator.h @@ -0,0 +1,27 @@ +/*** +* +* 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); +}; \ No newline at end of file diff --git a/dlls/squad.h b/dlls/squad.h new file mode 100644 index 00000000..5f9f2499 --- /dev/null +++ b/dlls/squad.h @@ -0,0 +1,20 @@ +//========= Copyright © 1996-2002, 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 ) \ No newline at end of file diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp new file mode 100644 index 00000000..d0a65ba1 --- /dev/null +++ b/dlls/squadmonster.cpp @@ -0,0 +1,623 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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] == NULL) + { + 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 != NULL) + { + // 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 != NULL ) + { + 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 ) +{ + 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: + case MONSTERSTATE_ALERT: + if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) + { + SquadMakeEnemy ( m_hEnemy ); + } + 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 != NULL && 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/dlls/squadmonster.h b/dlls/squadmonster.h new file mode 100644 index 00000000..f5297876 --- /dev/null +++ b/dlls/squadmonster.h @@ -0,0 +1,120 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL; } + 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/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp new file mode 100644 index 00000000..b3b34edc --- /dev/null +++ b/dlls/squeakgrenade.cpp @@ -0,0 +1,601 @@ +/*** +* +* 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 != NULL) + { + 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( SuperBounceTouch ); + SetThink( 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( SUB_Remove ); + ResetTouch(); + 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 != NULL) + 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 != NULL) + 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()) + { + ResetTouch(); + 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; + + CBaseEntity *pOther = NULL; + Vector vecDir; + TraceResult tr; + + Vector vecFlat = pev->velocity; + vecFlat.z = 0; + vecFlat = vecFlat.Normalize( ); + + UTIL_MakeVectors( pev->angles ); + + if (m_hEnemy == NULL || !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 != NULL) + { + 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 != NULL) + 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 = UTIL_WeaponTimeBase() + 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 \ No newline at end of file diff --git a/dlls/stats.cpp b/dlls/stats.cpp new file mode 100644 index 00000000..3323c1ca --- /dev/null +++ b/dlls/stats.cpp @@ -0,0 +1,156 @@ +//========= Copyright © 1996-2002, 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/dlls/subs.cpp b/dlls/subs.cpp new file mode 100644 index 00000000..a1093661 --- /dev/null +++ b/dlls/subs.cpp @@ -0,0 +1,559 @@ +/*** +* +* 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( 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( 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 ) +{ + 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( 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/dlls/talkmonster.cpp b/dlls/talkmonster.cpp new file mode 100644 index 00000000..bf4bbe87 --- /dev/null +++ b/dlls/talkmonster.cpp @@ -0,0 +1,1472 @@ +/*** +* +* 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. +* +****/ +#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 +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 != NULL) + { + 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 != NULL) + { + // 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 != NULL) + { + // 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 != NULL) + { + 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(); + ResetUse(); + CBaseMonster::Killed( pevAttacker, iGib ); +} + + + +CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) +{ + CBaseEntity *pFriend = pPrevious; + 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 == NULL || !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; + 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 ) +{ + int pitch = GetVoicePitch(); + + // 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 != NULL && 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 + int pitch; + 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); + + } + + pitch = GetVoicePitch(); + + // 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 = NULL; + if ( clearSchedule ) + ClearSchedule(); + if ( m_hEnemy != NULL ) + m_IdealMonsterState = MONSTERSTATE_COMBAT; + } +} + + +void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) +{ + if ( m_pCine ) + m_pCine->CancelScript(); + + if ( m_hEnemy != NULL ) + 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/dlls/talkmonster.h b/dlls/talkmonster.h new file mode 100644 index 00000000..d59c55f4 --- /dev/null +++ b/dlls/talkmonster.h @@ -0,0 +1,183 @@ +/*** +* +* 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. +* +****/ +#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 != NULL && 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 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/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp new file mode 100644 index 00000000..db99778f --- /dev/null +++ b/dlls/teamplay_gamerules.cpp @@ -0,0 +1,630 @@ +/*** +* +* 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 = 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; + + int slot = atoi( CMD_ARGV(1) ); + + // 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 ); + int clientIndex = pPlayer->entindex(); + 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( 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] += 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/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h new file mode 100644 index 00000000..c7c351e6 --- /dev/null +++ b/dlls/teamplay_gamerules.h @@ -0,0 +1,57 @@ +/*** +* +* 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/dlls/tempmonster.cpp b/dlls/tempmonster.cpp new file mode 100644 index 00000000..2ad893f1 --- /dev/null +++ b/dlls/tempmonster.cpp @@ -0,0 +1,117 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 0 diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp new file mode 100644 index 00000000..ef3ab574 --- /dev/null +++ b/dlls/tentacle.cpp @@ -0,0 +1,1044 @@ +/*** +* +* 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. +* +****/ +#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( Start ); + SetTouch( HitTouch ); + SetUse( 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 (m_flSoundTime < gpGlobals->time) + { + // play "I hear new something" sound + 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); + } + 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 + char *sound; + + 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( 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( 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 ) +{ + char *sound; + + 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( 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 \ No newline at end of file diff --git a/dlls/trains.h b/dlls/trains.h new file mode 100644 index 00000000..4ee44112 --- /dev/null +++ b/dlls/trains.h @@ -0,0 +1,127 @@ +/*** +* +* 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/dlls/triggers.cpp b/dlls/triggers.cpp new file mode 100644 index 00000000..a75cbbca --- /dev/null +++ b/dlls/triggers.cpp @@ -0,0 +1,2434 @@ +/*** +* +* 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( 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 ( ManagerUse ); + SetThink ( 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? + { + ResetThink(); + if ( IsClone() ) + { + UTIL_Remove( this ); + return; + } + SetUse ( 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; + + ResetUse();// disable use until all targets have fired + + SetThink ( 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( ToggleUse ); + } +} + + +void CTriggerMonsterJump :: Think( void ) +{ + pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE + UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list + ResetThink(); +} + +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 pause\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 ); + + ResetTouch(); + 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 ( HurtTouch ); + + if ( !FStringNull ( pev->targetname ) ) + { + SetUse ( ToggleUse ); + } + else + { + ResetUse(); + } + + if (m_bitsDamageInflict & DMG_RADIATION) + { + SetThink ( 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( 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( 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... + ResetTouch(); + pev->nextthink = gpGlobals->time + 0.1; + SetThink( 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; +// } + ResetThink(); +} + + +// ========================= 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( 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 = NULL; + 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\n", m_szMapName ); + + if (!FStringNull ( pev->targetname ) ) + { + SetUse ( UseChangeLevel ); + } + InitTrigger(); + if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) + SetTouch( 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; + LEVELLIST levels[16]; + + 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; + + // this flag was changed and flying barrels on c2a5 stay broken + if ( FStrEq( STRING( gpGlobals->mapname ), "c2a5" ) && pev->spawnflags & 4) + pev->spawnflags |= SF_TRIG_PUSH_ONCE; + + if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. + pev->solid = SOLID_NOT; + + SetUse( 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( 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( SaveTouch ); +} + +void CTriggerSave::SaveTouch( CBaseEntity *pOther ) +{ + if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) + return; + + // Only save on clients + if ( !pOther->IsPlayer() ) + return; + + ResetTouch(); + 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; + + ResetUse(); + + 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 ( EndSectionUse ); + // If it is a "use only" trigger, then don't set the touch function. + if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) + SetTouch( EndSectionTouch ); +} + +void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) +{ + // Only save on clients + if ( !pOther->IsNetClient() ) + return; + + ResetTouch(); + + 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( 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 == NULL ) + { + 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( FollowTarget ); + pev->nextthink = gpGlobals->time; + + m_moveDistance = 0; + Move(); +} + + +void CTriggerCamera::FollowTarget( ) +{ + if (m_hPlayer == NULL) + return; + + if (m_hTarget == NULL || 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/dlls/tripmine.cpp b/dlls/tripmine.cpp new file mode 100644 index 00000000..6b039080 --- /dev/null +++ b/dlls/tripmine.cpp @@ -0,0 +1,526 @@ +/*** +* +* 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( 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( PowerupThink ); + pev->nextthink = gpGlobals->time + 1.0; +} + + +void CTripmineGrenade :: PowerupThink( void ) +{ + TraceResult tr; + + if (m_hOwner == NULL) + { + // 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( 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( 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.0, 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( 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 == NULL) + 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( 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( 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 *pEnt = 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 = UTIL_WeaponTimeBase() + 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/dlls/turret.cpp b/dlls/turret.cpp new file mode 100644 index 00000000..efd9b5a5 --- /dev/null +++ b/dlls/turret.cpp @@ -0,0 +1,1305 @@ +/*** +* +* 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. +* +****/ +/* + +===== 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( 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(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(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(AutoSearchThink); + pev->nextthink = gpGlobals->time + .1; + } + else + SetThink(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(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(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 == NULL)) + { + m_hEnemy = NULL; + m_flLastSight = gpGlobals->time + m_flMaxWait; + SetThink(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(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(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(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(AutoSearchThink); + pev->nextthink = gpGlobals->time + .1; + } + else + SetThink(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(ActiveThink); + m_iStartSpin = 0; + m_iSpin = 1; + } + else + { + pev->framerate += 0.075; + } + } + + if (m_iSpin) + { + SetThink(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; + } + //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 != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + + // Acquire Target + if (m_hEnemy == NULL) + { + Look(TURRET_RANGE); + m_hEnemy = BestVisibleEnemy(); + } + + // If we've found a target, spin up the barrel and start to attack + if (m_hEnemy != NULL) + { + m_flLastSight = 0; + m_flSpinUpTime = 0; + SetThink(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(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 != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + // Acquire Target + + if (m_hEnemy == NULL) + { + Look( TURRET_RANGE ); + m_hEnemy = BestVisibleEnemy(); + } + + if (m_hEnemy != NULL) + { + SetThink(Deploy); + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + } +} + + +void CBaseTurret :: TurretDeath( void ) +{ + BOOL iActive = FALSE; + + 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; + ResetThink(); + } +} + + + +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??? + + ResetUse(); + SetThink(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(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(SentryTouch); + SetThink(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( Deploy ); + ResetUse(); + 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??? + + ResetUse(); + SetThink(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 ) +{ + BOOL iActive = FALSE; + + 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; + ResetThink(); + } +} + diff --git a/dlls/util.cpp b/dlls/util.cpp new file mode 100644 index 00000000..ab27c186 --- /dev/null +++ b/dlls/util.cpp @@ -0,0 +1,2543 @@ +/*** +* +* 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 = 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 = 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 = 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 = gpGlobals->trace_allsolid; + tr.fStartSolid = gpGlobals->trace_startsolid; + tr.fInOpen = gpGlobals->trace_inopen; + tr.fInWater = 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 ) +{ + SET_ORIGIN(ENT(pev), 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( 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( 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 + sizeof(int *), // FIELD_FUNCTION + 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, const int *data, int count ) +{ + const char *functionName; + + functionName = NAME_FOR_FUNCTION( *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 < 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; + } + } + 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, (int *)(char *)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/dlls/util.h b/dlls/util.h new file mode 100644 index 00000000..ab3dfd5c --- /dev/null +++ b/dlls/util.h @@ -0,0 +1,548 @@ +/*** +* +* 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. +* +****/ +// +// Misc utility code +// +#ifndef ACTIVITY_H +#include "activity.h" +#endif + +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif + +#ifndef PHYSCALLBACK_H +#include "physcallback.h" +#endif + + +#include +#include +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 + (int)offset) +#define MAKE_STRING(str) ((int)str - (int)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 +#define M_PI 3.14159265358979323846 + +// Keeps clutter down a bit, when declaring external entity/global method prototypes +#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) +#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) + +// 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 +#ifdef _WIN32 +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ + extern "C" _declspec( dllexport ) void mapClassName( entvars_t *pev ); \ + void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } +#else +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" void mapClassName( entvars_t *pev ); void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } +#endif + + +// +// 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) +{ +#if _DEBUG + if ( !pent ) + ALERT( at_error, "Bad ent in OFFSET()\n" ); +#endif + return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); +} +inline EOFFSET OFFSET(entvars_t *pev) +{ +#if _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 }; +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( 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 < 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/dlls/vector.h b/dlls/vector.h new file mode 100644 index 00000000..c498c835 --- /dev/null +++ b/dlls/vector.h @@ -0,0 +1,112 @@ +/*** +* +* 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) { } + inline Vector2D(float X, float Y) { 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 + { + Vector2D vec2; + + 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) { } + inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { 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 \ No newline at end of file diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp new file mode 100644 index 00000000..4a28819a --- /dev/null +++ b/dlls/weapons.cpp @@ -0,0 +1,1580 @@ +/*** +* +* 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( DefaultTouch ); + SetThink( 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 (DefaultTouch); + ResetThink(); + +} + +//========================================================= +// 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->ResetTouch();// no touch + pNewWeapon->SetThink( 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_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 ) +{ + ResetTouch(); + SetThink(SUB_Remove); + pev->nextthink = gpGlobals->time + .1; +} + +void CBasePlayerItem::Kill( void ) +{ + ResetTouch(); + SetThink(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; + ResetTouch(); + ResetThink(); +} + +// 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( char *szViewModel, char *szWeaponModel, int iAnim, 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; + + 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( DefaultTouch ); +} + +CBaseEntity* CBasePlayerAmmo::Respawn( void ) +{ + pev->effects |= EF_NODRAW; + ResetTouch(); + + UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. + + SetThink( 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( DefaultTouch ); +} + +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) +{ + if ( !pOther->IsPlayer() ) + { + return; + } + + if (AddAmmo( pOther )) + { + if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) + { + Respawn(); + } + else + { + ResetTouch(); + SetThink(SUB_Remove); + pev->nextthink = gpGlobals->time + .1; + } + } + else if (gEvilImpulse101) + { + // evil impulse 101 hack, kill always + ResetTouch(); + SetThink(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; + + 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 ); +} + +//********************************************************* +// 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(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 ); + ResetTouch(); + 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->ResetThink();// crowbar may be trying to swing again, etc. + pWeapon->ResetTouch(); + 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, 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/dlls/weapons.h b/dlls/weapons.h new file mode 100644 index 00000000..aaa98247 --- /dev/null +++ b/dlls/weapons.h @@ -0,0 +1,1015 @@ +/*** +* +* 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/dlls/world.cpp b/dlls/world.cpp new file mode 100644 index 00000000..82a6e822 --- /dev/null +++ b/dlls/world.cpp @@ -0,0 +1,860 @@ +/*** +* +* 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" +#include "physcallback.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( 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 ( SUB_DoNothing ); + SetUse(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( 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 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( ); +} + +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 < 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 ); + + // g-cont. moved here to right restore global WaveHeight on save\restore level + CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); + + 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( 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 ); + + pev->spawnflags &= ~SF_WORLD_DARK; // g-cont. don't apply fade after save\restore + + if ( pev->spawnflags & SF_WORLD_TITLE ) + gDisplayTitle = TRUE; // display the game title if this key is set + else + gDisplayTitle = FALSE; + + pev->spawnflags &= ~SF_WORLD_TITLE; // g-cont. don't show logo after save\restore + + if ( pev->spawnflags & SF_WORLD_FORCETEAM ) + { + CVAR_SET_FLOAT( "mp_defaultteam", 1 ); + } + else + { + CVAR_SET_FLOAT( "mp_defaultteam", 0 ); + } + + // g-cont. moved here so cheats will working on restore level + g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? +} + + +// +// 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; + } + 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 ); +} + +// +// Xash3D physics interface +// + +typedef void ( *LINK_ENTITY_FN)( entvars_t *pev ); + +// +// attempt to create custom entity when default method is failed +// 0 - attempt to create, -1 - reject to create +// +int DispatchCreateEntity( edict_t *pent, const char *szName ) +{ +/* +#ifdef CREATE_ENTITY_TEST + // quake armor entities. we just replaced it with item_battery... + if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" )) + { + LINK_ENTITY_FN SpawnEdict; + + // ugly method to get acess with himself exports + SpawnEdict = (LINK_ENTITY_FN)GetProcAddress( GetModuleHandle( "hl" ), "item_battery" ); + + if( SpawnEdict != NULL ) // found the valid spawn + { + // BUGBUG: old classname hanging in memory + pent->v.classname = ALLOC_STRING( "item_battery" ); + +// ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); + + SpawnEdict( &pent->v ); + return 0; // handled + } + } +#endif +*/ + return -1; +} + +// +// run custom physics for each entity +// return 0 to use built-in engine physic +// +int DispatchPhysicsEntity( edict_t *pEdict ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pEdict); + + if( !pEntity ) + { +// ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); + return 0; // not initialized + } + + // NOTE: at this point pEntity assume to be valid +/* +#ifdef CUSTOM_PHYSICS_TEST + // test alien controller without physics, thinking only + if( FClassnameIs( pEntity->pev, "monster_alien_controller" )) + { + float thinktime; + + thinktime = pEntity->pev->nextthink; + if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime ) + return 1; + + if( thinktime < PHYSICS_TIME( )) + thinktime = PHYSICS_TIME(); // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + pEntity->pev->nextthink = 0.0f; + gpGlobals->time = thinktime; + + DispatchThink( pEdict ); + +#ifdef GRAVITY_TEST + // stupid fake gravity test + pEntity->pev->origin.z -= 1; + LINK_ENTITY( pEdict, true ); +#endif + + return 1; // handled + } +#endif +*/ + return 0; +} + +static physics_interface_t gPhysicsInterface = +{ + SV_PHYSICS_INTERFACE_VERSION, + DispatchCreateEntity, + DispatchPhysicsEntity, +}; + +int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ) +{ + if ( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) + { + return FALSE; + } + + // copy new physics interface + memcpy(&g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t)); + + // fill engine callbacks + memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) ); + + return TRUE; +} \ No newline at end of file diff --git a/dlls/wxdebug.h b/dlls/wxdebug.h new file mode 100644 index 00000000..321b1bcd --- /dev/null +++ b/dlls/wxdebug.h @@ -0,0 +1,137 @@ +#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/dlls/xen.cpp b/dlls/xen.cpp new file mode 100644 index 00000000..a52ea6b5 --- /dev/null +++ b/dlls/xen.cpp @@ -0,0 +1,584 @@ +/*** +* +* 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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 < 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 ) +{ + float flInterval = StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + +#if 0 + DispatchAnimEvents( flInterval ); + + switch( GetActivity() ) + { + default: + case ACT_IDLE: + break; + + } +#endif +} + + diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp new file mode 100644 index 00000000..234eafca --- /dev/null +++ b/dlls/zombie.cpp @@ -0,0 +1,346 @@ +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ) +{ + int pitch = 95 + RANDOM_LONG(0,9); + + // 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() +{ + int 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; + +} \ No newline at end of file diff --git a/engine/anorms.h b/engine/anorms.h new file mode 100644 index 00000000..c90f8d6f --- /dev/null +++ b/engine/anorms.h @@ -0,0 +1,177 @@ +/*** +* +* 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/engine/cdll_exp.h b/engine/cdll_exp.h new file mode 100644 index 00000000..07227057 --- /dev/null +++ b/engine/cdll_exp.h @@ -0,0 +1,69 @@ +/* +cdll_exp.h - exports for client +Copyright (C) 2013 Uncle Mike + +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. +*/ +#ifndef CDLL_EXP_H +#define CDLL_EXP_H + +// NOTE: ordering is important! +typedef struct cldll_func_s +{ + int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion ); + void (*pfnInit)( void ); + int (*pfnVidInit)( void ); + int (*pfnRedraw)( float flTime, int intermission ); + int (*pfnUpdateClientData)( client_data_t *cdata, float flTime ); + void (*pfnReset)( void ); + void (*pfnPlayerMove)( struct playermove_s *ppmove, int server ); + void (*pfnPlayerMoveInit)( struct playermove_s *ppmove ); + char (*pfnPlayerMoveTexture)( char *name ); + void (*IN_ActivateMouse)( void ); + void (*IN_DeactivateMouse)( void ); + void (*IN_MouseEvent)( int mstate ); + void (*IN_ClearStates)( void ); + void (*IN_Accumulate)( void ); + void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active ); + int (*CL_IsThirdPerson)( void ); + void (*CL_CameraOffset)( float *ofs ); + void *(*KB_Find)( const char *name ); + void (*CAM_Think)( void ); // camera stuff + void (*pfnCalcRefdef)( ref_params_t *pparams ); + int (*pfnAddEntity)( int type, cl_entity_t *ent, const char *modelname ); + void (*pfnCreateEntities)( void ); + void (*pfnDrawNormalTriangles)( void ); + void (*pfnDrawTransparentTriangles)( void ); + void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity ); + void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed ); + void (*pfnShutdown)( void ); + void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client ); + void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src ); + void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd ); + void (*pfnDemo_ReadBuffer)( int size, byte *buffer ); + int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size ); + int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs ); + void (*pfnFrame)( double time ); + int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding ); + void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp )); + cl_entity_t *(*pfnGetUserEntity)( int index ); + void (*pfnVoiceStatus)( int entindex, qboolean bTalking ); + void (*pfnDirectorMessage)( int iSize, void *pbuf ); + int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); + void (*pfnChatInputPosition)( int *x, int *y ); + int (*pfnGetPlayerTeam)( int playerIndex ); + void *(*pfnGetClientFactory)( void ); + // Xash3D extension + int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback ); + void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr ); +} cldll_func_t; + +#endif//CDLL_EXP_H \ No newline at end of file diff --git a/engine/cdll_int.h b/engine/cdll_int.h new file mode 100644 index 00000000..dd3b0a02 --- /dev/null +++ b/engine/cdll_int.h @@ -0,0 +1,308 @@ +/*** +* +* 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" + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +// this file is included by both the engine and the client-dll, +// so make sure engine declarations aren't done twice + +typedef int HSPRITE; // handle to a graphic +typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); + +#include "wrect.h" + +#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; + 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 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; + +typedef struct hud_player_info_s +{ + char *name; + short ping; + byte thisplayer; // TRUE if this is the calling player + + // stuff that's unused at the moment, but should be done + byte spectator; + byte packetloss; + char *model; + short topcolor; + short bottomcolor; + + unsigned long long m_nSteamID; +} hud_player_info_t; + +typedef struct cl_enginefuncs_s +{ + // sprite handlers + HSPRITE (*pfnSPR_Load)( const char *szPicName ); + int (*pfnSPR_Frames)( HSPRITE hPic ); + int (*pfnSPR_Height)( HSPRITE hPic, int frame ); + int (*pfnSPR_Width)( HSPRITE hPic, int frame ); + void (*pfnSPR_Set)( HSPRITE hPic, int r, int g, int b ); + void (*pfnSPR_Draw)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawHoles)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_EnableScissor)( int x, int y, int width, int height ); + void (*pfnSPR_DisableScissor)( void ); + client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount ); + + // screen handlers + void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetScreenInfo)( SCREENINFO *pscrinfo ); + void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b ); + + // cvar handlers + struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags ); + float (*pfnGetCvarFloat)( char *szName ); + char* (*pfnGetCvarString)( char *szName ); + + // command handlers + int (*pfnAddCommand)( char *cmd_name, void (*function)(void) ); + int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn ); + int (*pfnServerCmd)( char *szCmdString ); + int (*pfnClientCmd)( char *szCmdString ); + + void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo ); + + // sound handlers + void (*pfnPlaySoundByName)( char *szSound, float volume ); + void (*pfnPlaySoundByIndex)( int iSound, float volume ); + + // vector helpers + void (*pfnAngleVectors)( const float *vecAngles, float *forward, float *right, float *up ); + + // text message system + client_textmessage_t *(*pfnTextMessageGet)( const char *pName ); + int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b ); + int (*pfnDrawConsoleString)( int x, int y, char *string ); + void (*pfnDrawSetTextColor)( float r, float g, float b ); + void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); + + void (*pfnConsolePrint)( const char *string ); + void (*pfnCenterPrint)( const char *string ); + + // Added for user input processing + int (*GetWindowCenterX)( void ); + int (*GetWindowCenterY)( void ); + void (*GetViewAngles)( float * ); + void (*SetViewAngles)( float * ); + int (*GetMaxClients)( void ); + void (*Cvar_SetValue)( char *cvar, float value ); + + int (*Cmd_Argc)( void ); + char *(*Cmd_Argv)( int arg ); + void (*Con_Printf)( char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_NPrintf)( int pos, char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + + const char* (*PhysInfo_ValueForKey)( const char *key ); + const char* (*ServerInfo_ValueForKey)( const char *key ); + float (*GetClientMaxspeed)( void ); + int (*CheckParm)( char *parm, char **ppnext ); + + void (*Key_Event)( int key, int down ); + void (*GetMousePosition)( int *mx, int *my ); + int (*IsNoClipping)( void ); + + struct cl_entity_s *(*GetLocalPlayer)( void ); + struct cl_entity_s *(*GetViewModel)( void ); + struct cl_entity_s *(*GetEntityByIndex)( int idx ); + + float (*GetClientTime)( void ); + void (*V_CalcShake)( void ); + void (*V_ApplyShake)( float *origin, float *angles, float factor ); + + int (*PM_PointContents)( float *point, int *truecontents ); + int (*PM_WaterEntity)( float *p ); + struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehull, int ignore_pe ); + + struct model_s *(*CL_LoadModel)( const char *modelname, int *index ); + int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); + + const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); + void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); + + unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); + void (*pfnPlaybackEvent)( 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 ); + void (*pfnWeaponAnim)( int iAnim, int body ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + long (*pfnRandomLong)( long lLow, long lHigh ); + void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); + int (*Con_IsVisible) (); + const char *(*pfnGetGameDirectory)( void ); + struct cvar_s *(*pfnGetCvarPointer)( const char *szName ); + const char *(*Key_LookupBinding)( const char *pBinding ); + const char *(*pfnGetLevelName)( void ); + void (*pfnGetScreenFade)( struct screenfade_s *fade ); + void (*pfnSetScreenFade)( struct screenfade_s *fade ); + void* (*VGui_GetPanel)( ); + void (*VGui_ViewportPaintBackground)( int extents[4] ); + + byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength ); + char* (*COM_ParseFile)( char *data, char *token ); + void (*COM_FreeFile)( void *buffer ); + + 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; + + // returns 1 if the client is a spectator only (connected to a proxy), 0 otherwise or 2 if in dev_overview mode + int (*IsSpectateOnly)( void ); + struct model_s *(*LoadMapSprite)( const char *filename ); + + // file search functions + void (*COM_AddAppDirectoryToSearchPath)( const char *pszBaseDir, const char *appName ); + int (*COM_ExpandFilename)( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); + + // User info + // playerNum is in the range (1, MaxClients) + // returns NULL if player doesn't exit + // returns "" if no value is set + const char *( *PlayerInfo_ValueForKey )( int playerNum, const char *key ); + void (*PlayerInfo_SetValueForKey )( const char *key, const char *value ); + + // Gets a unique ID for the specified player. This is the same even if you see the player on a different server. + // iPlayer is an entity index, so client 0 would use iPlayer=1. + // Returns false if there is no player on the server in the specified slot. + qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]); + + // TrackerID access + int (*GetTrackerIDForPlayer)(int playerSlot); + int (*GetPlayerForTrackerID)(int trackerID); + + // Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream + // (but it might not get there). + int ( *pfnServerCmdUnreliable )( char *szCmdString ); + + void (*pfnGetMousePos)( struct tagPOINT *ppt ); + void (*pfnSetMousePos)( int x, int y ); + void (*pfnSetMouseEnable)( qboolean fEnable ); + + // undocumented interface starts here + struct cvar_s* (*pfnGetFirstCvarPtr)( void ); + void* (*pfnGetFirstCmdFunctionHandle)( void ); + void* (*pfnGetNextCmdFunctionHandle)( void *cmdhandle ); + const char* (*pfnGetCmdFunctionName)( void *cmdhandle ); + float (*pfnGetClientOldTime)( void ); + float (*pfnGetGravity)( void ); + struct model_s* (*pfnGetModelByIndex)( int index ); + void (*pfnSetFilterMode)( int mode ); // same as gl_texsort in original Quake + void (*pfnSetFilterColor)( float red, float green, float blue ); + void (*pfnSetFilterBrightness)( float brightness ); + void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); + void (*pfnSPR_DrawGeneric)( int frame, int x, int y, const wrect_t *prc, int blendsrc, int blenddst, int width, int height ); + void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *entryPicked ); + int (*pfnDrawString)( int x, int y, const char *str, int r, int g, int b ); + int (*pfnDrawStringReverse)( int x, int y, const char *str, int r, int g, int b ); + const char *(*LocalPlayerInfo_ValueForKey)( const char* key ); + int (*pfnVGUI2DrawCharacter)( int x, int y, int ch, unsigned int font ); + int (*pfnVGUI2DrawCharacterAdditive)( int x, int y, int ch, int r, int g, int b, unsigned int font ); + unsigned int (*pfnGetApproxWavePlayLen)( char *filename ); + void* (*GetCareerGameUI)( void ); // g-cont. !!!! potential crash-point! + void (*Cvar_Set)( char *name, char *value ); + int (*pfnIsPlayingCareerMatch)( void ); + void (*pfnPlaySoundVoiceByName)( char *szSound, float volume, int pitch ); + void (*pfnPrimeMusicStream)( char *filename, int looping ); + double (*pfnSys_FloatTime)( void ); + + // decay funcs + void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnResetTutorMessageDecayData)( void ); + + void (*pfnPlaySoundByNameAtPitch)( char *szSound, float volume, int pitch ); + void (*pfnFillRGBABlend)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetAppID)( void ); + cmdalias_t *(*pfnGetAliases)( void ); + void (*pfnVguiWrap2_GetMouseDelta)( int *x, int *y ); +} cl_enginefunc_t; + +#define CLDLL_INTERFACE_VERSION 7 + +#ifdef __cplusplus +} +#endif + +#endif//CDLL_INT_H \ No newline at end of file diff --git a/engine/custom.h b/engine/custom.h new file mode 100644 index 00000000..d7093818 --- /dev/null +++ b/engine/custom.h @@ -0,0 +1,93 @@ +/*** +* +* 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 CUSTOM_H +#define CUSTOM_H + +#include "const.h" + +///////////////// +// Customization +// passed to pfnPlayerCustomization +// For automatic downloading. + +typedef enum +{ + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // Fake type for world, is really t_model +} resourcetype_t; + +typedef struct +{ + int size; +} _resourceinfo_t; + +typedef struct resourceinfo_s +{ + _resourceinfo_t info[8]; +} resourceinfo_t; + +#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. +#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? +#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization + // 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_CHECKFILE (1<<7) // Check file on client + +typedef struct resource_s +{ + char szFileName[64]; // File name to download/precache. + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. + int nIndex; // For t_decals + int nDownloadSize; // Size in Bytes if this must be downloaded. + unsigned char ucFlags; + + // for handling client to client resource propagation + unsigned char rgucMD5_hash[16]; // To determine if we already have it. + unsigned char playernum; // Which player index this resource is associated with, + // if it's a custom resource. + + unsigned char rguc_reserved[32]; // For future expansion + struct resource_s *pNext; // Next in chain. + struct resource_s *pPrev; +} resource_t; + +typedef struct customization_s +{ + qboolean bInUse; // Is this customization in use; + resource_t resource; // The resource_t for this customization + qboolean bTranslated; // Has the raw data been translated into a useable format? + // (e.g., raw decal .wad make into texture_t *) + int nUserData1; // Customization specific data + int nUserData2; // Customization specific data + void *pInfo; // Buffer that holds the data structure that references + // the data (e.g., the cachewad_t) + void *pBuffer; // Buffer that holds the data for the customization + // (the raw .wad data) + struct customization_s *pNext; // Next in chain +} customization_t; + +#define FCUST_FROMHPAK ( 1<<0 ) +#define FCUST_WIPEDATA ( 1<<1 ) +#define FCUST_IGNOREINIT ( 1<<2 ) + +#endif // CUSTOM_H \ No newline at end of file diff --git a/engine/customentity.h b/engine/customentity.h new file mode 100644 index 00000000..78475f9b --- /dev/null +++ b/engine/customentity.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 CUSTOMENTITY_H +#define CUSTOMENTITY_H + +// Custom Entities + +// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12) +#define BEAMENT_ENTITY( x ) ((x) & 0xFFF) +#define BEAMENT_ATTACHMENT( x ) (((x)>>12) & 0xF) + +// Beam types, encoded as a byte +enum +{ + BEAM_POINTS = 0, + BEAM_ENTPOINT, + BEAM_ENTS, + BEAM_HOSE, +}; + +#define BEAM_FSINE 0x10 +#define BEAM_FSOLID 0x20 +#define BEAM_FSHADEIN 0x40 +#define BEAM_FSHADEOUT 0x80 + +#endif//CUSTOMENTITY_H \ No newline at end of file diff --git a/engine/edict.h b/engine/edict.h new file mode 100644 index 00000000..be63daac --- /dev/null +++ b/engine/edict.h @@ -0,0 +1,42 @@ +/*** +* +* 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 EDICT_H +#define EDICT_H + +#define MAX_ENT_LEAFS 48 + +#include "progdefs.h" + +struct edict_s +{ + qboolean free; + int serialnumber; + + link_t area; // linked to a division node or leaf + int headnode; // -1 to use normal leaf check + + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + + float freetime; // sv.time when the object was freed + + void* pvPrivateData; // Alloced and freed by engine, used by DLLs + entvars_t v; // C exported fields from progs + + // other fields from progs come immediately after +}; + +#endif//EDICT_H \ No newline at end of file diff --git a/engine/eiface.h b/engine/eiface.h new file mode 100644 index 00000000..64984b10 --- /dev/null +++ b/engine/eiface.h @@ -0,0 +1,497 @@ +/*** +* +* 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 EIFACE_H +#define EIFACE_H + +#ifdef HLDEMO_BUILD +#define INTERFACE_VERSION 001 +#else // !HLDEMO_BUILD, i.e., regular version of HL +#define INTERFACE_VERSION 140 +#endif // !HLDEMO_BUILD + +#include +#include "custom.h" +#include "cvardef.h" +// +// Defines entity interface between engine and DLLs. +// This header file included by engine files and DLL files. +// +// Before including this header, DLLs must: +// include progdefs.h +// This is conveniently done for them in extdll.h +// + +#ifdef _WIN32 +#define DLLEXPORT __stdcall +#else +#define DLLEXPORT /* */ +#endif + +typedef enum +{ + 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 +{ + print_console, + print_center, + print_chat, +} PRINT_TYPE; + +// For integrity checking of content on clients +typedef enum +{ + 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_TYPE; + +// Returned by TraceLine +typedef struct +{ + int fAllSolid; // if true, plane is not valid + int fStartSolid; // if true, the initial point was in a solid area + int fInOpen; + int fInWater; + float flFraction; // time completed, 1.0 = didn't hit anything + vec3_t vecEndPos; // final position + float flPlaneDist; + 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 +{ + int fPlaying;// is sound playing right now? + int fWasPlaying;// if not, CD is paused if WasPlaying is true. + int fInitialized; + int fEnabled; + int fPlayLooping; + float cdvolume; + int fCDRom; + int fPlayTrack; +} CDStatus; + +typedef unsigned long CRC32_t; + +// Engine hands this to DLLs for functionality callbacks +typedef struct enginefuncs_s +{ + int (*pfnPrecacheModel)( char* s ); + int (*pfnPrecacheSound)( char* s ); + void (*pfnSetModel)( edict_t *e, const char *m ); + int (*pfnModelIndex)( const char *m ); + int (*pfnModelFrames)( int modelIndex ); + void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); + void (*pfnChangeLevel)( char* s1, char* s2 ); + void (*pfnGetSpawnParms)( edict_t *ent ); + void (*pfnSaveSpawnParms)( edict_t *ent ); + float (*pfnVecToYaw)( const float *rgflVector ); + void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut ); + void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); + void (*pfnChangeYaw)( edict_t* ent ); + void (*pfnChangePitch)( edict_t* ent ); + edict_t* (*pfnFindEntityByString)( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); + int (*pfnGetEntityIllum)( edict_t* pEnt ); + edict_t* (*pfnFindEntityInSphere)( edict_t *pEdictStartSearchAfter, const float *org, float rad ); + edict_t* (*pfnFindClientInPVS)( edict_t *pEdict ); + edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer ); + void (*pfnMakeVectors)( const float *rgflVector ); + void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up ); + edict_t* (*pfnCreateEntity)( void ); + void (*pfnRemoveEntity)( edict_t* e ); + edict_t* (*pfnCreateNamedEntity)( int className ); + void (*pfnMakeStatic)( edict_t *ent ); + int (*pfnEntIsOnFloor)( edict_t *e ); + int (*pfnDropToFloor)( edict_t* e ); + int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode ); + void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin ); + void (*pfnEmitSound)( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch ); + void (*pfnEmitAmbientSound)( edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch ); + void (*pfnTraceLine)( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceToss)( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); + int (*pfnTraceMonsterHull)( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); + 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)( char* str ); + void (*pfnServerExecute)( void ); + void (*pfnClientCommand)( edict_t* pEdict, char* szFmt, ... ); + void (*pfnParticleEffect)( const float *org, const float *dir, float color, float count ); + 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 ); + void (*pfnMessageEnd)( void ); + void (*pfnWriteByte)( int iValue ); + void (*pfnWriteChar)( int iValue ); + void (*pfnWriteShort)( int iValue ); + void (*pfnWriteLong)( int iValue ); + void (*pfnWriteAngle)( float flValue ); + void (*pfnWriteCoord)( float flValue ); + void (*pfnWriteString)( const char *sz ); + void (*pfnWriteEntity)( int iValue ); + void (*pfnCVarRegister)( cvar_t *pCvar ); + float (*pfnCVarGetFloat)( const char *szVarName ); + const char* (*pfnCVarGetString)( const char *szVarName ); + void (*pfnCVarSetFloat)( const char *szVarName, float flValue ); + void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); + void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); + void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); + void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); + void* (*pfnPvEntPrivateData)( edict_t *pEdict ); + void (*pfnFreeEntPrivateData)( edict_t *pEdict ); + const char *(*pfnSzFromIndex)( int iString ); + int (*pfnAllocString)( const char *szValue ); + struct entvars_s *(*pfnGetVarsOfEnt)( edict_t *pEdict ); + edict_t* (*pfnPEntityOfEntOffset)( int iEntOffset ); + int (*pfnEntOffsetOfPEntity)( const edict_t *pEdict ); + int (*pfnIndexOfEdict)( const edict_t *pEdict ); + edict_t* (*pfnPEntityOfEntIndex)( int iEntIndex ); + edict_t* (*pfnFindEntityByVars)( struct entvars_s* pvars ); + void* (*pfnGetModelPtr)( edict_t* pEdict ); + int (*pfnRegUserMsg)( const char *pszName, int iSize ); + void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); + void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); + unsigned long (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( unsigned long function ); + void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients + void (*pfnServerPrint)( const char *szMsg ); + const char *(*pfnCmd_Args)( void ); // these 3 added + const char *(*pfnCmd_Argv)( int argc ); // so game DLL can easily + int (*pfnCmd_Argc)( void ); // access client 'cmd' strings + void (*pfnGetAttachment)( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); + void (*pfnCRC32_Init)( CRC32_t *pulCRC ); + void (*pfnCRC32_ProcessBuffer)( CRC32_t *pulCRC, void *p, int len ); + void (*pfnCRC32_ProcessByte)( CRC32_t *pulCRC, unsigned char ch ); + CRC32_t (*pfnCRC32_Final)( CRC32_t pulCRC ); + long (*pfnRandomLong)( long lLow, long lHigh ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + 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)( 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 ); + 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 ); + char* (*pfnGetInfoKeyBuffer)( edict_t *e ); // passing in NULL gets the serverinfo + char* (*pfnInfoKeyValue)( char *infobuffer, char *key ); + void (*pfnSetKeyValue)( char *infobuffer, char *key, char *value ); + void (*pfnSetClientKeyValue)( int clientIndex, char *infobuffer, char *key, char *value ); + int (*pfnIsMapValid)( char *filename ); + void (*pfnStaticDecal)( const float *origin, int decalIndex, int entityIndex, int modelIndex ); + 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? + cvar_t *(*pfnCVarGetPointer)( const char *szVarName ); + unsigned int (*pfnGetPlayerWONId)( edict_t *e ); // 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 + + // YWB 8/1/99 TFF Physics additions + void (*pfnInfo_RemoveKey)( char *s, const char *key ); + 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 ); + 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 ); + + void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); + void (*pfnDeltaUnsetField)( struct delta_s *pFields, const char *fieldname ); + 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 ); + void (*pfnDeltaSetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); + void (*pfnDeltaUnsetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); + void (*pfnSetGroupMask)( int mask, int op ); + int (*pfnCreateInstancedBaseline)( int classname, struct entity_state_s *baseline ); + void (*pfnCvar_DirectSet)( struct cvar_s *var, char *value ); + + // Forces the client and server to be running with the same version of the specified file + // ( e.g., a player model ). + // Calling this has no effect in single player + void (*pfnForceUnmodified)( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); + + void (*pfnGetPlayerStats)( const edict_t *pClient, int *ping, int *packet_loss ); + + 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). + qboolean (*pfnVoice_GetClientListening)(int iReceiver, int iSender); + qboolean (*pfnVoice_SetClientListening)(int iReceiver, int iSender, qboolean bListen); + + const char *(*pfnGetPlayerAuthId) ( edict_t *e ); + + void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); + void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked ); + int (*pfnGetFileSize)( char *filename ); + unsigned int (*pfnGetApproxWavePlayLen)( const char *filepath ); + int (*pfnIsCareerMatch)( void ); + int (*pfnGetLocalizedStringLength)( const char *label ); + void (*pfnRegisterTutorMessageShown)( int mid ); + 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 (*CheckParm)( char *parm, char **ppnext ); +} enginefuncs_t; +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 + +// Passed to pfnKeyValue +typedef struct KeyValueData_s +{ + char *szClassName; // in: entity classname + char *szKeyName; // in: name of key + char *szValue; // in: value of key + long fHandled; // out: DLL sets to true if key-value pair was understood +} KeyValueData; + + +typedef struct +{ + char mapName[32]; + char landmarkName[32]; + edict_t *pentLandmark; + vec3_t vecLandmarkOrigin; +} LEVELLIST; + +typedef struct +{ + int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) + edict_t *pent; // Pointer to the in-game entity + + int location; // Offset from the base data of this entity + int size; // Byte size of this entity's data + int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name + +} ENTITYTABLE; + +#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of ENTITYTABLE->flags + +#define FENTTABLE_PLAYER 0x80000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_GLOBAL 0x10000000 + +typedef struct saverestore_s +{ + char *pBaseData; // Start of all entity save data + char *pCurrentData; // Current buffer pointer for sequential access + int size; // Current data size + int bufferSize; // Total space for data + int tokenSize; // Size of the linear list of tokens + int tokenCount; // Number of elements in the pTokens table + char **pTokens; // Hash table of entity strings (sparse) + int currentIndex; // Holds a global entity table ID + int tableCount; // Number of elements in the entity table + int connectionCount; // Number of elements in the levelList[] + ENTITYTABLE *pTable; // Array of ENTITYTABLE elements (1 for each entity) + LEVELLIST levelList[MAX_LEVEL_CONNECTIONS]; // List of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[20]; // landmark we'll spawn near in next level + vec3_t vecLandmarkOffset; // for landmark transitions + float time; + char szCurrentMapName[32]; // To check global entities +} SAVERESTOREDATA; + +typedef enum _fieldtypes +{ + FIELD_FLOAT = 0, // Any floating point value + FIELD_STRING, // A string ID (return from ALLOC_STRING) + FIELD_ENTITY, // An entity offset (EOFFSET) + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // Entity handle + FIELD_EVARS, // EVARS * + FIELD_EDICT, // edict_t *, or edict_t * (same thing) + FIELD_VECTOR, // Any vector + FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) + FIELD_POINTER, // Arbitrary data pointer... to be removed, use an array of FIELD_CHARACTER + FIELD_INTEGER, // Any integer or enum + FIELD_FUNCTION, // A class function pointer (Think, Use, etc) + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_MODELNAME, // Engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) + + FIELD_TYPECOUNT, // MUST BE LAST +} FIELDTYPE; + +#ifndef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags } +#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0) +#define DEFINE_ARRAY(type,name,fieldtype,count) _FIELD(type, name, fieldtype, count, 0) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, FTYPEDESC_GLOBAL ) +#define DEFINE_GLOBAL_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, FTYPEDESC_GLOBAL ) + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore +#define FTYPEDESC_SAVE 0x0002 // This field is saved to disk +#define FTYPEDESC_KEY 0x0004 // This field can be requested and written to by string name at load time +#define FTYPEDESC_FUNCTIONTABLE 0x0008 // This is a table entry for a member function pointer + +typedef struct +{ + FIELDTYPE fieldType; + char *fieldName; + int fieldOffset; + short fieldSize; + short flags; +} TYPEDESCRIPTION; + +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +typedef struct +{ + // Initialize/shutdown the game (one-time call after loading of game .dll ) + void (*pfnGameInit)( void ); + int (*pfnSpawn)( edict_t *pent ); + void (*pfnThink)( edict_t *pent ); + void (*pfnUse)( edict_t *pentUsed, edict_t *pentOther ); + void (*pfnTouch)( edict_t *pentTouched, edict_t *pentOther ); + void (*pfnBlocked)( edict_t *pentBlocked, edict_t *pentOther ); + void (*pfnKeyValue)( edict_t *pentKeyvalue, KeyValueData *pkvd ); + void (*pfnSave)( edict_t *pent, SAVERESTOREDATA *pSaveData ); + int (*pfnRestore)( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); + void (*pfnSetAbsBox)( edict_t *pent ); + + void (*pfnSaveWriteFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveReadFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveGlobalState)( SAVERESTOREDATA * ); + void (*pfnRestoreGlobalState)( SAVERESTOREDATA * ); + void (*pfnResetGlobalState)( void ); + + qboolean (*pfnClientConnect)( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); + + void (*pfnClientDisconnect)( edict_t *pEntity ); + void (*pfnClientKill)( edict_t *pEntity ); + void (*pfnClientPutInServer)( edict_t *pEntity ); + void (*pfnClientCommand)( edict_t *pEntity ); + void (*pfnClientUserInfoChanged)( edict_t *pEntity, char *infobuffer ); + void (*pfnServerActivate)( edict_t *pEdictList, int edictCount, int clientMax ); + void (*pfnServerDeactivate)( void ); + void (*pfnPlayerPreThink)( edict_t *pEntity ); + void (*pfnPlayerPostThink)( edict_t *pEntity ); + + void (*pfnStartFrame)( void ); + void (*pfnParmsNewLevel)( void ); + void (*pfnParmsChangeLevel)( void ); + + // Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life + const char *(*pfnGetGameDescription)( void ); + + // Notify dll about a player customization. + void (*pfnPlayerCustomization)( edict_t *pEntity, customization_t *pCustom ); + + // Spectator funcs + void (*pfnSpectatorConnect)( edict_t *pEntity ); + void (*pfnSpectatorDisconnect)( edict_t *pEntity ); + void (*pfnSpectatorThink)( edict_t *pEntity ); + + // Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. + void (*pfnSys_Error)( const char *error_string ); + + void (*pfnPM_Move)( struct playermove_s *ppmove, qboolean server ); + void (*pfnPM_Init)( struct playermove_s *ppmove ); + 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 ); + void (*pfnCreateBaseline)( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); + void (*pfnRegisterEncoders)( void ); + int (*pfnGetWeaponData)( struct edict_s *player, struct weapon_data_s *info ); + + void (*pfnCmdStart)( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); + void (*pfnCmdEnd)( const edict_t *player ); + + // 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 ); + + // Enumerates player hulls. Returns 0 if the hull number doesn't exist, 1 otherwise + int (*pfnGetHullBounds) ( int hullnumber, float *mins, float *maxs ); + + // Create baselines for certain "unplaced" items. + void (*pfnCreateInstancedBaselines) ( void ); + + // One of the pfnForceUnmodified 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 (*pfnInconsistentFile)( const struct edict_s *player, const char *filename, char *disconnect_message ); + + // 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. + int (*pfnAllowLagCompensation)( void ); +} DLL_FUNCTIONS; + +extern DLL_FUNCTIONS gEntityInterface; + +// Current version. +#define NEW_DLL_FUNCTIONS_VERSION 1 + +typedef struct +{ + // Called right before the object's memory is freed. + // Calls its destructor. + void (*pfnOnFreeEntPrivateData)( edict_t *pEnt ); + void (*pfnGameShutdown)(void); + int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther ); + 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 ); + +// 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 \ No newline at end of file diff --git a/engine/engine.dsp b/engine/engine.dsp new file mode 100644 index 00000000..b79d1bfe --- /dev/null +++ b/engine/engine.dsp @@ -0,0 +1,621 @@ +# Microsoft Developer Studio Project File - Name="engine" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=engine - 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 "engine.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 "engine.mak" CFG="engine - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "engine - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "engine - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "engine - 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 "..\temp\engine\!release" +# PROP Intermediate_Dir "..\temp\engine\!release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "common" /I "common/imagelib" /I "common/soundlib" /I "server" /I "client" /I "client/vgui" /I "../common" /I "../game_shared" /I "../pm_shared" /I "../utils/vgui/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# SUBTRACT CPP /Fr /YX +# 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 /machine:I386 /opt:nowin98 +# ADD LINK32 msvcrt.lib user32.lib gdi32.lib shell32.lib advapi32.lib winmm.lib mpeg.lib ../utils/vgui/lib/win32_vc6/vgui.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc" /out:"..\temp\engine\!release/xash.dll" /libpath:"./common/soundlib" /opt:nowin98 +# SUBTRACT LINK32 /debug /nodefaultlib +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\engine\!release +InputPath=\Xash3D\src_main\temp\engine\!release\xash.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "engine - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\temp\engine\!debug" +# PROP Intermediate_Dir "..\temp\engine\!debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "common" /I "common/imagelib" /I "common/soundlib" /I "server" /I "client" /I "client/vgui" /I "../common" /I "../game_shared" /I "../pm_shared" /I "../utils/vgui/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FAs /FR /FD /c +# SUBTRACT CPP /YX +# 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 /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 /debug /machine:I386 +# ADD LINK32 msvcrtd.lib user32.lib gdi32.lib shell32.lib advapi32.lib winmm.lib mpeg_dbg.lib ../utils/vgui/lib/win32_vc6/vgui.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libcd.lib" /out:"..\temp\engine\!debug/xash.dll" /pdbtype:sept /libpath:"./common/soundlib" +# SUBTRACT LINK32 /incremental:no /map /nodefaultlib +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\engine\!debug +InputPath=\Xash3D\src_main\temp\engine\!debug\xash.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "engine - Win32 Release" +# Name "engine - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\common\avikit.c +# End Source File +# Begin Source File + +SOURCE=.\common\build.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_cmds.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_demo.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_events.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_frame.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_game.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_main.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_menu.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_parse.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_pmove.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_remap.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_scrn.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_tent.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_video.c +# End Source File +# Begin Source File + +SOURCE=.\client\cl_view.c +# End Source File +# Begin Source File + +SOURCE=.\common\cmd.c +# End Source File +# Begin Source File + +SOURCE=.\common\common.c +# End Source File +# Begin Source File + +SOURCE=.\common\con_utils.c +# End Source File +# Begin Source File + +SOURCE=.\common\console.c +# End Source File +# Begin Source File + +SOURCE=.\common\crclib.c +# End Source File +# Begin Source File + +SOURCE=.\common\crtlib.c +# End Source File +# Begin Source File + +SOURCE=.\common\cvar.c +# End Source File +# Begin Source File + +SOURCE=.\common\filesystem.c +# End Source File +# Begin Source File + +SOURCE=.\common\gamma.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_backend.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_beams.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_cull.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_decals.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_draw.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_image.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_mirror.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_refrag.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rlight.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rmain.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rmath.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rmisc.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rpart.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_rsurf.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_sprite.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_studio.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_vidnt.c +# End Source File +# Begin Source File + +SOURCE=.\client\gl_warp.c +# End Source File +# Begin Source File + +SOURCE=.\common\host.c +# End Source File +# Begin Source File + +SOURCE=.\common\hpak.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_bmp.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_dds.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_main.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_quant.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_tga.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_utils.c +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\img_wad.c +# End Source File +# Begin Source File + +SOURCE=.\common\infostring.c +# End Source File +# Begin Source File + +SOURCE=.\common\input.c +# End Source File +# Begin Source File + +SOURCE=.\common\keys.c +# End Source File +# Begin Source File + +SOURCE=.\common\library.c +# End Source File +# Begin Source File + +SOURCE=.\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=.\common\matrixlib.c +# End Source File +# Begin Source File + +SOURCE=.\common\mod_studio.c +# End Source File +# Begin Source File + +SOURCE=.\common\model.c +# End Source File +# Begin Source File + +SOURCE=.\common\net_buffer.c +# End Source File +# Begin Source File + +SOURCE=.\common\net_chan.c +# End Source File +# Begin Source File + +SOURCE=.\common\net_encode.c +# End Source File +# Begin Source File + +SOURCE=.\common\net_huff.c +# End Source File +# Begin Source File + +SOURCE=.\common\network.c +# End Source File +# Begin Source File + +SOURCE=.\common\pm_surface.c +# End Source File +# Begin Source File + +SOURCE=.\common\pm_trace.c +# End Source File +# Begin Source File + +SOURCE=.\common\random.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_backend.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_dsp.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_load.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_main.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_mix.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_mouth.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_stream.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_utils.c +# End Source File +# Begin Source File + +SOURCE=.\client\s_vox.c +# End Source File +# Begin Source File + +SOURCE=.\common\soundlib\snd_main.c +# End Source File +# Begin Source File + +SOURCE=.\common\soundlib\snd_mp3.c +# End Source File +# Begin Source File + +SOURCE=.\common\soundlib\snd_utils.c +# End Source File +# Begin Source File + +SOURCE=.\common\soundlib\snd_wav.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_client.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_cmds.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_custom.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_frame.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_game.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_init.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_main.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_move.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_phys.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_pmove.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_save.c +# End Source File +# Begin Source File + +SOURCE=.\server\sv_world.c +# End Source File +# Begin Source File + +SOURCE=.\common\sys_con.c +# End Source File +# Begin Source File + +SOURCE=.\common\sys_win.c +# End Source File +# Begin Source File + +SOURCE=.\common\titles.c +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_clip.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_draw.c +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_font.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_input.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_int.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_surf.cpp +# End Source File +# Begin Source File + +SOURCE=.\common\world.c +# End Source File +# Begin Source File + +SOURCE=.\common\zone.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\client\cl_tent.h +# End Source File +# Begin Source File + +SOURCE=.\client\client.h +# End Source File +# Begin Source File + +SOURCE=.\common\common.h +# End Source File +# Begin Source File + +SOURCE=.\common\crtlib.h +# End Source File +# Begin Source File + +SOURCE=.\common\filesystem.h +# End Source File +# Begin Source File + +SOURCE=.\client\gl_export.h +# End Source File +# Begin Source File + +SOURCE=.\client\gl_local.h +# End Source File +# Begin Source File + +SOURCE=.\common\imagelib\imagelib.h +# End Source File +# Begin Source File + +SOURCE=.\common\library.h +# End Source File +# Begin Source File + +SOURCE=.\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=.\common\mod_local.h +# End Source File +# Begin Source File + +SOURCE=.\common\net_buffer.h +# End Source File +# Begin Source File + +SOURCE=.\common\net_encode.h +# End Source File +# Begin Source File + +SOURCE=.\common\protocol.h +# End Source File +# Begin Source File + +SOURCE=.\server\server.h +# End Source File +# Begin Source File + +SOURCE=.\client\sound.h +# End Source File +# Begin Source File + +SOURCE=.\common\soundlib\soundlib.h +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_draw.h +# End Source File +# Begin Source File + +SOURCE=.\client\vgui\vgui_main.h +# End Source File +# Begin Source File + +SOURCE=.\client\vox.h +# End Source File +# Begin Source File + +SOURCE=.\common\world.h +# End Source File +# End Group +# End Target +# End Project diff --git a/engine/keydefs.h b/engine/keydefs.h new file mode 100644 index 00000000..2a1312f0 --- /dev/null +++ b/engine/keydefs.h @@ -0,0 +1,133 @@ +/*** +* +* 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 KEYDEFS_H +#define KEYDEFS_H + +// +// 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 +#define K_KP_NUMLOCK 176 + +// +// 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 \ No newline at end of file diff --git a/engine/menu_int.h b/engine/menu_int.h new file mode 100644 index 00000000..f380d6ff --- /dev/null +++ b/engine/menu_int.h @@ -0,0 +1,188 @@ +/* +menu_int.h - interface between engine and menu +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef MENU_INT_H +#define MENU_INT_H + +#include "cvardef.h" +#include "gameinfo.h" +#include "wrect.h" + +typedef int HIMAGE; // handle to a graphic + +// flags for PIC_Load +#define PIC_NEAREST (1<<0) // disable texfilter +#define PIC_KEEP_RGBDATA (1<<1) // some images keep source +#define PIC_NOFLIP_TGA (1<<2) // Steam background completely ignore tga attribute 0x20 +#define PIC_KEEP_8BIT (1<<3) // keep original 8-bit image (if present) + +typedef struct ui_globalvars_s +{ + float time; // unclamped host.realtime + float frametime; + + int scrWidth; // actual values + int scrHeight; + + int maxClients; + int developer; + int demoplayback; + int demorecording; + char demoname[64]; // name of currently playing demo + char maptitle[64]; // title of active map +} ui_globalvars_t; + +typedef struct ui_enginefuncs_s +{ + // image handlers + HIMAGE (*pfnPIC_Load)( const char *szPicName, const byte *ucRawImage, long ulRawImageSize, long flags ); + void (*pfnPIC_Free)( const char *szPicName ); + int (*pfnPIC_Width)( HIMAGE hPic ); + int (*pfnPIC_Height)( HIMAGE hPic ); + void (*pfnPIC_Set)( HIMAGE hPic, int r, int g, int b, int a ); + void (*pfnPIC_Draw)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawHoles)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawTrans)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawAdditive)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_EnableScissor)( int x, int y, int width, int height ); + void (*pfnPIC_DisableScissor)( void ); + + // screen handlers + void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); + + // cvar handlers + cvar_t* (*pfnRegisterVariable)( const char *szName, const char *szValue, int flags ); + float (*pfnGetCvarFloat)( const char *szName ); + char* (*pfnGetCvarString)( const char *szName ); + void (*pfnCvarSetString)( const char *szName, const char *szValue ); + void (*pfnCvarSetValue)( const char *szName, float flValue ); + + // command handlers + int (*pfnAddCommand)( const char *cmd_name, void (*function)(void) ); + void (*pfnClientCmd)( int execute_now, const char *szCmdString ); + void (*pfnDelCommand)( const char *cmd_name ); + int (*pfnCmdArgc)( void ); + char* (*pfnCmdArgv)( int argc ); + char* (*pfnCmd_Args)( void ); + + // debug messages (in-menu shows only notify) + void (*Con_Printf)( char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_NPrintf)( int pos, char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + + // sound handlers + void (*pfnPlayLocalSound)( const char *szSound ); + + // cinematic handlers + void (*pfnDrawLogo)( const char *filename, float x, float y, float width, float height ); + int (*pfnGetLogoWidth)( void ); + int (*pfnGetLogoHeight)( void ); + float (*pfnGetLogoLength)( void ); // cinematic duration in seconds + + // text message system + void (*pfnDrawCharacter)( int x, int y, int width, int height, int ch, int ulRGBA, HIMAGE hFont ); + int (*pfnDrawConsoleString)( int x, int y, const char *string ); + void (*pfnDrawSetTextColor)( int r, int g, int b, int alpha ); + void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); + void (*pfnSetConsoleDefaultColor)( int r, int g, int b ); // color must came from colors.lst + + // custom rendering (for playermodel preview) + struct cl_entity_s* (*pfnGetPlayerModel)( void ); // for drawing playermodel previews + void (*pfnSetModel)( struct cl_entity_s *ed, const char *path ); + void (*pfnClearScene)( void ); + void (*pfnRenderScene)( const struct ref_params_s *fd ); + int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); + + // misc handlers + void (*pfnHostError)( const char *szFmt, ... ); + int (*pfnFileExists)( const char *filename, int gamedironly ); + void (*pfnGetGameDir)( char *szGetGameDir ); + + // gameinfo handlers + int (*pfnCreateMapsList)( int fRefresh ); + int (*pfnClientInGame)( void ); + void (*pfnClientJoin)( const struct netadr_s adr ); + + // parse txt files + byte* (*COM_LoadFile)( const char *filename, int *pLength ); + char* (*COM_ParseFile)( char *data, char *token ); + void (*COM_FreeFile)( void *buffer ); + + // keyfuncs + void (*pfnKeyClearStates)( void ); // call when menu open or close + void (*pfnSetKeyDest)( int dest ); + const char *(*pfnKeynumToString)( int keynum ); + const char *(*pfnKeyGetBinding)( int keynum ); + void (*pfnKeySetBinding)( int keynum, const char *binding ); + int (*pfnKeyIsDown)( int keynum ); + int (*pfnKeyGetOverstrikeMode)( void ); + void (*pfnKeySetOverstrikeMode)( int fActive ); + void *(*pfnKeyGetState)( const char *name ); // for mlook, klook etc + + // engine memory manager + void* (*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); + + // collect info from engine + int (*pfnGetGameInfo)( GAMEINFO *pgameinfo ); + GAMEINFO **(*pfnGetGamesList)( int *numGames ); // collect info about all mods + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); // find in files + int (*pfnGetSaveComment)( const char *savename, char *comment ); + int (*pfnGetDemoComment)( const char *demoname, char *comment ); + int (*pfnCheckGameDll)( void ); // returns false if hl.dll is missed or invalid + char *(*pfnGetClipboardData)( void ); + + // engine launcher + void (*pfnShellExecute)( const char *name, const char *args, int closeEngine ); + void (*pfnWriteServerConfig)( const char *name ); + void (*pfnChangeInstance)( const char *newInstance, const char *szFinalMessage ); + void (*pfnPlayBackgroundTrack)( const char *introName, const char *loopName ); + void (*pfnHostEndGame)( const char *szFinalMessage ); + + // menu interface is freezed at version 0.75 + // new functions starts here + float (*pfnRandomFloat)( float flLow, float flHigh ); + long (*pfnRandomLong)( long lLow, long lHigh ); + + void (*pfnSetCursor)( void *hCursor ); // change cursor + int (*pfnIsMapValid)( char *filename ); + void (*pfnProcessImage)( int texnum, float gamma, int topColor, int bottomColor ); + int (*pfnCompareFileTime)( char *filename1, char *filename2, int *iCompare ); +} ui_enginefuncs_t; + +typedef struct +{ + int (*pfnVidInit)( void ); + void (*pfnInit)( void ); + void (*pfnShutdown)( void ); + void (*pfnRedraw)( float flTime ); + void (*pfnKeyEvent)( int key, int down ); + void (*pfnMouseMove)( int x, int y ); + void (*pfnSetActiveMenu)( int active ); + void (*pfnAddServerToList)( struct netadr_s adr, const char *info ); + void (*pfnGetCursorPos)( int *pos_x, int *pos_y ); + void (*pfnSetCursorPos)( int pos_x, int pos_y ); + void (*pfnShowCursor)( int show ); + void (*pfnCharEvent)( int key ); + int (*pfnMouseInRect)( void ); // mouse entering\leave game window + int (*pfnIsVisible)( void ); + int (*pfnCreditsActive)( void ); // unused + void (*pfnFinalCredits)( void ); // show credits + game end +} UI_FUNCTIONS; + +typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); + +#endif//MENU_INT_H \ No newline at end of file diff --git a/engine/physint.h b/engine/physint.h new file mode 100644 index 00000000..14f068ce --- /dev/null +++ b/engine/physint.h @@ -0,0 +1,114 @@ +/* +physint.h - Server Physics Interface +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef PHYSINT_H +#define PHYSINT_H + +#define SV_PHYSICS_INTERFACE_VERSION 6 + +#define STRUCT_FROM_LINK( l, t, m ) ((t *)((byte *)l - (int)&(((t *)0)->m))) +#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area ) + +// values that can be returned with pfnServerState +#define SERVER_DEAD 0 +#define SERVER_LOADING 1 +#define SERVER_ACTIVE 2 + +typedef struct areanode_s +{ + int axis; // -1 = leaf node + float dist; + struct areanode_s *children[2]; + link_t trigger_edicts; + link_t solid_edicts; + link_t water_edicts; // func water +} areanode_t; + +typedef struct server_physics_api_s +{ + // unlink edict from old position and link onto new + void ( *pfnLinkEdict) ( edict_t *ent, qboolean touch_triggers ); + double ( *pfnGetServerTime )( void ); // unclamped + double ( *pfnGetFrameTime )( void ); // unclamped + void* ( *pfnGetModel )( int modelindex ); + areanode_t* ( *pfnGetHeadnode )( void ); // BSP tree for all physic entities + int ( *pfnServerState )( void ); + void ( *pfnHost_Error )( const char *error, ... ); // cause Host Error +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 + struct triangleapi_s *pTriAPI; // draw coliisions etc. Only for local system + + // draw debug messages (must be called from DrawOrthoTriangles). Only for local system + int ( *pfnDrawConsoleString )( int x, int y, char *string ); + void ( *pfnDrawSetTextColor )( float r, float g, float b ); + void ( *pfnDrawConsoleStringLen )( const char *string, int *length, int *height ); + void ( *Con_NPrintf )( int pos, char *fmt, ... ); + void ( *Con_NXPrintf )( struct con_nprint_s *info, char *fmt, ... ); + const char *( *pfnGetLightStyle )( int style ); // read custom appreance for selected lightstyle + void ( *pfnUpdateFogSettings )( unsigned int packed_fog ); + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); + struct msurface_s *(*pfnTraceSurface)( edict_t *pTextureEntity, const float *v1, const float *v2 ); + const byte *(*pfnGetTextureData)( unsigned int texnum ); + + // static allocations + void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); +} server_physics_api_t; + +// physic callbacks +typedef struct physics_interface_s +{ + int version; + // passed through pfnCreate (0 is attempt to create, -1 is reject) + int ( *SV_CreateEntity )( edict_t *pent, const char *szName ); + // run custom physics for each entity (return 0 to use built-in engine physic) + int ( *SV_PhysicsEntity )( edict_t *pEntity ); + // spawn entities with internal mod function e.g. for re-arrange spawn order (0 - use engine parser, 1 - use mod parser) + int ( *SV_LoadEntities )( const char *mapname, char *entities ); + // update conveyor belt for clients + void ( *SV_UpdatePlayerBaseVelocity )( edict_t *ent ); + // The game .dll should return 1 if save game should be allowed + int ( *SV_AllowSaveGame )( void ); +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 + // override trigger area checking and touching + int ( *SV_TriggerTouch )( edict_t *pent, edict_t *trigger ); + // some engine features can be enabled only through this function + unsigned int ( *SV_CheckFeatures )( void ); + // used for draw debug collisions for custom physic engine etc + void ( *DrawDebugTriangles )( void ); + // used for draw debug overlay (textured) + void ( *DrawNormalTriangles )( void ); + // used for draw debug messages (2d mode) + void ( *DrawOrthoTriangles )( void ); + // tracing entities with SOLID_CUSTOM mode on a server (not used by pmove code) + void ( *ClipMoveToEntity)( edict_t *ent, const float *start, float *mins, float *maxs, const float *end, trace_t *trace ); + // tracing entities with SOLID_CUSTOM mode on a server (only used by pmove code) + void ( *ClipPMoveToEntity)( struct physent_s *pe, const float *start, float *mins, float *maxs, const float *end, struct pmtrace_s *tr ); + // called at end the frame of SV_Physics call + void ( *SV_EndFrame )( void ); + // called through save\restore process + void (*pfnCreateEntitiesInTransitionList)( SAVERESTOREDATA*, int levelMask ); + // called through save\restore process + void (*pfnCreateEntitiesInRestoreList)( SAVERESTOREDATA*, int createPlayers ); + // allocate custom string (e.g. using user implementation of stringtable, not engine strings) + string_t (*pfnAllocString)( const char *szValue ); + // make custom string (e.g. using user implementation of stringtable, not engine strings) + string_t (*pfnMakeString)( const char *szValue ); + // read custom string (e.g. using user implementation of stringtable, not engine strings) + const char* (*pfnGetString)( string_t iString ); + // helper for restore custom decals that have custom message (e.g. Paranoia) + int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); +} physics_interface_t; + +#endif//PHYSINT_H \ No newline at end of file diff --git a/engine/progdefs.h b/engine/progdefs.h new file mode 100644 index 00000000..2a35559c --- /dev/null +++ b/engine/progdefs.h @@ -0,0 +1,218 @@ +/*** +* +* 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 PROGDEFS_H +#define PROGDEFS_H + +typedef struct +{ + float time; + float frametime; + float force_retouch; + string_t mapname; + string_t startspot; + float deathmatch; + float coop; + float teamplay; + float serverflags; + float found_secrets; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + edict_t *trace_ent; + float trace_inopen; + float trace_inwater; + int trace_hitgroup; + int trace_flags; + int changelevel; // transition in progress when true (was msg_entity) + int cdAudioTrack; + int maxClients; + int maxEntities; + const char *pStringBase; + + void *pSaveData; // (SAVERESTOREDATA *) pointer + vec3_t vecLandmarkOffset; +} globalvars_t; + +typedef struct entvars_s +{ + string_t classname; + string_t globalname; + + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t basevelocity; + vec3_t clbasevelocity; // Base velocity that was passed in to server physics so + // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. + vec3_t movedir; + + vec3_t angles; // Model angles + vec3_t avelocity; // angle velocity (degrees per second) + vec3_t punchangle; // auto-decaying view angle adjustment + vec3_t v_angle; // Viewing angle (player only) + + // For parametric entities + vec3_t endpos; + vec3_t startpos; + float impacttime; + float starttime; + + int fixangle; // 0:nothing, 1:force view angles, 2:add avelocity + float idealpitch; + float pitch_speed; + float ideal_yaw; + float yaw_speed; + + int modelindex; + + string_t model; + int viewmodel; // player's viewmodel + int weaponmodel; // what other players see + + vec3_t absmin; // BB max translated to world coord + vec3_t absmax; // BB max translated to world coord + vec3_t mins; // local BB min + vec3_t maxs; // local BB max + vec3_t size; // maxs - mins + + float ltime; + float nextthink; + + int movetype; + int solid; + + int skin; + int body; // sub-model selection for studiomodels + int effects; + float gravity; // % of "normal" gravity + float friction; // inverse elasticity of MOVETYPE_BOUNCE + + int light_level; + + int sequence; // animation sequence + int gaitsequence; // movement animation sequence for player (0 for none) + float frame; // % playback position in animation sequences (0..255) + float animtime; // world time when frame was set + float framerate; // animation playback rate (-8x to 8x) + byte controller[4]; // bone controller setting (0..255) + byte blending[2]; // blending amount between sub-sequences (0..255) + + float scale; // sprites and models rendering scale (0..255) + int rendermode; + float renderamt; + vec3_t rendercolor; + int renderfx; + + float health; + float frags; + int weapons; // bit mask for available weapons + float takedamage; + + int deadflag; + vec3_t view_ofs; // eye position + + int button; + int impulse; + + edict_t *chain; // Entity pointer when linked into a linked list + edict_t *dmg_inflictor; + edict_t *enemy; + edict_t *aiment; // entity pointer when MOVETYPE_FOLLOW + edict_t *owner; + edict_t *groundentity; + + int spawnflags; + int flags; + + int colormap; // lowbyte topcolor, highbyte bottomcolor + int team; + + float max_health; + float teleport_time; + float armortype; + float armorvalue; + int waterlevel; + int watertype; + + string_t target; + string_t targetname; + string_t netname; + string_t message; + + float dmg_take; + float dmg_save; + float dmg; + float dmgtime; + + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; + + float speed; + float air_finished; + float pain_finished; + float radsuit_finished; + + edict_t *pContainingEntity; + + int playerclass; + float maxspeed; + + float fov; + int weaponanim; + + int pushmsec; + + int bInDuck; + int flTimeStepSound; + int flSwimTime; + int flDuckTime; + int iStepLeft; + float flFallVelocity; + + int gamestate; + + int oldbuttons; + + int groupinfo; + + // 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; + edict_t *euser1; + edict_t *euser2; + edict_t *euser3; + edict_t *euser4; +} entvars_t; + +#endif//PROGDEFS_H \ No newline at end of file diff --git a/engine/shake.h b/engine/shake.h new file mode 100644 index 00000000..7eeb6790 --- /dev/null +++ b/engine/shake.h @@ -0,0 +1,50 @@ +/*** +* +* 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 SHAKE_H +#define SHAKE_H + +// Screen / View effects + +// screen shake +extern int gmsgShake; + +// This structure is sent over the net to describe a screen shake event +typedef struct +{ + unsigned short amplitude; // FIXED 4.12 amount of shake + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short frequency; // FIXED 8.8 noise frequency (low frequency is a jerk,high frequency is a rumble) +} ScreenShake; + +// Fade in/out +extern int gmsgFade; + +#define FFADE_IN 0x0000 // Just here so we don't pass 0 into the function +#define FFADE_OUT 0x0001 // Fade out (not in) +#define FFADE_MODULATE 0x0002 // Modulate (don't blend) +#define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received + + +// This structure is sent over the net to describe a screen fade event +typedef struct +{ + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short holdTime; // FIXED 4.12 seconds duration until reset (fade & hold) + short fadeFlags; // flags + byte r, g, b, a; // fade to color ( max alpha ) +} ScreenFade; + +#endif // SHAKE_H \ No newline at end of file diff --git a/engine/sprite.h b/engine/sprite.h new file mode 100644 index 00000000..99c39935 --- /dev/null +++ b/engine/sprite.h @@ -0,0 +1,102 @@ +/*** +* +* 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 SPRITE_H +#define SPRITE_H + +/* +============================================================================== + +SPRITE MODELS + +.spr extended version (Half-Life compatible sprites with some Xash3D extensions) +============================================================================== +*/ + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP" +#define SPRITE_VERSION 2 // Half-Life sprites + +typedef enum +{ + ST_SYNC = 0, + ST_RAND +} synctype_t; + +typedef enum +{ + FRAME_SINGLE = 0, + FRAME_GROUP, + FRAME_ANGLED // Xash3D ext +} frametype_t; + +typedef enum +{ + SPR_NORMAL = 0, + SPR_ADDITIVE, + SPR_INDEXALPHA, + SPR_ALPHTEST, +} drawtype_t; + +typedef enum +{ + SPR_FWD_PARALLEL_UPRIGHT = 0, + SPR_FACING_UPRIGHT, + SPR_FWD_PARALLEL, + SPR_ORIENTED, + SPR_FWD_PARALLEL_ORIENTED, +} angletype_t; + +typedef enum +{ + SPR_CULL_FRONT = 0, // oriented sprite will be draw with one face + SPR_CULL_NONE, // oriented sprite will be draw back face too +} facetype_t; + +typedef struct +{ + int ident; // LittleLong 'ISPR' + int version; // current version 2 + angletype_t type; // camera align + drawtype_t texFormat; // rendering mode + int boundingradius; // quick face culling + int bounds[2]; // mins\maxs + int numframes; // including groups + facetype_t facetype; // cullface (Xash3D ext) + synctype_t synctype; // animation synctype +} dsprite_t; + +typedef struct +{ + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct +{ + int numframes; +} dspritegroup_t; + +typedef struct +{ + float interval; +} dspriteinterval_t; + +typedef struct +{ + frametype_t type; +} dframetype_t; + +#endif//SPRITE_H \ No newline at end of file diff --git a/engine/studio.h b/engine/studio.h new file mode 100644 index 00000000..8cffc27a --- /dev/null +++ b/engine/studio.h @@ -0,0 +1,369 @@ +/*** +* +* 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 STUDIO_H +#define STUDIO_H + +/* +============================================================================== + +STUDIO MODELS + +Studio models are position independent, so the cache manager can move them. +============================================================================== +*/ + +// header +#define STUDIO_VERSION 10 +#define IDSTUDIOHEADER (('T'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDST" +#define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ" + +// studio limits +#define MAXSTUDIOTRIANGLES 32768 // max triangles per model +#define MAXSTUDIOVERTS 4096 // max vertices per submodel +#define MAXSTUDIOSEQUENCES 256 // total animation sequences +#define MAXSTUDIOSKINS 256 // 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 // body parts per submodel +#define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) +#define MAXSTUDIOANIMATIONS 512 // max frames per sequence +#define MAXSTUDIOMESHES 256 // max textures per model +#define MAXSTUDIOEVENTS 1024 // events per model +#define MAXSTUDIOPIVOTS 256 // pivot points +#define MAXSTUDIOBLENDS 16 // max anim blends +#define MAXSTUDIOCONTROLLERS 8 // max controllers per model +#define MAXSTUDIOATTACHMENTS 4 // max attachments per model + +// client-side model flags +#define STUDIO_ROCKET 0x0001 // leave a trail +#define STUDIO_GRENADE 0x0002 // leave a trail +#define STUDIO_GIB 0x0004 // leave a trail +#define STUDIO_ROTATE 0x0008 // rotate (bonus items) +#define STUDIO_TRACER 0x0010 // green split trail +#define STUDIO_ZOMGIB 0x0020 // small blood trail +#define STUDIO_TRACER2 0x0040 // orange split trail + rotate +#define STUDIO_TRACER3 0x0080 // purple trail +#define STUDIO_DYNAMIC_LIGHT 0x0100 // dynamically get lighting from floor or ceil (flying monsters) +#define STUDIO_TRACE_HITBOX 0x0200 // always use hitbox trace instead of bbox + +// lighting & rendermode options +#define STUDIO_NF_FLATSHADE 0x0001 +#define STUDIO_NF_CHROME 0x0002 +#define STUDIO_NF_FULLBRIGHT 0x0004 +#define STUDIO_NF_COLORMAP 0x0008 // can changed by colormap command +#define STUDIO_NF_ALPHA 0x0010 // rendering as transparent texture +#define STUDIO_NF_ADDITIVE 0x0020 // rendering with additive mode +#define STUDIO_NF_TRANSPARENT 0x0040 // use texture with alpha channel +#define STUDIO_NF_NORMALMAP 0x0080 // indexed normalmap +#define STUDIO_NF_GLOSSMAP 0x0100 // heightmap that can be used for parallax or normalmap +#define STUDIO_NF_GLOSSPOWER 0x0200 // glossmap +#define STUDIO_NF_UV_COORDS (1<<31) // using fixed coords instead of ST + +// motion flags +#define STUDIO_X 0x0001 +#define STUDIO_Y 0x0002 +#define STUDIO_Z 0x0004 +#define STUDIO_XR 0x0008 +#define STUDIO_YR 0x0010 +#define STUDIO_ZR 0x0020 +#define STUDIO_LX 0x0040 +#define STUDIO_LY 0x0080 +#define STUDIO_LZ 0x0100 +#define STUDIO_AX 0x0200 +#define STUDIO_AY 0x0400 +#define STUDIO_AZ 0x0800 +#define STUDIO_AXR 0x1000 +#define STUDIO_AYR 0x2000 +#define STUDIO_AZR 0x4000 +#define STUDIO_TYPES 0x7FFF +#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + +// bonecontroller types +#define STUDIO_MOUTH 4 // hardcoded + +// sequence flags +#define STUDIO_LOOPING 0x0001 +#define STUDIO_STATIC 0x8000 // studiomodel is static + +// bone flags +#define STUDIO_HAS_NORMALS 0x0001 +#define STUDIO_HAS_VERTICES 0x0002 +#define STUDIO_HAS_BBOX 0x0004 +#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + +typedef struct +{ + int ident; + int version; + + char name[64]; + int length; + + vec3_t eyeposition; // ideal eye position + vec3_t min; // ideal movement hull size + vec3_t max; + + vec3_t bbmin; // clipping bounding box + vec3_t bbmax; + + int flags; + + int numbones; // bones + int boneindex; + + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + + int numhitboxes; // complex bounding boxes + int hitboxindex; + + int numseq; // animation sequences + int seqindex; + + int numseqgroups; // demand loaded sequences + int seqgroupindex; + + int numtextures; // raw textures + int textureindex; + int texturedataindex; + + int numskinref; // replaceable textures + int numskinfamilies; + int skinindex; + + int numbodyparts; + int bodypartindex; + + int numattachments; // queryable attachable points + int attachmentindex; + + int soundtable; + int soundindex; + int soundgroups; + int soundgroupindex; + + int numtransitions; // animation node to animation node transition graph + int transitionindex; +} studiohdr_t; + +// header for demand loaded sequence group data +typedef struct +{ + int id; + int version; + + char name[64]; + int length; +} studioseqhdr_t; + +// bones +typedef struct +{ + char name[32]; // bone name for symbolic links + int parent; // parent bone + int flags; // ?? + int bonecontroller[6]; // bone controller index, -1 == none + float value[6]; // default DoF values + float scale[6]; // scale for delta DoF values +} mstudiobone_t; + +// bone controllers +typedef struct +{ + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int index; // 0-3 user set controller, 4 mouth +} mstudiobonecontroller_t; + +// intersection boxes +typedef struct +{ + int bone; + int group; // intersection group + vec3_t bbmin; // bounding box + vec3_t bbmax; +} mstudiobbox_t; + +#ifndef CACHE_USER +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; // extradata +} cache_user_t; +#endif + +// demand loaded sequence groups +typedef struct +{ + char label[32]; // textual name + char name[64]; // file name + cache_user_t cache; // cache index pointer + int data; // hack for group 0 +} mstudioseqgroup_t; + +// sequence descriptions +typedef struct +{ + char label[32]; // sequence label + + float fps; // frames per second + int flags; // looping/non-looping flags + + int activity; + int actweight; + + int numevents; + int eventindex; + + int numframes; // number of frames per sequence + + int numpivots; // number of foot pivots + int pivotindex; + + int motiontype; + int motionbone; + vec3_t linearmovement; + int automoveposindex; + int automoveangleindex; + + vec3_t bbmin; // per sequence bounding box + vec3_t bbmax; + + int numblends; + int animindex; // mstudioanim_t pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + int blendtype[2]; // X, Y, Z, XR, YR, ZR + float blendstart[2]; // starting value + float blendend[2]; // ending value + int blendparent; + + int seqgroup; // sequence group for demand loading + + int entrynode; // transition node at entry + int exitnode; // transition node at exit + int nodeflags; // transition rules + + int nextseq; // auto advancing sequences +} mstudioseqdesc_t; + +// events +#include "studio_event.h" + +// pivots +typedef struct +{ + vec3_t org; // pivot point + int start; + int end; +} mstudiopivot_t; + +// attachment +typedef struct +{ + char name[32]; + int type; + int bone; + vec3_t org; // attachment point + vec3_t vectors[3]; +} mstudioattachment_t; + +typedef struct +{ + unsigned short offset[6]; +} mstudioanim_t; + +// animation frames +typedef union +{ + struct + { + byte valid; + byte total; + } num; + short value; +} mstudioanimvalue_t; + +// body part index +typedef struct +{ + char name[64]; + int nummodels; + int base; + int modelindex; // index into models array +} mstudiobodyparts_t; + +// skin info +typedef struct mstudiotex_s +{ + char name[64]; + unsigned short flags; + unsigned short unused; // lower 16 bit is a user area + int width; + int height; + int index; +} mstudiotexture_t; + +// skin families +// short index[skinfamilies][skinref] + +// studio models +typedef struct +{ + char name[64]; + + int type; + float boundingradius; + + int nummesh; + int meshindex; + + int numverts; // number of unique vertices + int vertinfoindex; // vertex bone info + int vertindex; // vertex vec3_t + int numnorms; // number of unique surface normals + int norminfoindex; // normal bone info + int normindex; // normal vec3_t + + int numgroups; // deformation groups + int groupindex; +} mstudiomodel_t; + +// vec3_t boundingbox[model][bone][2]; // complex intersection info + +// meshes +typedef struct +{ + int numtris; + int triindex; + int skinref; + int numnorms; // per mesh normals + int normindex; // normal vec3_t +} mstudiomesh_t; + +// triangles +typedef struct +{ + short vertindex; // index into vertex array + short normindex; // index into normal array + short s,t; // s,t position on skin +} mstudiotrivert_t; + +#endif//STUDIO_H \ No newline at end of file diff --git a/engine/warpsin.h b/engine/warpsin.h new file mode 100644 index 00000000..e140acf9 --- /dev/null +++ b/engine/warpsin.h @@ -0,0 +1,53 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +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. + +*/ + + +0.000000, 0.098165, 0.196270, 0.294259, 0.392069, 0.489643, 0.586920, 0.683850, +0.780360, 0.876405, 0.971920, 1.066850, 1.161140, 1.254725, 1.347560, 1.439580, +1.530735, 1.620965, 1.710220, 1.798445, 1.885585, 1.971595, 2.056410, 2.139990, +2.222280, 2.303235, 2.382795, 2.460925, 2.537575, 2.612690, 2.686235, 2.758160, +2.828425, 2.896990, 2.963805, 3.028835, 3.092040, 3.153385, 3.212830, 3.270340, +3.325880, 3.379415, 3.430915, 3.480350, 3.527685, 3.572895, 3.615955, 3.656840, +3.695520, 3.731970, 3.766175, 3.798115, 3.827760, 3.855105, 3.880125, 3.902810, +3.923140, 3.941110, 3.956705, 3.969920, 3.980740, 3.989160, 3.995180, 3.998795, +4.000000, 3.998795, 3.995180, 3.989160, 3.980740, 3.969920, 3.956705, 3.941110, +3.923140, 3.902810, 3.880125, 3.855105, 3.827760, 3.798115, 3.766175, 3.731970, +3.695520, 3.656840, 3.615955, 3.572895, 3.527685, 3.480350, 3.430915, 3.379415, +3.325880, 3.270340, 3.212830, 3.153385, 3.092040, 3.028835, 2.963805, 2.896990, +2.828425, 2.758160, 2.686235, 2.612690, 2.537575, 2.460925, 2.382795, 2.303235, +2.222280, 2.139990, 2.056410, 1.971595, 1.885585, 1.798445, 1.710220, 1.620965, +1.530735, 1.439580, 1.347560, 1.254725, 1.161140, 1.066850, 0.971920, 0.876405, +0.780360, 0.683850, 0.586920, 0.489643, 0.392069, 0.294259, 0.196270, 0.098165, +0.000000, -0.098165, -0.196270, -0.294259, -0.392069, -0.489643, -0.586920, -0.683850, +-0.780360, -0.876405, -0.971920, -1.066850, -1.161140, -1.254725, -1.347560, -1.439580, +-1.530735, -1.620965, -1.710220, -1.798445, -1.885585, -1.971595, -2.056410, -2.139990, +-2.222280, -2.303235, -2.382795, -2.460925, -2.537575, -2.612690, -2.686235, -2.758160, +-2.828425, -2.896990, -2.963805, -3.028835, -3.092040, -3.153385, -3.212830, -3.270340, +-3.325880, -3.379415, -3.430915, -3.480350, -3.527685, -3.572895, -3.615955, -3.656840, +-3.695520, -3.731970, -3.766175, -3.798115, -3.827760, -3.855105, -3.880125, -3.902810, +-3.923140, -3.941110, -3.956705, -3.969920, -3.980740, -3.989160, -3.995180, -3.998795, +-4.000000, -3.998795, -3.995180, -3.989160, -3.980740, -3.969920, -3.956705, -3.941110, +-3.923140, -3.902810, -3.880125, -3.855105, -3.827760, -3.798115, -3.766175, -3.731970, +-3.695520, -3.656840, -3.615955, -3.572895, -3.527685, -3.480350, -3.430915, -3.379415, +-3.325880, -3.270340, -3.212830, -3.153385, -3.092040, -3.028835, -2.963805, -2.896990, +-2.828425, -2.758160, -2.686235, -2.612690, -2.537575, -2.460925, -2.382795, -2.303235, +-2.222280, -2.139990, -2.056410, -1.971595, -1.885585, -1.798445, -1.710220, -1.620965, +-1.530735, -1.439580, -1.347560, -1.254725, -1.161140, -1.066850, -0.971920, -0.876405, +-0.780360, -0.683850, -0.586920, -0.489643, -0.392069, -0.294259, -0.196270, -0.098165, diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h new file mode 100644 index 00000000..0271a117 --- /dev/null +++ b/game_shared/bitvec.h @@ -0,0 +1,179 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + + +#include + + +class CBitVecAccessor +{ +public: + CBitVecAccessor(unsigned long *pDWords, int iBit); + + void operator=(int val); + operator unsigned long(); + +private: + unsigned long *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(); + unsigned long GetDWord(int i); + void SetDWord(int i, unsigned long val); + + int GetNumBits(); + +private: + + enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; + unsigned long m_DWords[NUM_DWORDS]; +}; + + + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(unsigned long *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] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator unsigned long() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + + +// ------------------------------------------------------------------------ // +// CBitVec inlines. +// ------------------------------------------------------------------------ // + +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) +{ + 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 int CBitVec::GetNumDWords() +{ + return NUM_DWORDS; +} + +template +inline unsigned long CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + + +template +inline void CBitVec::SetDWord(int i, unsigned long val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} + + +#endif // BITVEC_H + diff --git a/game_shared/vgui_checkbutton2.cpp b/game_shared/vgui_checkbutton2.cpp new file mode 100644 index 00000000..511853f8 --- /dev/null +++ b/game_shared/vgui_checkbutton2.cpp @@ -0,0 +1,197 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "vgui_checkbutton2.h" +#include "vgui_loadtga.h" + + +#define EXTRA_X 5 + + +using namespace vgui; + + + +CCheckButton2::CCheckButton2() : + m_Label(""), + m_pChecked(NULL), + m_pUnchecked(NULL), + m_pHandler(NULL), + m_CheckboxPanel(NULL) +{ + m_bOwnImages = false; + m_bChecked = false; + m_pChecked = m_pUnchecked = NULL; + m_bCheckboxLeft = true; + + m_Label.setParent(this); + m_Label.setFgColor(255,255,255,0); + m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white + m_Label.addInputSignal(this); + + m_CheckboxPanel.setParent(this); + m_CheckboxPanel.addInputSignal(this); + + setPaintBackgroundEnabled(false); +} + + +CCheckButton2::~CCheckButton2() +{ + DeleteImages(); +} + + +void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) +{ + DeleteImages(); + + m_pChecked = vgui_LoadTGA(pChecked); + m_pUnchecked = vgui_LoadTGA(pUnchecked); + m_bOwnImages = true; + + SetupControls(); +} + + +void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) +{ + DeleteImages(); + + m_pChecked = pChecked; + m_pUnchecked = pUnchecked; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::DeleteImages() +{ + if(m_bOwnImages) + { + delete m_pChecked; + delete m_pUnchecked; + } + + m_pChecked = NULL; + m_pUnchecked = NULL; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) +{ + m_bCheckboxLeft = bLeftAlign; + SetupControls(); +} + + +bool CCheckButton2::GetCheckboxLeft() +{ + return m_bCheckboxLeft; +} + + +void CCheckButton2::SetText(char const *pText, ...) +{ + char str[512]; + + va_list marker; + va_start(marker, pText); + _vsnprintf(str, sizeof(str), pText, marker); + va_end(marker); + + m_Label.setText(str); + SetupControls(); +} + + +void CCheckButton2::SetTextColor(int r, int g, int b, int a) +{ + m_Label.setFgColor(r, g, b, a); + repaint(); +} + + +void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) +{ + m_pHandler = pHandler; +} + + +bool CCheckButton2::IsChecked() +{ + return m_bChecked; +} + + +void CCheckButton2::SetChecked(bool bChecked) +{ + m_bChecked = bChecked; + SetupControls(); +} + + +void CCheckButton2::internalMousePressed(MouseCode code) +{ + m_bChecked = !m_bChecked; + + if(m_pHandler) + m_pHandler->StateChanged(this); + + SetupControls(); +} + + +void CCheckButton2::SetupControls() +{ + // Initialize the checkbutton bitmap. + Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; + + Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; + int controlSizes[2][2]; + + controlSizes[0][0] = controlSizes[0][1] = 0; + if(pBitmap) + pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); + + m_CheckboxPanel.setImage(pBitmap); + m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); + + + // Get the label's size. + m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); + m_Label.setContentAlignment(Label::a_west); + + + // Position the controls. + int iLeftControl = !m_bCheckboxLeft; + int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; + controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); + controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); + + + // Fit this control to the sizes of the subcontrols. + setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); + repaint(); +} + + +void CCheckButton2::mousePressed(MouseCode code, Panel *panel) +{ + internalMousePressed(code); +} + + + + + diff --git a/game_shared/vgui_checkbutton2.h b/game_shared/vgui_checkbutton2.h new file mode 100644 index 00000000..8f985d9f --- /dev/null +++ b/game_shared/vgui_checkbutton2.h @@ -0,0 +1,101 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_CHECKBUTTON2_H +#define VGUI_CHECKBUTTON2_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_label.h" +#include "vgui_imagepanel.h" +#include "vgui_defaultinputsignal.h" + + +namespace vgui +{ + + +class CCheckButton2; + + +class ICheckButton2Handler +{ +public: + virtual void StateChanged(CCheckButton2 *pButton) = 0; +}; + + +// VGUI checkbox class. +// - Provides access to the checkbox images. +// - Provides an easy callback mechanism for state changes. +// - Default background is invisible, and default text color is white. +class CCheckButton2 : public Panel, public CDefaultInputSignal +{ +public: + + CCheckButton2(); + ~CCheckButton2(); + + // Initialize the button with these. + void SetImages(char const *pChecked, char const *pUnchecked); + void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. + void DeleteImages(); + + // The checkbox can be to the left or the right of the text (default is left). + void SetCheckboxLeft(bool bLeftAlign); + bool GetCheckboxLeft(); + + // Set the label text. + void SetText(char const *pText, ...); + void SetTextColor(int r, int g, int b, int a); + + // You can register for change notification here. + void SetHandler(ICheckButton2Handler *pHandler); + + // Get/set the check state. + bool IsChecked(); + void SetChecked(bool bChecked); + + + +// Panel overrides. +public: + + virtual void internalMousePressed(MouseCode code); + + +protected: + + void SetupControls(); + + +// InputSignal overrides. +protected: + virtual void mousePressed(MouseCode code,Panel* panel); + + +public: + ICheckButton2Handler *m_pHandler; + + bool m_bCheckboxLeft; + Label m_Label; + ImagePanel m_CheckboxPanel; + + Image *m_pChecked; + Image *m_pUnchecked; + bool m_bOwnImages; + + bool m_bChecked; +}; + + +} + + +#endif // VGUI_CHECKBUTTON2_H diff --git a/game_shared/vgui_defaultinputsignal.h b/game_shared/vgui_defaultinputsignal.h new file mode 100644 index 00000000..94dae8df --- /dev/null +++ b/game_shared/vgui_defaultinputsignal.h @@ -0,0 +1,39 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_DEFAULTINPUTSIGNAL_H +#define VGUI_DEFAULTINPUTSIGNAL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_inputsignal.h" + + +namespace vgui +{ + // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. + class CDefaultInputSignal : public vgui::InputSignal + { + public: + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) {} + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseReleased(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} + }; +} + + +#endif // VGUI_DEFAULTINPUTSIGNAL_H diff --git a/game_shared/vgui_grid.cpp b/game_shared/vgui_grid.cpp new file mode 100644 index 00000000..00e9d699 --- /dev/null +++ b/game_shared/vgui_grid.cpp @@ -0,0 +1,398 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "vgui_grid.h" + + +using namespace vgui; + + +#define AssertCheck(expr, msg) \ + if(!(expr))\ + {\ + assert(!msg);\ + return 0;\ + } + + + +// ------------------------------------------------------------------------------ // +// CGrid::CGridEntry. +// ------------------------------------------------------------------------------ // + +CGrid::CGridEntry::CGridEntry() +{ + m_pPanel = NULL; + m_bUnderline = false; +} + +CGrid::CGridEntry::~CGridEntry() +{ +} + + +// ------------------------------------------------------------------------------ // +// CGrid. +// ------------------------------------------------------------------------------ // + +CGrid::CGrid() +{ + Clear(); +} + + +CGrid::~CGrid() +{ + Term(); +} + + +bool CGrid::SetDimensions(int xCols, int yRows) +{ + Term(); + + m_GridEntries = new CGridEntry[xCols * yRows]; + m_Widths = new int[xCols*2 + yRows*2]; + m_Heights = m_Widths + xCols; + m_ColOffsets = m_Heights + yRows; + m_RowOffsets = m_ColOffsets + xCols; + + if(!m_GridEntries || !m_Widths) + { + Term(); + return false; + } + + memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); + + m_xCols = xCols; + m_yRows = yRows; + return true; +} + + +void CGrid::Term() +{ + delete [] m_GridEntries; + delete [] m_Widths; + Clear(); +} + + +Panel* CGrid::GetEntry(int x, int y) +{ + return GridEntry(x, y)->m_pPanel; +} + + +bool CGrid::SetEntry(int x, int y, Panel *pPanel) +{ + CGridEntry *pEntry = GridEntry(x, y); + if(!pEntry) + return false; + + if(pEntry->m_pPanel) + pEntry->m_pPanel->setParent(NULL); + + pEntry->m_pPanel = pPanel; + if(pPanel) + pPanel->setParent(this); + + m_bDirty = true; + return true; +} + + +int CGrid::GetXSpacing() +{ + return m_xSpacing; +} + + +int CGrid::GetYSpacing() +{ + return m_ySpacing; +} + + +void CGrid::SetSpacing(int xSpacing, int ySpacing) +{ + if(xSpacing != m_xSpacing) + { + m_xSpacing = xSpacing; + CalcColOffsets(0); + m_bDirty = true; + } + + if(ySpacing != m_ySpacing) + { + m_ySpacing = ySpacing; + CalcRowOffsets(0); + m_bDirty = true; + } +} + + +bool CGrid::SetColumnWidth(int iColumn, int width) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); + m_Widths[iColumn] = width; + CalcColOffsets(iColumn+1); + m_bDirty = true; + return true; +} + + +bool CGrid::SetRowHeight(int iRow, int height) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); + m_Heights[iRow] = height; + CalcRowOffsets(iRow+1); + m_bDirty = true; + return true; +} + + +int CGrid::GetColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); + return m_Widths[iColumn]; +} + + +int CGrid::GetRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); + return m_Heights[iRow]; +} + + +int CGrid::CalcFitColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_yRows; i++) + { + Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(w > maxSize) + maxSize = w; + } + + return maxSize; +} + + +int CGrid::CalcFitRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_xCols; i++) + { + Panel *pPanel = GridEntry(i, iRow)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(h > maxSize) + maxSize = h; + } + + return maxSize; +} + + +void CGrid::AutoSetRowHeights() +{ + for(int i=0; i < m_yRows; i++) + SetRowHeight(i, CalcFitRowHeight(i)); +} + + +bool CGrid::GetEntryBox( + int col, int row, int &x, int &y, int &w, int &h) +{ + AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); + + x = m_ColOffsets[col]; + w = m_Widths[col]; + + y = m_RowOffsets[row]; + h = m_Heights[row]; + return true; +} + + +bool CGrid::CopyColumnWidths(CGrid *pOther) +{ + if(!pOther || pOther->m_xCols != m_xCols) + return false; + + for(int i=0; i < m_xCols; i++) + m_Widths[i] = pOther->m_Widths[i]; + + CalcColOffsets(0); + m_bDirty = true; + return true; +} + + +void CGrid::RepositionContents() +{ + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if(!pPanel) + continue; + + pPanel->setBounds( + m_ColOffsets[x], + m_RowOffsets[y], + m_Widths[x], + m_Heights[y]); + } + } + + m_bDirty = false; +} + + +int CGrid::CalcDrawHeight() +{ + if(m_yRows > 0) + { + return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; + } + else + { + return 0; + } +} + + +void CGrid::paint() +{ + if(m_bDirty) + RepositionContents(); + + Panel::paint(); + + // walk the grid looking for underlined rows + int x = 0, y = 0; + for (int row = 0; row < m_yRows; row++) + { + CGridEntry *cell = GridEntry(0, row); + + y += cell->m_pPanel->getTall() + m_ySpacing; + if (cell->m_bUnderline) + { + drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); + drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); + } + } +} + +void CGrid::paintBackground() +{ + Panel::paintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets underline color for a particular row +//----------------------------------------------------------------------------- +void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) +{ + CGridEntry *cell = GridEntry(0, row); + cell->m_bUnderline = enabled; + if (enabled) + { + cell->m_iUnderlineOffset = offset; + cell->m_UnderlineColor[0] = r; + cell->m_UnderlineColor[1] = g; + cell->m_UnderlineColor[2] = b; + cell->m_UnderlineColor[3] = a; + } +} + +void CGrid::Clear() +{ + m_xCols = m_yRows = 0; + m_Widths = NULL; + m_GridEntries = NULL; + m_xSpacing = m_ySpacing = 0; + m_bDirty = false; +} + + +CGrid::CGridEntry* CGrid::GridEntry(int x, int y) +{ + AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); + return &m_GridEntries[y*m_xCols + x]; +} + + +void CGrid::CalcColOffsets(int iStart) +{ + int cur = m_xSpacing; + if(iStart != 0) + cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; + + for(int i=iStart; i < m_xCols; i++) + { + m_ColOffsets[i] = cur; + cur += m_Widths[i] + m_xSpacing; + } +} + + +void CGrid::CalcRowOffsets(int iStart) +{ + int cur = m_ySpacing; + if(iStart != 0) + cur += m_RowOffsets[iStart-1]; + + for(int i=iStart; i < m_yRows; i++) + { + m_RowOffsets[i] = cur; + cur += m_Heights[i] + m_ySpacing; + } +} + +bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) +{ + row = -1; col = -1; + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if (!pPanel) + continue; + + if (pPanel->isWithin(worldX, worldY)) + { + col = x; + row = y; + return true; + } + } + } + + return false; +} + + diff --git a/game_shared/vgui_grid.h b/game_shared/vgui_grid.h new file mode 100644 index 00000000..472f5094 --- /dev/null +++ b/game_shared/vgui_grid.h @@ -0,0 +1,122 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_GRID_H +#define VGUI_GRID_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" + + +namespace vgui +{ + +// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and +// configure and fill the panels however you want. +// To use this control, call SetDimensions, SetSpacing and fill the controls. +class CGrid : public Panel +{ +public: + CGrid(); + virtual ~CGrid(); + + bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. + void Term(); + + Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. + bool SetEntry(int x, int y, Panel *pPanel); + + int GetXSpacing(); + int GetYSpacing(); + void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. + + bool SetColumnWidth(int iColumn, int width); // Set a column's width. + bool SetRowHeight(int iRow, int height); // Set a row's height. + + int GetColumnWidth(int iColumn); + int GetRowHeight(int iRow); + + int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. + int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. + + int CalcDrawHeight(); // Returns how many pixels high the grid control should be + // for all of its contents to be visible (based on its row heights + // and y spacing). + + void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. + + bool GetEntryBox( // Returns the bounding box for the specified entry. + int col, int row, int &x, int &y, int &w, int &h); + + bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the + // column count is different. + + void RepositionContents(); // Sets the size and position of all the grid entries based + // on current spacings and row/column widths. + // You usually only want to call this while setting up the control + // if you want to get the position or dimensions of the child + // controls. This will set them. + + void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row + + // returns the true if found, false otherwise + bool getCellAtPoint(int worldX, int worldY, int &row, int &col); + +// Panel overrides. +public: + + virtual void paint(); + virtual void paintBackground(); + +protected: + + class CGridEntry + { + public: + CGridEntry(); + ~CGridEntry(); + + Panel *m_pPanel; + + bool m_bUnderline; + short m_UnderlineColor[4]; + int m_iUnderlineOffset; + }; + + void Clear(); + CGridEntry* GridEntry(int x, int y); + + void CalcColOffsets(int iStart); + void CalcRowOffsets(int iStart); + + +protected: + + bool m_bDirty; // Set when controls will need to be repositioned. + + int m_xCols; + int m_yRows; + + int m_xSpacing; + int m_ySpacing; + + int *m_Widths; + int *m_Heights; + int *m_ColOffsets; + int *m_RowOffsets; + + CGridEntry *m_GridEntries; + +}; + +}; + + +#endif // VGUI_GRID_H diff --git a/game_shared/vgui_helpers.cpp b/game_shared/vgui_helpers.cpp new file mode 100644 index 00000000..fbcfeb5e --- /dev/null +++ b/game_shared/vgui_helpers.cpp @@ -0,0 +1,45 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_helpers.h" + + +using namespace vgui; + + +void AlignPanel(Panel *pChild, Panel *pParent, int alignment) +{ + int w, h, cw, ch; + pParent->getSize(w, h); + pChild->getSize(cw, ch); + + int xCenter = (w - cw) / 2; + int yCenter = (h - ch) / 2; + + if(alignment == Label::a_west) + pChild->setPos(0, yCenter); + else if(alignment == Label::a_northwest) + pChild->setPos(0,0); + else if(alignment == Label::a_north) + pChild->setPos(xCenter, 0); + else if(alignment == Label::a_northeast) + pChild->setPos(w - cw, 0); + else if(alignment == Label::a_east) + pChild->setPos(w - cw, yCenter); + else if(alignment == Label::a_southeast) + pChild->setPos(w - cw, h - ch); + else if(alignment == Label::a_south) + pChild->setPos(xCenter, h - ch); + else if(alignment == Label::a_southwest) + pChild->setPos(0, h - ch); + else if(alignment == Label::a_center) + pChild->setPos(xCenter, yCenter); +} + + + + diff --git a/game_shared/vgui_helpers.h b/game_shared/vgui_helpers.h new file mode 100644 index 00000000..f9ee45e8 --- /dev/null +++ b/game_shared/vgui_helpers.h @@ -0,0 +1,31 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_HELPERS_H +#define VGUI_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" +#include "vgui_label.h" + + +inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} +inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} +inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} +inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} +inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} +inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} + +// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. +void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); + + +#endif // VGUI_HELPERS_H + diff --git a/game_shared/vgui_listbox.cpp b/game_shared/vgui_listbox.cpp new file mode 100644 index 00000000..972091e0 --- /dev/null +++ b/game_shared/vgui_listbox.cpp @@ -0,0 +1,207 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_listbox.h" + + + +using namespace vgui; + + +CListBox::CListBox() : Panel(0, 0, 0, 0), + m_ItemsPanel(0,0,0,0), + m_ScrollBar(0, 0, 0, 0, true), + m_Slider(0, 0, 10, 40, true) +{ + m_Signal.m_pListBox = this; + + m_ItemsPanel.setParent(this); + m_ItemsPanel.setBgColor(0,0,0,255); + + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + m_ScrollBar.setParent(this); + m_ScrollBar.addIntChangeSignal(&m_Signal); + m_ScrollBar.setSlider(&m_Slider); + m_ScrollBar.setButtonPressedScrollValue(1); + + m_Items.m_pNext = m_Items.m_pPrev = &m_Items; + m_ItemOffset = 0; + m_iScrollMax = -1; +} + +CListBox::~CListBox() +{ + Term(); +} + +void CListBox::Init() +{ + Term(); +} + +void CListBox::Term() +{ + m_ItemOffset = 0; + + // Free the LBItems. + LBItem *pNext; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) + { + pItem->m_pPanel->setParent(NULL); // detach the panel from us + pNext = pItem->m_pNext; + delete pItem; + } + m_Items.m_pPrev = m_Items.m_pNext = &m_Items; +} + +void CListBox::AddItem(Panel* panel) +{ + // Add the item. + LBItem *pItem = new LBItem; + if(!pItem) + return; + + pItem->m_pPanel = panel; + pItem->m_pPanel->setParent(&m_ItemsPanel); + + pItem->m_pPrev = m_Items.m_pPrev; + pItem->m_pNext = &m_Items; + pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; + + m_ScrollBar.setRange(0, GetScrollMax()); + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + InternalLayout(); +} + +int CListBox::GetNumItems() +{ + int count=0; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + ++count; + + return count; +} + +int CListBox::GetItemWidth() +{ + int wide, tall; + m_ItemsPanel.getSize(wide, tall); + return wide; +} + +int CListBox::GetScrollPos() +{ + return m_ItemOffset; +} + +void CListBox::SetScrollPos(int pos) +{ + int maxItems = GetScrollMax(); + if(maxItems < 0) + return; + + m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); + InternalLayout(); +} + +void CListBox::setPos(int x, int y) +{ + Panel::setPos(x, y); + InternalLayout(); +} + +void CListBox::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + InternalLayout(); +} + +void CListBox::setPixelScroll(int value) +{ + m_ItemOffset = m_ScrollBar.getValue(); + InternalLayout(); +} + +void CListBox::InternalLayout() +{ + int x, y, wide, tall; + getBounds(x, y, wide, tall); + + // Reposition the main panel and the scrollbar. + m_ItemsPanel.setBounds(0, 0, wide-15, tall); + m_ScrollBar.setBounds(wide-15, 0, 15, tall); + + bool bNeedScrollbar = false; + + // Reposition the items. + int curItem = 0; + int curY = 0; + int maxItem = GetScrollMax(); + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + { + if(curItem < m_ItemOffset) + { + pItem->m_pPanel->setVisible(false); + bNeedScrollbar = true; + } + else if (curItem >= maxItem) + { + // item is past the end of the items we care about + pItem->m_pPanel->setVisible(false); + } + else + { + pItem->m_pPanel->setVisible(true); + + int itemWidth, itemHeight; + pItem->m_pPanel->getSize(itemWidth, itemHeight); + + // Don't change the item's height but change its width to fit the listbox. + pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); + + curY += itemHeight; + + if (curY > tall) + { + bNeedScrollbar = true; + } + } + + ++curItem; + } + + m_ScrollBar.setVisible(bNeedScrollbar); + + repaint(); +} + +void CListBox::paintBackground() +{ +} + +void CListBox::SetScrollRange(int maxScroll) +{ + m_iScrollMax = maxScroll; + m_ScrollBar.setRange(0, maxScroll); + InternalLayout(); +} + +int CListBox::GetScrollMax() +{ + if (m_iScrollMax < 0) + { + return GetNumItems() - 1; + } + + return m_iScrollMax; +} + + diff --git a/game_shared/vgui_listbox.h b/game_shared/vgui_listbox.h new file mode 100644 index 00000000..a48acef4 --- /dev/null +++ b/game_shared/vgui_listbox.h @@ -0,0 +1,115 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_LISTBOX_H +#define VOICE_LISTBOX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" +#include "VGUI_IntChangeSignal.h" + +#include "VGUI_Slider2.h" +#include "VGUI_ScrollBar2.h" + + +namespace vgui +{ + +// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: +// - This listbox clips its child items to its rectangle. +// - You can access things like the scrollbar and find out the item width. +// - The scrollbar scrolls one element at a time and the range is correct. + +// Note: this listbox does not provide notification when items are +class CListBox : public Panel +{ +public: + + CListBox(); + ~CListBox(); + + void Init(); + void Term(); + + // Add an item to the listbox. This automatically sets the item's parent to the listbox + // and resizes the item's width to fit within the listbox. + void AddItem(Panel *pPanel); + + // Get the number of items currently in the listbox. + int GetNumItems(); + + // Get the width that listbox items will be set to (this changes if you resize the listbox). + int GetItemWidth(); + + // Get/set the scrollbar position (position says which element is at the top of the listbox). + int GetScrollPos(); + void SetScrollPos(int pos); + + // sets the last item the listbox should scroll to + // scroll to GetNumItems() if not set + void SetScrollRange(int maxScroll); + + // returns the maximum value the scrollbar can scroll to + int GetScrollMax(); + +// vgui overrides. +public: + + virtual void setPos(int x, int y); + virtual void setSize(int wide,int tall); + virtual void setPixelScroll(int value); + virtual void paintBackground(); + + +protected: + + class LBItem + { + public: + Panel *m_pPanel; + LBItem *m_pPrev, *m_pNext; + }; + + class ListBoxSignal : public IntChangeSignal + { + public: + void intChanged(int value,Panel* panel) + { + m_pListBox->setPixelScroll(-value); + } + + vgui::CListBox *m_pListBox; + }; + + +protected: + + void InternalLayout(); + + +protected: + + // All the items.. + LBItem m_Items; + + Panel m_ItemsPanel; + + int m_ItemOffset; // where we're scrolled to + Slider2 m_Slider; + ScrollBar2 m_ScrollBar; + ListBoxSignal m_Signal; + + int m_iScrollMax; +}; + +} + + +#endif // VOICE_LISTBOX_H diff --git a/game_shared/vgui_loadtga.cpp b/game_shared/vgui_loadtga.cpp new file mode 100644 index 00000000..d7e1f5e9 --- /dev/null +++ b/game_shared/vgui_loadtga.cpp @@ -0,0 +1,93 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/wrect.h" +#include "../cl_dll/cl_dll.h" +#include "vgui.h" +#include "vgui_loadtga.h" +#include "vgui_inputstream.h" + + +// ---------------------------------------------------------------------- // +// Helper class for loading tga files. +// ---------------------------------------------------------------------- // +class MemoryInputStream : public vgui::InputStream +{ +public: + MemoryInputStream() + { + m_pData = NULL; + m_DataLen = m_ReadPos = 0; + } + + virtual void seekStart(bool& success) {m_ReadPos=0; success=true;} + virtual void seekRelative(int count,bool& success) {m_ReadPos+=count; success=true;} + virtual void seekEnd(bool& success) {m_ReadPos=m_DataLen; success=true;} + virtual int getAvailable(bool& success) {success=false; return 0;} // This is what vgui does for files... + + virtual uchar readUChar(bool& success) + { + if(m_ReadPos>=0 && m_ReadPos +#include +#include +#include + +using namespace vgui; + + +namespace +{ +class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal +{ +public: + FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) + { + _scrollBar=scrollBar; + } + virtual void intChanged(int value,Panel* panel) + { + _scrollBar->fireIntChangeSignal(); + } +protected: + ScrollBar2* _scrollBar; +}; + +class FooDefaultButtonSignal : public ActionSignal +{ +public: + ScrollBar2* _scrollBar; + int _buttonIndex; +public: + FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) + { + _scrollBar=scrollBar; + _buttonIndex=buttonIndex; + } +public: + virtual void actionPerformed(Panel* panel) + { + _scrollBar->doButtonPressed(_buttonIndex); + } +}; + +} + +//----------------------------------------------------------------------------- +// Purpose: Default scrollbar button +// Draws in new scoreboard style +//----------------------------------------------------------------------------- +class ScrollBarButton : public Button +{ +private: + LineBorder m_Border; + +public: + ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) + { + Image *image = vgui_LoadTGA(filename); + if (image) + { + image->setColor(Color(140, 140, 140, 0)); + setImage(image); + } + + setBorder(&m_Border); + } + + virtual void paintBackground() + { + int wide,tall; + getPaintSize(wide,tall); + + // fill the background + drawSetColor(0, 0, 0, 0); + drawFilledRect(0, 0, wide, tall); + } +}; + + + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : x - +// y - +// wide - +// tall - +// vertical - +//----------------------------------------------------------------------------- +ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _slider=null; + _button[0]=null; + _button[1]=null; + + if(vertical) + { + setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); + setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); + setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); + } + else + { + // untested code + setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); + setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); + setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); + } + + setPaintBorderEnabled(true); + setPaintBackgroundEnabled(true); + setPaintEnabled(true); + setButtonPressedScrollValue(15); + + validate(); + } + +void ScrollBar2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + if(_slider==null) + { + return; + } + + if(_button[0]==null) + { + return; + } + + if(_button[1]==null) + { + return; + } + + getPaintSize(wide,tall); + + if(_slider->isVertical()) + { + _slider->setBounds(0,wide,wide,tall-(wide*2)); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,wide,wide); + _button[1]->setBounds(0,tall-wide,wide,wide); + } + else + { + _slider->setBounds(tall,0,wide-(tall*2),tall); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,tall,tall); + _button[1]->setBounds((wide-tall),0,tall,tall); + } +} + +void ScrollBar2::performLayout() +{ +} + +void ScrollBar2::setValue(int value) +{ + _slider->setValue(value); +} + +int ScrollBar2::getValue() +{ + return _slider->getValue(); +} + +void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); +} + +void ScrollBar2::setRange(int min,int max) +{ + _slider->setRange(min,max); +} + +void ScrollBar2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); + } +} + +bool ScrollBar2::isVertical() +{ + return _slider->isVertical(); +} + +bool ScrollBar2::hasFullRange() +{ + return _slider->hasFullRange(); +} + +//LEAK: new and old slider will leak +void ScrollBar2::setButton(Button* button,int index) +{ + if(_button[index]!=null) + { + removeChild(_button[index]); + } + _button[index]=button; + addChild(_button[index]); + + _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); + + validate(); + + //_button[index]->setVisible(false); +} + +Button* ScrollBar2::getButton(int index) +{ + return _button[index]; +} + +//LEAK: new and old slider will leak +void ScrollBar2::setSlider(Slider2 *slider) +{ + if(_slider!=null) + { + removeChild(_slider); + } + _slider=slider; + addChild(_slider); + + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); + + validate(); +} + +Slider2 *ScrollBar2::getSlider() +{ + return _slider; +} + +void ScrollBar2::doButtonPressed(int buttonIndex) +{ + if(buttonIndex==0) + { + _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); + } + else + { + _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); + } + +} + +void ScrollBar2::setButtonPressedScrollValue(int value) +{ + _buttonPressedScrollValue=value; +} + +void ScrollBar2::setRangeWindow(int rangeWindow) +{ + _slider->setRangeWindow(rangeWindow); +} + +void ScrollBar2::setRangeWindowEnabled(bool state) +{ + _slider->setRangeWindowEnabled(state); +} + +void ScrollBar2::validate() +{ + if(_slider!=null) + { + int buttonOffset=0; + + for(int i=0;i<2;i++) + { + if(_button[i]!=null) + { + if(_button[i]->isVisible()) + { + if(_slider->isVertical()) + { + buttonOffset+=_button[i]->getTall(); + } + else + { + buttonOffset+=_button[i]->getWide(); + } + } + } + } + + _slider->setButtonOffset(buttonOffset); + } + + int wide,tall; + getSize(wide,tall); + setSize(wide,tall); +} diff --git a/game_shared/vgui_scrollbar2.h b/game_shared/vgui_scrollbar2.h new file mode 100644 index 00000000..b9dfea6d --- /dev/null +++ b/game_shared/vgui_scrollbar2.h @@ -0,0 +1,62 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SCROLLBAR2_H +#define VGUI_SCROLLBAR2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class IntChangeSignal; +class Button; +class Slider2; + +//----------------------------------------------------------------------------- +// Purpose: Hacked up version of the vgui scrollbar +//----------------------------------------------------------------------------- +class VGUIAPI ScrollBar2 : public Panel +{ +public: + ScrollBar2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual bool isVertical(); + virtual bool hasFullRange(); + virtual void setButton(Button *button,int index); + virtual Button* getButton(int index); + virtual void setSlider(Slider2 *slider); + virtual Slider2 *getSlider(); + virtual void doButtonPressed(int buttonIndex); + virtual void setButtonPressedScrollValue(int value); + virtual void validate(); +public: //bullshit public + virtual void fireIntChangeSignal(); +protected: + virtual void performLayout(); +protected: + Button* _button[2]; + Slider2 *_slider; + Dar _intChangeSignalDar; + int _buttonPressedScrollValue; +}; + +} + +#endif // VGUI_SCROLLBAR2_H diff --git a/game_shared/vgui_slider2.cpp b/game_shared/vgui_slider2.cpp new file mode 100644 index 00000000..7a220b5b --- /dev/null +++ b/game_shared/vgui_slider2.cpp @@ -0,0 +1,436 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: New version of the slider bar +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Slider2.h" + +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooDefaultSliderSignal : public InputSignal +{ +private: + Slider2* _slider; +public: + FooDefaultSliderSignal(Slider2* slider) + { + _slider=slider; + } +public: + void cursorMoved(int x,int y,Panel* panel) + { + _slider->privateCursorMoved(x,y,panel); + } + void cursorEntered(Panel* panel){} + void cursorExited(Panel* panel){} + void mouseDoublePressed(MouseCode code,Panel* panel){} + void mousePressed(MouseCode code,Panel* panel) + { + _slider->privateMousePressed(code,panel); + } + void mouseReleased(MouseCode code,Panel* panel) + { + _slider->privateMouseReleased(code,panel); + } + void mouseWheeled(int delta,Panel* panel){} + void keyPressed(KeyCode code,Panel* panel){} + void keyTyped(KeyCode code,Panel* panel){} + void keyReleased(KeyCode code,Panel* panel){} + void keyFocusTicked(Panel* panel){} +}; +} + +Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _vertical=vertical; + _dragging=false; + _value=0; + _range[0]=0; + _range[1]=299; + _rangeWindow=0; + _rangeWindowEnabled=false; + _buttonOffset=0; + recomputeNobPosFromValue(); + addInputSignal(new FooDefaultSliderSignal(this)); +} + +void Slider2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + recomputeNobPosFromValue(); +} + +bool Slider2::isVertical() +{ + return _vertical; +} + +void Slider2::setValue(int value) +{ + int oldValue=_value; + + if(value<_range[0]) + { + value=_range[0]; + } + + if(value>_range[1]) + { + value=_range[1]; + } + + _value=value; + recomputeNobPosFromValue(); + + if(_value!=oldValue) + { + fireIntChangeSignal(); + } +} + +int Slider2::getValue() +{ + return _value; +} + +void Slider2::recomputeNobPosFromValue() +{ + int wide,tall; + + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fper=fvalue/frange; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + float freepixels = ftall - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-((int)fnobsize); + _nobPos[1]=tall; + } + } + else + { + float fnobsize=frangewindow; + float freepixels = fwide - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-((int)fnobsize); + _nobPos[1]=wide; + } + } + } + + repaint(); +} + +void Slider2::recomputeValueFromNobPos() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fnob=(float)_nobPos[0]; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(ftall-fnobsize)); + } + else + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(fwide-fnobsize)); + } + } + // Take care of rounding issues. + _value=(int)(fvalue+_range[0]+0.5); + + // Clamp final result + _value = ( _value < _range[1] ) ? _value : _range[1]; +} + +bool Slider2::hasFullRange() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + if( frangewindow <= ( ftall + _buttonOffset ) ) + { + return true; + } + } + else + { + if( frangewindow <= ( fwide + _buttonOffset ) ) + { + return true; + } + } + } + + return false; +} + +void Slider2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); +} + +void Slider2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(getValue(),this); + } +} + +void Slider2::paintBackground() +{ + int wide,tall; + getPaintSize(wide,tall); + + if (_vertical) + { + // background behind slider + drawSetColor(40, 40, 40, 0); + drawFilledRect(0, 0, wide, tall); + + // slider front + drawSetColor(0, 0, 0, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); + + // slider border + drawSetColor(60, 60, 60, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top + drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom + drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left + drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right + } + else + { + //!! doesn't work + + drawSetColor(Scheme::sc_secondary3); + drawFilledRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_primary2); + drawFilledRect(_nobPos[0],0,_nobPos[1],tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); + } +} + +void Slider2::setRange(int min,int max) +{ + if(maxmax) + { + min=max; + } + + _range[0]=min; + _range[1]=max; +} + +void Slider2::getRange(int& min,int& max) +{ + min=_range[0]; + max=_range[1]; +} + +void Slider2::privateCursorMoved(int x,int y,Panel* panel) +{ + if(!_dragging) + { + return; + } + + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + int wide,tall; + getPaintSize(wide,tall); + + if(_vertical) + { + _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); + _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=tall; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + else + { + _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); + _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=wide; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + + recomputeValueFromNobPos(); + repaint(); + fireIntChangeSignal(); +} + +void Slider2::privateMousePressed(MouseCode code,Panel* panel) +{ + int x,y; + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + if(_vertical) + { + if((y>=_nobPos[0])&&(y<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + else + { + if((x>=_nobPos[0])&&(x<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + +} + +void Slider2::privateMouseReleased(MouseCode code,Panel* panel) +{ + _dragging=false; + getApp()->setMouseCapture(null); +} + +void Slider2::getNobPos(int& min, int& max) +{ + min=_nobPos[0]; + max=_nobPos[1]; +} + +void Slider2::setRangeWindow(int rangeWindow) +{ + _rangeWindow=rangeWindow; +} + +void Slider2::setRangeWindowEnabled(bool state) +{ + _rangeWindowEnabled=state; +} + +void Slider2::setButtonOffset(int buttonOffset) +{ + _buttonOffset=buttonOffset; +} \ No newline at end of file diff --git a/game_shared/vgui_slider2.h b/game_shared/vgui_slider2.h new file mode 100644 index 00000000..ec384210 --- /dev/null +++ b/game_shared/vgui_slider2.h @@ -0,0 +1,67 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SLIDER2_H +#define VGUI_SLIDER2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class IntChangeSignal; + +class VGUIAPI Slider2 : public Panel +{ +private: + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + Dar _intChangeSignalDar; + int _range[2]; + int _value; + int _rangeWindow; + bool _rangeWindowEnabled; + int _buttonOffset; +public: + Slider2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual bool isVertical(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void getRange(int& min,int& max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual void getNobPos(int& min, int& max); + virtual bool hasFullRange(); + virtual void setButtonOffset(int buttonOffset); +private: + virtual void recomputeNobPosFromValue(); + virtual void recomputeValueFromNobPos(); +public: //bullshit public + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); +protected: + virtual void fireIntChangeSignal(); + virtual void paintBackground(); +}; + +} + +#endif // VGUI_SLIDER2_H diff --git a/game_shared/voice_banmgr.cpp b/game_shared/voice_banmgr.cpp new file mode 100644 index 00000000..470e80ec --- /dev/null +++ b/game_shared/voice_banmgr.cpp @@ -0,0 +1,197 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "voice_banmgr.h" + + +#define BANMGR_FILEVERSION 1 +char const *g_pBanMgrFilename = "voice_ban.dt"; + + + +// Hash a player ID to a byte. +unsigned char HashPlayerID(char const playerID[16]) +{ + unsigned char curHash = 0; + + for(int i=0; i < 16; i++) + curHash += (unsigned char)playerID[i]; + + return curHash; +} + + + +CVoiceBanMgr::CVoiceBanMgr() +{ + Clear(); +} + + +CVoiceBanMgr::~CVoiceBanMgr() +{ + Term(); +} + + +bool CVoiceBanMgr::Init(char const *pGameDir) +{ + Term(); + + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + // Load in the squelch file. + FILE *fp = fopen(filename, "rb"); + if(fp) + { + int version; + fread(&version, 1, sizeof(version), fp); + if(version == BANMGR_FILEVERSION) + { + fseek(fp, 0, SEEK_END); + int nIDs = (ftell(fp) - sizeof(version)) / 16; + fseek(fp, sizeof(version), SEEK_SET); + + for(int i=0; i < nIDs; i++) + { + char playerID[16]; + fread(playerID, 1, 16, fp); + AddBannedPlayer(playerID); + } + } + + fclose(fp); + } + + return true; +} + + +void CVoiceBanMgr::Term() +{ + // Free all the player structures. + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + BannedPlayer *pNext; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) + { + pNext = pCur->m_pNext; + delete pCur; + } + } + + Clear(); +} + + +void CVoiceBanMgr::SaveState(char const *pGameDir) +{ + // Save the file out. + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + FILE *fp = fopen(filename, "wb"); + if(fp) + { + int version = BANMGR_FILEVERSION; + fwrite(&version, 1, sizeof(version), fp); + + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + fwrite(pCur->m_PlayerID, 1, 16, fp); + } + } + + fclose(fp); + } +} + + +bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) +{ + return !!InternalFindPlayerSquelch(playerID); +} + + +void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) +{ + if(bSquelch) + { + // Is this guy already squelched? + if(GetPlayerBan(playerID)) + return; + + AddBannedPlayer(playerID); + } + else + { + BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); + if(pPlayer) + { + pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; + pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; + delete pPlayer; + } + } +} + + +void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) +{ + for(int i=0; i < 256; i++) + { + for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) + { + callback(pCur->m_PlayerID); + } + } +} + + +void CVoiceBanMgr::Clear() +{ + // Tie off the hash table entries. + for(int i=0; i < 256; i++) + m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) +{ + int index = HashPlayerID(playerID); + BannedPlayer *pListHead = &m_PlayerHash[index]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) + return pCur; + } + + return NULL; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) +{ + BannedPlayer *pNew = new BannedPlayer; + if(!pNew) + return NULL; + + int index = HashPlayerID(playerID); + memcpy(pNew->m_PlayerID, playerID, 16); + pNew->m_pNext = &m_PlayerHash[index]; + pNew->m_pPrev = m_PlayerHash[index].m_pPrev; + pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; + return pNew; +} + diff --git a/game_shared/voice_banmgr.h b/game_shared/voice_banmgr.h new file mode 100644 index 00000000..2f14d8b7 --- /dev/null +++ b/game_shared/voice_banmgr.h @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_BANMGR_H +#define VOICE_BANMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class manages the (persistent) list of squelched players. +class CVoiceBanMgr +{ +public: + + CVoiceBanMgr(); + ~CVoiceBanMgr(); + + // Init loads the list of squelched players from disk. + bool Init(char const *pGameDir); + void Term(); + + // Saves the state into voice_squelch.dt. + void SaveState(char const *pGameDir); + + bool GetPlayerBan(char const playerID[16]); + void SetPlayerBan(char const playerID[16], bool bSquelch); + + // Call your callback for each banned player. + void ForEachBannedPlayer(void (*callback)(char id[16])); + + +protected: + + class BannedPlayer + { + public: + char m_PlayerID[16]; + BannedPlayer *m_pPrev, *m_pNext; + }; + + void Clear(); + BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); + BannedPlayer* AddBannedPlayer(char const playerID[16]); + + +protected: + + BannedPlayer m_PlayerHash[256]; +}; + + +#endif // VOICE_BANMGR_H diff --git a/game_shared/voice_common.h b/game_shared/voice_common.h new file mode 100644 index 00000000..93e9353f --- /dev/null +++ b/game_shared/voice_common.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitvec.h" + + +#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec CPlayerBitVec; + + +#endif // VOICE_COMMON_H diff --git a/game_shared/voice_gamemgr.cpp b/game_shared/voice_gamemgr.cpp new file mode 100644 index 00000000..5ba2edfe --- /dev/null +++ b/game_shared/voice_gamemgr.cpp @@ -0,0 +1,274 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "voice_gamemgr.h" +#include +#include +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" + + + +#define UPDATE_INTERVAL 0.3 + + +// These are stored off as CVoiceGameMgr is created and deleted. +CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. + // (If it's zero, then the server reports that the game rules are saying the + // player can't hear anyone). + +CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. + // These are indexed as clients and each bit represents a client + // (so player entity is bit+1). + +CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if +CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. +CPlayerBitVec g_bWantModEnable; + +cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; + +// Set game rules to allow all clients to talk to each other. +// Muted players still can't talk to each other. +cvar_t sv_alltalk = {"sv_alltalk", "0"}; + +// ------------------------------------------------------------------------ // +// Static helpers. +// ------------------------------------------------------------------------ // + +// Find a player with a case-insensitive name search. +static CBasePlayer* FindPlayerByName(const char *pTestName) +{ + for(int i=1; i <= gpGlobals->maxClients; i++) + { + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); + if(pEdict) + { + CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); + if(pEnt && pEnt->IsPlayer()) + { + const char *pNetName = STRING(pEnt->pev->netname); + if(stricmp(pNetName, pTestName) == 0) + { + return (CBasePlayer*)pEnt; + } + } + } + } + + return NULL; +} + +static void VoiceServerDebug( char const *pFmt, ... ) +{ + char msg[4096]; + va_list marker; + + if( !voice_serverdebug.value ) + return; + + va_start( marker, pFmt ); + _vsnprintf( msg, sizeof(msg), pFmt, marker ); + va_end( marker ); + + ALERT( at_console, "%s", msg ); +} + + + +// ------------------------------------------------------------------------ // +// CVoiceGameMgr. +// ------------------------------------------------------------------------ // + +CVoiceGameMgr::CVoiceGameMgr() +{ + m_UpdateInterval = 0; + m_nMaxPlayers = 0; +} + + +CVoiceGameMgr::~CVoiceGameMgr() +{ +} + + +bool CVoiceGameMgr::Init( + IVoiceGameMgrHelper *pHelper, + int maxClients) +{ + m_pHelper = pHelper; + m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; + g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); + + m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); + m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); + + // register voice_serverdebug if it hasn't been registered already + if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) + CVAR_REGISTER( &voice_serverdebug ); + + if( !CVAR_GET_POINTER( "sv_alltalk" ) ) + CVAR_REGISTER( &sv_alltalk ); + + return true; +} + + +void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) +{ + m_pHelper = pHelper; +} + + +void CVoiceGameMgr::Update(double frametime) +{ + // Only update periodically. + m_UpdateInterval += frametime; + if(m_UpdateInterval < UPDATE_INTERVAL) + return; + + UpdateMasks(); +} + + +void CVoiceGameMgr::ClientConnected(edict_t *pEdict) +{ + int index = ENTINDEX(pEdict) - 1; + + // Clear out everything we use for deltas on this guy. + g_bWantModEnable[index] = true; + g_SentGameRulesMasks[index].Init(0); + g_SentBanMasks[index].Init(0); +} + +// Called to determine if the Receiver has muted (blocked) the Sender +// Returns true if the receiver has blocked the sender +bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) +{ + int iReceiverIndex, iSenderIndex; + + if ( !pReceiver || !pSender ) + return false; + + iReceiverIndex = pReceiver->entindex() - 1; + iSenderIndex = pSender->entindex() - 1; + + if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) + return false; + + return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); +} + +bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) +{ + int playerClientIndex = pPlayer->entindex() - 1; + if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); + return true; + } + + bool bBan = stricmp(cmd, "vban") == 0; + if(bBan && CMD_ARGC() >= 2) + { + for(int i=1; i < CMD_ARGC(); i++) + { + unsigned long mask = 0; + sscanf(CMD_ARGV(i), "%x", &mask); + + if(i <= VOICE_MAX_PLAYERS_DW) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); + g_BanMasks[playerClientIndex].SetDWord(i-1, mask); + } + else + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); + } + } + + // Force it to update the masks now. + //UpdateMasks(); + return true; + } + else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); + g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); + g_bWantModEnable[playerClientIndex] = false; + //UpdateMasks(); + return true; + } + else + { + return false; + } +} + + +void CVoiceGameMgr::UpdateMasks() +{ + m_UpdateInterval = 0; + + bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" ); + + for(int iClient=0; iClient < m_nMaxPlayers; iClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); + if(!pEnt || !pEnt->IsPlayer()) + continue; + + // Request the state of their "VModEnable" cvar. + if(g_bWantModEnable[iClient]) + { + MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); + MESSAGE_END(); + } + + CBasePlayer *pPlayer = (CBasePlayer*)pEnt; + + CPlayerBitVec gameRulesMask; + if( g_PlayerModEnable[iClient] ) + { + // Build a mask of who they can hear based on the game rules. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1); + if(pEnt && pEnt->IsPlayer() && + (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) + { + gameRulesMask[iOtherClient] = true; + } + } + } + + // If this is different from what the client has, send an update. + if(gameRulesMask != g_SentGameRulesMasks[iClient] || + g_BanMasks[iClient] != g_SentBanMasks[iClient]) + { + g_SentGameRulesMasks[iClient] = gameRulesMask; + g_SentBanMasks[iClient] = g_BanMasks[iClient]; + + MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); + int dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + WRITE_LONG(gameRulesMask.GetDWord(dw)); + WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); + } + MESSAGE_END(); + } + + // Tell the engine. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; + g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); + } + } +} diff --git a/game_shared/voice_gamemgr.h b/game_shared/voice_gamemgr.h new file mode 100644 index 00000000..9605c5c8 --- /dev/null +++ b/game_shared/voice_gamemgr.h @@ -0,0 +1,79 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_GAMEMGR_H +#define VOICE_GAMEMGR_H +#pragma once + + +#include "voice_common.h" + + +class CGameRules; +class CBasePlayer; + + +class IVoiceGameMgrHelper +{ +public: + virtual ~IVoiceGameMgrHelper() {} + + // 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: + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); + + bool Init( + IVoiceGameMgrHelper *m_pHelper, + int maxClients + ); + + void SetHelper(IVoiceGameMgrHelper *pHelper); + + // Updates which players can hear which other players. + // If gameplay mode is DM, then only players within the PVS can hear each other. + // If gameplay mode is teamplay, then only players on the same team can hear each other. + // Player masks are always applied. + void Update(double frametime); + + // Called when a new client connects (unsquelches its entity for everyone). + void ClientConnected(struct edict_s *pEdict); + + // Called on ClientCommand. Checks for the squelch and unsquelch commands. + // Returns true if it handled the command. + bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); + + // Called to determine if the Receiver has muted (blocked) the Sender + // Returns true if the receiver has blocked the sender + bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); + + +private: + + // Force it to update the client masks. + void UpdateMasks(); + + +private: + int m_msgPlayerVoiceMask; + int m_msgRequestState; + + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. +}; + + +#endif // VOICE_GAMEMGR_H diff --git a/game_shared/voice_status.cpp b/game_shared/voice_status.cpp new file mode 100644 index 00000000..e5378d00 --- /dev/null +++ b/game_shared/voice_status.cpp @@ -0,0 +1,874 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// There are hud.h's coming out of the woodwork so this ensures that we get the right one. +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/hud.h" + #include "../dmc/cl_dll/cl_util.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/hud.h" + #include "../ricochet/cl_dll/cl_util.h" +#else + #include "../cl_dll/hud.h" + #include "../cl_dll/cl_util.h" +#endif + +#include +#include +#include + +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/parsemsg.h" + #include "../dmc/cl_dll/hud_servers.h" + #include "../dmc/cl_dll/demo.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/parsemsg.h" + #include "../ricochet/cl_dll/hud_servers.h" + #include "../ricochet/cl_dll/demo.h" +#else + #include "../cl_dll/parsemsg.h" + #include "../cl_dll/hud_servers.h" + #include "../cl_dll/demo.h" +#endif + +#include "demo_api.h" +#include "voice_status.h" +#include "r_efx.h" +#include "entity_types.h" +#include "VGUI_ActionSignal.h" +#include "VGUI_Scheme.h" +#include "VGUI_TextImage.h" +#include "vgui_loadtga.h" +#include "vgui_helpers.h" +#include "vgui_mousecode.h" + + + +using namespace vgui; + + +extern int cam_thirdperson; + + +#define VOICE_MODEL_INTERVAL 0.3 +#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. +#define SQUELCHOSCILLATE_PER_SECOND 2.0f + + +extern BitmapTGA *LoadTGA( const char* pImageName ); + + + +// ---------------------------------------------------------------------- // +// The voice manager for the client. +// ---------------------------------------------------------------------- // +CVoiceStatus g_VoiceStatus; + +CVoiceStatus* GetClientVoiceMgr() +{ + return &g_VoiceStatus; +} + + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +static CVoiceStatus *g_pInternalVoiceStatus = NULL; + +int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); + + return 1; +} + +int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); + + return 1; +} + + +int g_BannedPlayerPrintCount; +void ForEachBannedPlayer(char id[16]) +{ + char str[256]; + sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", + g_BannedPlayerPrintCount++, + id[0], id[1], id[2], id[3], + id[4], id[5], id[6], id[7], + id[8], id[9], id[10], id[11], + id[12], id[13], id[14], id[15] + ); + strupr(str); + gEngfuncs.pfnConsolePrint(str); +} + + +void ShowBannedCallback() +{ + if(g_pInternalVoiceStatus) + { + g_BannedPlayerPrintCount = 0; + gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); + g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); + gEngfuncs.pfnConsolePrint("------------------------------\n"); + } +} + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +CVoiceStatus::CVoiceStatus() +{ + m_bBanMgrInitialized = false; + m_LastUpdateServerState = 0; + + m_pSpeakerLabelIcon = NULL; + m_pScoreboardNeverSpoken = NULL; + m_pScoreboardNotSpeaking = NULL; + m_pScoreboardSpeaking = NULL; + m_pScoreboardSpeaking2 = NULL; + m_pScoreboardSquelch = NULL; + m_pScoreboardBanned = NULL; + + m_pLocalBitmap = NULL; + m_pAckBitmap = NULL; + + m_bTalking = m_bServerAcked = false; + + memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); + + m_bServerModEnable = -1; + + m_pchGameDir = NULL; +} + + +CVoiceStatus::~CVoiceStatus() +{ + g_pInternalVoiceStatus = NULL; + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + delete m_Labels[i].m_pLabel; + m_Labels[i].m_pLabel = NULL; + + delete m_Labels[i].m_pIcon; + m_Labels[i].m_pIcon = NULL; + + delete m_Labels[i].m_pBackground; + m_Labels[i].m_pBackground = NULL; + } + + delete m_pLocalLabel; + m_pLocalLabel = NULL; + + FreeBitmaps(); + + if(m_pchGameDir) + { + if(m_bBanMgrInitialized) + { + m_BanMgr.SaveState(m_pchGameDir); + } + + free(m_pchGameDir); + } +} + + +int CVoiceStatus::Init( + IVoiceStatusHelper *pHelper, + Panel **pParentPanel) +{ + // Setup the voice_modenable cvar. + gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); + + gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); + + gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); + + if(gEngfuncs.pfnGetGameDirectory()) + { + m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); + m_bBanMgrInitialized = true; + } + + assert(!g_pInternalVoiceStatus); + g_pInternalVoiceStatus = this; + + m_BlinkTimer = 0; + m_VoiceHeadModel = NULL; + memset(m_Labels, 0, sizeof(m_Labels)); + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + pLabel->m_pBackground = new Label(""); + + if(pLabel->m_pLabel = new Label("")) + { + pLabel->m_pLabel->setVisible( true ); + pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); + pLabel->m_pLabel->setTextAlignment( Label::a_east ); + pLabel->m_pLabel->setContentAlignment( Label::a_east ); + pLabel->m_pLabel->setParent( pLabel->m_pBackground ); + } + + if( pLabel->m_pIcon = new ImagePanel( NULL ) ) + { + pLabel->m_pIcon->setVisible( true ); + pLabel->m_pIcon->setParent( pLabel->m_pBackground ); + } + + pLabel->m_clientindex = -1; + } + + m_pLocalLabel = new ImagePanel(NULL); + + m_bInSquelchMode = false; + + m_pHelper = pHelper; + m_pParentPanel = pParentPanel; + gHUD.AddHudElem(this); + m_iFlags = HUD_ACTIVE; + HOOK_MESSAGE(VoiceMask); + HOOK_MESSAGE(ReqState); + + // Cache the game directory for use when we shut down + const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); + m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); + strcpy(m_pchGameDir, pchGameDirT); + + return 1; +} + + +int CVoiceStatus::VidInit() +{ + FreeBitmaps(); + + + if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) + { + m_pLocalBitmap->setColor(Color(255,255,255,135)); + } + + if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) + { + m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. + } + + m_pLocalLabel->setImage( m_pLocalBitmap ); + m_pLocalLabel->setVisible( false ); + + + if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) + m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. + + if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) + m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) + m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) + m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) + m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) + m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) + m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + // Figure out the voice head model height. + m_VoiceHeadModelHeight = 45; + char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); + if(pFile) + { + char token[4096]; + gEngfuncs.COM_ParseFile(pFile, token); + if(token[0] >= '0' && token[0] <= '9') + { + m_VoiceHeadModelHeight = (float)atof(token); + } + + gEngfuncs.COM_FreeFile(pFile); + } + + m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); + return TRUE; +} + + +void CVoiceStatus::Frame(double frametime) +{ + // check server banned players once per second + if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) + { + UpdateServerState(false); + } + + m_BlinkTimer += frametime; + + // Update speaker labels. + if( m_pHelper->CanShowSpeakerLabels() ) + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); + } + else + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( false ); + } + + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + UpdateBanButton(i); +} + + +void CVoiceStatus::CreateEntities() +{ + if(!m_VoiceHeadModel) + return; + + cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); + + int iOutModel = 0; + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if(!m_VoicePlayers[i]) + continue; + + cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); + + // Don't show an icon if the player is not in our PVS. + if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) + continue; + + // Don't show an icon for dead or spectating players (ie: invisible entities). + if(pClient->curstate.effects & EF_NODRAW) + continue; + + // Don't show an icon for the local player unless we're in thirdperson mode. + if(pClient == localPlayer && !cam_thirdperson) + continue; + + cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; + ++iOutModel; + + memset(pEnt, 0, sizeof(*pEnt)); + + pEnt->curstate.rendermode = kRenderTransAdd; + pEnt->curstate.renderamt = 255; + pEnt->baseline.renderamt = 255; + pEnt->curstate.renderfx = kRenderFxNoDissipation; + pEnt->curstate.framerate = 1; + pEnt->curstate.frame = 0; + pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); + pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; + pEnt->curstate.scale = 0.5f; + + pEnt->origin[0] = pEnt->origin[1] = 0; + pEnt->origin[2] = 45; + + VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); + + // Tell the engine. + gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); + } +} + + +void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) +{ + if(!*m_pParentPanel) + return; + + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + char msg[256]; + _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); + gEngfuncs.pfnConsolePrint( msg ); + } + + // Is it the local player talking? + if( entindex == -1 ) + { + m_bTalking = !!bTalking; + if( bTalking ) + { + // Enable voice for them automatically if they try to talk. + gEngfuncs.pfnClientCmd( "voice_modenable 1" ); + } + } + else if( entindex == -2 ) + { + m_bServerAcked = !!bTalking; + } + else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) + { + int iClient = entindex - 1; + if(iClient < 0) + return; + + CVoiceLabel *pLabel = FindVoiceLabel(iClient); + if(bTalking) + { + m_VoicePlayers[iClient] = true; + m_VoiceEnabledPlayers[iClient] = true; + + // If we don't have a label for this guy yet, then create one. + if(!pLabel) + { + if(pLabel = GetFreeVoiceLabel()) + { + // Get the name from the engine. + hud_player_info_t info; + memset(&info, 0, sizeof(info)); + GetPlayerInfo(entindex, &info); + + char paddedName[512]; + _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); + + int color[3]; + m_pHelper->GetPlayerTextColor( entindex, color ); + + if( pLabel->m_pBackground ) + { + pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); + pLabel->m_pBackground->setParent( *m_pParentPanel ); + pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); + } + + if( pLabel->m_pLabel ) + { + pLabel->m_pLabel->setFgColor( 255, 255, 255, 0 ); + pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); + pLabel->m_pLabel->setText( paddedName ); + } + + pLabel->m_clientindex = iClient; + } + } + } + else + { + m_VoicePlayers[iClient] = false; + + // If we have a label for this guy, kill it. + if(pLabel) + { + pLabel->m_pBackground->setVisible(false); + pLabel->m_clientindex = -1; + } + } + } + + RepositionLabels(); +} + + +void CVoiceStatus::UpdateServerState(bool bForce) +{ + // Can't do anything when we're not in a level. + char const *pLevelName = gEngfuncs.pfnGetLevelName(); + if( pLevelName[0] == 0 ) + { + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); + } + + return; + } + + int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); + if(bForce || m_bServerModEnable != bCVarModEnable) + { + m_bServerModEnable = bCVarModEnable; + + char str[256]; + _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); + ServerCmd(str); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + } + + char str[2048]; + sprintf(str, "vban"); + bool bChange = false; + + for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + unsigned long serverBanMask = 0; + unsigned long banMask = 0; + for(unsigned long i=0; i < 32; i++) + { + char playerID[16]; + if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) + continue; + + if(m_BanMgr.GetPlayerBan(playerID)) + banMask |= 1 << i; + + if(m_ServerBannedPlayers[dw*32 + i]) + serverBanMask |= 1 << i; + } + + if(serverBanMask != banMask) + bChange = true; + + // Ok, the server needs to be updated. + char numStr[512]; + sprintf(numStr, " %x", banMask); + strcat(str, numStr); + } + + if(bChange || bForce) + { + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + + gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. + } + else + { + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); + } + } + + m_LastUpdateServerState = gEngfuncs.GetClientTime(); +} + +void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) +{ + m_pBanButtons[iPlayer-1] = pLabel; + UpdateBanButton(iPlayer-1); +} + +void CVoiceStatus::UpdateBanButton(int iClient) +{ + Label *pPanel = m_pBanButtons[iClient]; + + if (!pPanel) + return; + + char playerID[16]; + extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); + if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) + return; + + // Figure out if it's blinking or not. + bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; + bool bTalking = !!m_VoicePlayers[iClient]; + bool bBanned = m_BanMgr.GetPlayerBan(playerID); + bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; + + // Get the appropriate image to display on the panel. + if (bBanned) + { + pPanel->setImage(m_pScoreboardBanned); + } + else if (bTalking) + { + if (bBlink) + { + pPanel->setImage(m_pScoreboardSpeaking2); + } + else + { + pPanel->setImage(m_pScoreboardSpeaking); + } + pPanel->setFgColor(255, 170, 0, 1); + } + else if (bNeverSpoken) + { + pPanel->setImage(m_pScoreboardNeverSpoken); + pPanel->setFgColor(100, 100, 100, 1); + } + else + { + pPanel->setImage(m_pScoreboardNotSpeaking); + } +} + + +void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + unsigned long dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); + m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); + + sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + + sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + } + } + + m_bServerModEnable = READ_BYTE(); +} + +void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) +{ + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); + } + + UpdateServerState(true); +} + +void CVoiceStatus::StartSquelchMode() +{ + if(m_bInSquelchMode) + return; + + m_bInSquelchMode = true; + m_pHelper->UpdateCursorState(); +} + +void CVoiceStatus::StopSquelchMode() +{ + m_bInSquelchMode = false; + m_pHelper->UpdateCursorState(); +} + +bool CVoiceStatus::IsInSquelchMode() +{ + return m_bInSquelchMode; +} + +CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) +{ + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + if(m_Labels[i].m_clientindex == clientindex) + return &m_Labels[i]; + } + + return NULL; +} + + +CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() +{ + return FindVoiceLabel(-1); +} + + +void CVoiceStatus::RepositionLabels() +{ + // find starting position to draw from, along right-hand side of screen + int y = ScreenHeight / 2; + + int iconWide = 8, iconTall = 8; + if( m_pSpeakerLabelIcon ) + { + m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); + } + + // Reposition active labels. + for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) + { + if( pLabel->m_pBackground ) + pLabel->m_pBackground->setVisible( false ); + + continue; + } + + int textWide, textTall; + pLabel->m_pLabel->getContentSize( textWide, textTall ); + + // Don't let it stretch too far across their screen. + if( textWide > (ScreenWidth*2)/3 ) + textWide = (ScreenWidth*2)/3; + + // Setup the background label to fit everything in. + int border = 2; + int bgWide = textWide + iconWide + border*3; + int bgTall = max( textTall, iconTall ) + border*2; + pLabel->m_pBackground->setBounds( ScreenWidth - bgWide - 8, y, bgWide, bgTall ); + + // Put the text at the left. + pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); + + // Put the icon at the right. + int iconLeft = border + textWide + border; + int iconTop = (bgTall - iconTall) / 2; + if( pLabel->m_pIcon ) + { + pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); + pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); + } + + y += bgTall + 2; + } + + if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) + { + m_pLocalLabel->setParent(*m_pParentPanel); + m_pLocalLabel->setVisible( true ); + + if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + m_pLocalLabel->setImage( m_pAckBitmap ); + else + m_pLocalLabel->setImage( m_pLocalBitmap ); + + int sizeX, sizeY; + m_pLocalBitmap->getSize(sizeX, sizeY); + + int local_xPos = ScreenWidth - sizeX - 10; + int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; + + m_pLocalLabel->setPos( local_xPos, local_yPos ); + } + else + { + m_pLocalLabel->setVisible( false ); + } +} + + +void CVoiceStatus::FreeBitmaps() +{ + // Delete all the images we have loaded. + delete m_pLocalBitmap; + m_pLocalBitmap = NULL; + + delete m_pAckBitmap; + m_pAckBitmap = NULL; + + delete m_pSpeakerLabelIcon; + m_pSpeakerLabelIcon = NULL; + + delete m_pScoreboardNeverSpoken; + m_pScoreboardNeverSpoken = NULL; + + delete m_pScoreboardNotSpeaking; + m_pScoreboardNotSpeaking = NULL; + + delete m_pScoreboardSpeaking; + m_pScoreboardSpeaking = NULL; + + delete m_pScoreboardSpeaking2; + m_pScoreboardSpeaking2 = NULL; + + delete m_pScoreboardSquelch; + m_pScoreboardSquelch = NULL; + + delete m_pScoreboardBanned; + m_pScoreboardBanned = NULL; + + // Clear references to the images in panels. + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if (m_pBanButtons[i]) + { + m_pBanButtons[i]->setImage(NULL); + } + } + + if(m_pLocalLabel) + m_pLocalLabel->setImage(NULL); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the target client has been banned +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerBlocked(int iPlayer) +{ + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return false; + + return m_BanMgr.GetPlayerBan(playerID); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerAudible(int iPlayer) +{ + return !!m_AudiblePlayers[iPlayer-1]; +} + +//----------------------------------------------------------------------------- +// Purpose: blocks/unblocks the target client from being heard +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) +{ + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); + } + + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return; + + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); + } + + // Squelch or (try to) unsquelch this player. + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); + gEngfuncs.pfnConsolePrint(str); + } + + m_BanMgr.SetPlayerBan( playerID, blocked ); + UpdateServerState(false); +} diff --git a/game_shared/voice_status.h b/game_shared/voice_status.h new file mode 100644 index 00000000..7825083a --- /dev/null +++ b/game_shared/voice_status.h @@ -0,0 +1,228 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_STATUS_H +#define VOICE_STATUS_H +#pragma once + + +#include "VGUI_Label.h" +#include "VGUI_LineBorder.h" +#include "VGUI_ImagePanel.h" +#include "VGUI_BitmapTGA.h" +#include "VGUI_InputSignal.h" +#include "VGUI_Button.h" +#include "voice_common.h" +#include "cl_entity.h" +#include "voice_banmgr.h" +#include "vgui_checkbutton2.h" +#include "vgui_defaultinputsignal.h" + + +class CVoiceStatus; + + +class CVoiceLabel +{ +public: + vgui::Label *m_pLabel; + vgui::Label *m_pBackground; + vgui::ImagePanel *m_pIcon; // Voice icon next to player name. + int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. +}; + + +// This is provided by each mod to access data that may not be the same across mods. +class IVoiceStatusHelper +{ +public: + virtual ~IVoiceStatusHelper() {} + + // Get RGB color for voice status text about this player. + virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; + + // Force it to update the cursor state. + virtual void UpdateCursorState() = 0; + + // Return the height above the bottom that the voice ack icons should be drawn at. + virtual int GetAckIconHeight() = 0; + + // Return true if the voice manager is allowed to show speaker labels + // (mods usually return false when the scoreboard is up). + virtual bool CanShowSpeakerLabels() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Holds a color for the shared image +//----------------------------------------------------------------------------- +class VoiceImagePanel : public vgui::ImagePanel +{ + virtual void paintBackground() + { + if (_image!=null) + { + vgui::Color col; + getFgColor(col); + _image->setColor(col); + _image->doPaint(this); + } + } +}; + + +class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal +{ +public: + CVoiceStatus(); + virtual ~CVoiceStatus(); + +// CHudBase overrides. +public: + + // Initialize the cl_dll's voice manager. + virtual int Init( + IVoiceStatusHelper *m_pHelper, + vgui::Panel **pParentPanel); + + // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. + virtual int VidInit(); + + +public: + + // Call from HUD_Frame each frame. + void Frame(double frametime); + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). + // entindex is -2 to represent the local client's voice being acked by the server. + void UpdateSpeakerStatus(int entindex, qboolean bTalking); + + // sets the correct image in the label for the player + void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); + + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void CreateEntities(); + + // Called when the server registers a change to who this client can hear. + void HandleVoiceMaskMsg(int iSize, void *pbuf); + + // The server sends this message initially to tell the client to send their state. + void HandleReqStateMsg(int iSize, void *pbuf); + + +// Squelch mode functions. +public: + + // When you enter squelch mode, pass in + void StartSquelchMode(); + void StopSquelchMode(); + bool IsInSquelchMode(); + + // returns true if the target client has been banned + // playerIndex is of range 1..maxplayers + bool IsPlayerBlocked(int iPlayerIndex); + + // returns false if the player can't hear the other client due to game rules (eg. the other team) + bool IsPlayerAudible(int iPlayerIndex); + + // blocks the target client from being heard + void SetPlayerBlockedState(int iPlayerIndex, bool blocked); + +public: + + CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. + // Returns NULL if none. + // entindex can be -1 if you want a currently-unused voice label. + CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. + + void RepositionLabels(); + + void FreeBitmaps(); + + void UpdateServerState(bool bForce); + + // Update the button artwork to reflect the client's current state. + void UpdateBanButton(int iClient); + + +public: + + enum {MAX_VOICE_SPEAKERS=7}; + + float m_LastUpdateServerState; // Last time we called this function. + int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. + + vgui::Panel **m_pParentPanel; + CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. + + // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on + // and is totally separate from the ban list. Indexed by client index. + CPlayerBitVec m_AudiblePlayers; + + // Players who have spoken at least once in the game so far + CPlayerBitVec m_VoiceEnabledPlayers; + + // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). + // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. + CPlayerBitVec m_ServerBannedPlayers; + + cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just + // a place for it to put data in during CreateEntities. + + IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. + + + // Scoreboard icons. + double m_BlinkTimer; // Blink scoreboard icons.. + vgui::BitmapTGA *m_pScoreboardNeverSpoken; + vgui::BitmapTGA *m_pScoreboardNotSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking2; + vgui::BitmapTGA *m_pScoreboardSquelch; + vgui::BitmapTGA *m_pScoreboardBanned; + + vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. + + // Squelch mode stuff. + bool m_bInSquelchMode; + + HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). + float m_VoiceHeadModelHeight; // Height above their head to place the model. + + vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. + + // Lower-right icons telling when the local player is talking.. + vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. + vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. + vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. + + bool m_bTalking; // Set to true when the client thinks it's talking. + bool m_bServerAcked; // Set to true when the server knows the client is talking. + +public: + + CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. + +public: + + bool m_bBanMgrInitialized; + + // Labels telling who is speaking. + CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; + + // Cache the game directory for use when we shut down + char * m_pchGameDir; +}; + + +// Get the (global) voice manager. +CVoiceStatus* GetClientVoiceMgr(); + + +#endif // VOICE_STATUS_H diff --git a/game_shared/voice_vgui_tweakdlg.cpp b/game_shared/voice_vgui_tweakdlg.cpp new file mode 100644 index 00000000..b5cde708 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.cpp @@ -0,0 +1,289 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/hud.h" +#include "../cl_dll/cl_util.h" +#include "../cl_dll/vgui_teamfortressviewport.h" + + +#include "vgui_actionsignal.h" +#include "voice_vgui_tweakdlg.h" +#include "voice_vgui_tweakdlg.h" +#include "vgui_panel.h" +#include "vgui_scrollbar.h" +#include "vgui_slider.h" +#include "ivoicetweak.h" +#include "vgui_button.h" +#include "vgui_checkbutton2.h" +#include "vgui_helpers.h" + + +#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. +#define VOICETWEAK_TRANSPARENCY 150 + + +class TweakScroller +{ +public: + TweakScroller(); + void Init(Panel *pParent, char *pText, int yPos); + + // Get/set value. Values are 0-1. + float GetValue(); + void SetValue(float val); + +public: + Label m_Label; + ScrollBar m_Scroll; + Slider m_Slider; +}; + + +class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler +{ +typedef CMenuPanel BaseClass; + +public: + CVoiceVGUITweakDlg(); + ~CVoiceVGUITweakDlg(); + +// CMenuPanel overrides. +public: + virtual void Open(); + virtual void Close(); + + +// ICheckButton2Handler overrides. +public: + + virtual void StateChanged(CCheckButton2 *pButton); + + + +// Panel overrides. +public: + virtual void paintBackground(); + + +private: + + int m_DlgWidth; + int m_DlgHeight; + + Label m_Label; + + IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. + + TweakScroller m_MicVolume; + TweakScroller m_SpeakerVolume; + + CCheckButton2 m_VoiceModEnable; + + Button m_Button_OK; +}; + + + +bool g_bTweakDlgOpen = false; + +bool IsTweakDlgOpen() +{ + return g_bTweakDlgOpen; +} + + + +// ------------------------------------------------------------------------ // +// Global functions. +// ------------------------------------------------------------------------ // + +static CVoiceVGUITweakDlg g_VoiceTweakDlg; +CMenuPanel* GetVoiceTweakDlg() +{ + return &g_VoiceTweakDlg; +} + + +class CVoiceTweakOKButton : public ActionSignal +{ +public: + virtual void actionPerformed(Panel *pPanel) + { + gViewPort->HideVGUIMenu(); + } +}; +CVoiceTweakOKButton g_OKButtonSignal; + + + +// ------------------------------------------------------------------------ // +// TweakScroller +// ------------------------------------------------------------------------ // + +TweakScroller::TweakScroller() : + m_Label(""), + m_Scroll(0,0,0,0,false), + m_Slider(0,0,10,10,false) +{ +} + + +void TweakScroller::Init(Panel *pParent, char *pText, int yPos) +{ + int parentWidth, parentHeight; + pParent->getSize(parentWidth, parentHeight); + + // Setup the volume scroll bar. + m_Label.setParent(pParent); + m_Label.setFont(Scheme::sf_primary1); + m_Label.setContentAlignment(vgui::Label::a_northwest); + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setPos(ITEM_BORDER, yPos); + m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); + m_Label.setText(pText); + m_Label.setVisible(true); + + m_Slider.setRangeWindow(10); + m_Slider.setRangeWindowEnabled(true); + + m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); + m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); + m_Scroll.setSlider(&m_Slider); + m_Scroll.setParent(pParent); + m_Scroll.setRange(0, 100); + m_Scroll.setFgColor(255,255,255,0); + m_Scroll.setBgColor(255,255,255,0); +} + + +float TweakScroller::GetValue() +{ + return m_Scroll.getValue() / 100.0f; +} + + +void TweakScroller::SetValue(float val) +{ + m_Scroll.setValue((int)(val * 100.0f)); +} + + +// ------------------------------------------------------------------------ // +// CVoiceVGUITweakDlg implementation. +// ------------------------------------------------------------------------ // + +CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() + : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), + m_Button_OK("",0,0), + m_Label("") +{ + m_pVoiceTweak = NULL; + m_Button_OK.addActionSignal(&g_OKButtonSignal); + m_Label.setBgColor(255,255,255,200); +} + + +CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() +{ +} + + +void CVoiceVGUITweakDlg::Open() +{ + if(g_bTweakDlgOpen) + return; + + g_bTweakDlgOpen = true; + + m_DlgWidth = ScreenWidth; + m_DlgHeight = ScreenHeight; + + m_pVoiceTweak = gEngfuncs.pVoiceTweak; + + // Tell the engine to start voice tweak mode (pipe voice output right to speakers). + m_pVoiceTweak->StartVoiceTweakMode(); + + // Set our size. + setPos((ScreenWidth - m_DlgWidth) / 2, (ScreenHeight - m_DlgHeight) / 2); + setSize(m_DlgWidth, m_DlgHeight); + + int curY = ITEM_BORDER; + m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); + m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); + curY = PanelBottom(&m_MicVolume.m_Label); + + m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); + m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); + curY = PanelBottom(&m_SpeakerVolume.m_Label); + + m_VoiceModEnable.setParent(this); + m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); + m_VoiceModEnable.SetText("Enable Voice In This Mod"); + m_VoiceModEnable.setPos(ITEM_BORDER, curY); + m_VoiceModEnable.SetCheckboxLeft(false); + m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); + m_VoiceModEnable.SetHandler(this); + + // Setup the OK button. + int buttonWidth, buttonHeight; + m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); + m_Button_OK.getSize(buttonWidth, buttonHeight); + m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); + m_Button_OK.setParent(this); + + // Put the label on the top. + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); + int labelWidth, labelHeight; + m_Label.getSize(labelWidth, labelHeight); + m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); + m_Label.setParent(this); + + BaseClass::Open(); +} + + +void CVoiceVGUITweakDlg::Close() +{ + m_pVoiceTweak->EndVoiceTweakMode(); + g_bTweakDlgOpen = false; + + BaseClass::Close(); +} + + +void CVoiceVGUITweakDlg::paintBackground() +{ + BaseClass::paintBackground(); + + // Draw our border. + int w,h; + getSize(w,h); + + drawSetColor(128,128,128,1); + drawOutlinedRect(0, 0, w, h); + + float volume = m_MicVolume.GetValue(); + m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); + + m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); +} + + +void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) +{ + if(pButton == &m_VoiceModEnable) + { + if(pButton->IsChecked()) + gEngfuncs.pfnClientCmd("voice_modenable 1"); + else + gEngfuncs.pfnClientCmd("voice_modenable 0"); + } +} + diff --git a/game_shared/voice_vgui_tweakdlg.h b/game_shared/voice_vgui_tweakdlg.h new file mode 100644 index 00000000..857ffd25 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.h @@ -0,0 +1,25 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_VGUI_TWEAKDLG_H +#define VOICE_VGUI_TWEAKDLG_H +#ifdef _WIN32 +#pragma once +#endif + + +class CMenuPanel; + + +// Returns true if the tweak dialog is currently up. +bool IsTweakDlgOpen(); + +// Returns a global instance of the tweak dialog. +CMenuPanel* GetVoiceTweakDlg(); + + +#endif // VOICE_VGUI_TWEAKDLG_H diff --git a/gnu.txt b/gnu.txt new file mode 100644 index 00000000..f718b3eb --- /dev/null +++ b/gnu.txt @@ -0,0 +1,621 @@ + 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 \ No newline at end of file diff --git a/make_sdk.bat b/make_sdk.bat new file mode 100644 index 00000000..96602839 --- /dev/null +++ b/make_sdk.bat @@ -0,0 +1,62 @@ +@echo off +color 5A +echo XashXT Group 2010 (C) +echo Create Xash3D SDK +echo. + +if not exist D:\Xash3D\src_main\xash_sdk/ mkdir D:\Xash3D\src_main\xash_sdk\ +if not exist D:\Xash3D\src_main\xash_sdk\engine/ mkdir D:\Xash3D\src_main\xash_sdk\engine\ +if not exist D:\Xash3D\src_main\xash_sdk\common/ mkdir D:\Xash3D\src_main\xash_sdk\common\ +if not exist D:\Xash3D\src_main\xash_sdk\mainui/ mkdir D:\Xash3D\src_main\xash_sdk\mainui\ +if not exist D:\Xash3D\src_main\xash_sdk\mainui\legacy/ mkdir D:\Xash3D\src_main\xash_sdk\mainui\legacy +if not exist D:\Xash3D\src_main\xash_sdk\utils/ mkdir D:\Xash3D\src_main\xash_sdk\utils\ +if not exist D:\Xash3D\src_main\xash_sdk\utils\makefont/ mkdir D:\Xash3D\src_main\xash_sdk\utils\makefont +if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui +if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui\include/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui\include +if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui\lib/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui\lib +if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui\lib\win32_vc6/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui\lib\win32_vc6 +if not exist D:\Xash3D\src_main\xash_sdk\game_launch/ mkdir D:\Xash3D\src_main\xash_sdk\game_launch\ +if not exist D:\Xash3D\src_main\xash_sdk\cl_dll/ mkdir D:\Xash3D\src_main\xash_sdk\cl_dll\ +if not exist D:\Xash3D\src_main\xash_sdkcl_dll\hl/ mkdir D:\Xash3D\src_main\xash_sdk\cl_dll\hl\ +if not exist D:\Xash3D\src_main\xash_sdk\dlls/ mkdir D:\Xash3D\src_main\xash_sdk\dlls\ +if not exist D:\Xash3D\src_main\xash_sdk\dlls\wpn_shared/ mkdir D:\Xash3D\src_main\xash_sdk\dlls\wpn_shared\ +if not exist D:\Xash3D\src_main\xash_sdk\game_shared/ mkdir D:\Xash3D\src_main\xash_sdk\game_shared\ +if not exist D:\Xash3D\src_main\xash_sdk\pm_shared/ mkdir D:\Xash3D\src_main\xash_sdk\pm_shared\ +@copy /Y engine\*.h xash_sdk\engine\*.h +@copy /Y game_launch\*.* xash_sdk\game_launch\*.* +@copy /Y mainui\*.* xash_sdk\mainui\*.* +@copy /Y mainui\legacy\*.* xash_sdk\mainui\legacy\*.* +@copy /Y common\*.* xash_sdk\common\*.* +@copy /Y cl_dll\*.* xash_sdk\cl_dll\*.* +@copy /Y cl_dll\hl\*.* xash_sdk\cl_dll\hl\*.* +@copy /Y dlls\*.* xash_sdk\dlls\*.* +@copy /Y dlls\wpn_shared\*.* xash_sdk\dlls\wpn_shared\*.* +@copy /Y utils\makefont\*.* xash_sdk\utils\makefont\*.* +@copy /Y utils\vgui\include\*.* xash_sdk\utils\vgui\include\*.* +@copy /Y utils\vgui\lib\win32_vc6\*.* xash_sdk\utils\vgui\lib\win32_vc6\*.* +@copy /Y game_shared\*.* xash_sdk\game_shared\*.* +@copy /Y pm_shared\*.* xash_sdk\pm_shared\*.* +@copy /Y xash_sdk.dsw xash_sdk\xash_sdk.dsw +echo Prepare OK! +echo Please wait: creating SDK in progress +C:\Progra~1\WinRar\rar a xash_sdk -dh -k -r -s -df -m5 @xash_sdk.lst >>makesdk.log +if errorlevel 1 goto error +if errorlevel 0 goto ok +:ok +cls +echo SDK was sucessfully created +echo and stored in RAR-chive "xash_sdk" +echo Press any key for exit. :-) +if exist makesdk.log del /f /q makesdk.log +exit +:error +echo ****************************** +echo ***********Error!************* +echo ****************************** +echo *See makesdk.log for details** +echo ****************************** +echo ****************************** +echo. +echo press any key for exit :-( +pause>nul +exit \ No newline at end of file diff --git a/pm_shared/pm_debug.c b/pm_shared/pm_debug.c new file mode 100644 index 00000000..d9d097db --- /dev/null +++ b/pm_shared/pm_debug.c @@ -0,0 +1,320 @@ +/*** +* +* 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 + +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) + +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/pm_shared/pm_debug.h b/pm_shared/pm_debug.h new file mode 100644 index 00000000..19dd5ea5 --- /dev/null +++ b/pm_shared/pm_debug.h @@ -0,0 +1,23 @@ +/*** +* +* 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 + +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//PM_DEBUG_H \ No newline at end of file diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h new file mode 100644 index 00000000..2a2ee680 --- /dev/null +++ b/pm_shared/pm_defs.h @@ -0,0 +1,221 @@ +/*** +* +* 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_DEFS_H +#define PM_DEFS_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_CUSTOM_IGNORE 0x00000010 // Ignore entities with SOLID_CUSTOM mode + +// Values for flags parameter of PM_TraceLine +#define PM_TRACELINE_PHYSENTSONLY 0 +#define PM_TRACELINE_ANYVISIBLE 1 + +#include "pm_info.h" + +// PM_PlayerTrace results. +#include "pmtrace.h" + + +#include "usercmd.h" + +// 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; // also contains pev->scale when "sv_allow_studio_scaling" is "1" + 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 + + // 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 ); + long (*RandomLong)( long lLow, long 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 )); + struct msurface_s *(*PM_TraceSurface)( int ground, float *vstart, float *vend ); +} playermove_t; +#endif//PM_DEFS_H \ No newline at end of file diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h new file mode 100644 index 00000000..e2f434f6 --- /dev/null +++ b/pm_shared/pm_info.h @@ -0,0 +1,20 @@ +/*** +* +* 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_INFO_H +#define PM_INFO_H + +#define MAX_PHYSINFO_STRING 256 + +#endif//PM_INFO_H \ No newline at end of file diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h new file mode 100644 index 00000000..47d875e8 --- /dev/null +++ b/pm_shared/pm_materials.h @@ -0,0 +1,32 @@ +/*** +* +* 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_MATERIALS_H +#define PM_MATERIALS_H + +#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' + +#endif//PM_MATERIALS_H \ No newline at end of file diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c new file mode 100644 index 00000000..a5d78dc1 --- /dev/null +++ b/pm_shared/pm_math.c @@ -0,0 +1,422 @@ +/*** +* +* 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 + +#pragma warning(disable : 4244) + +vec3_t vec3_origin = {0,0,0}; +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; + } +} + + +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; +} + +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; +} + + +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]; +} + + +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]; +} + +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]; +} + +double sqrt(double x); + +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; +} + +float Distance(const vec3_t v1, const vec3_t v2) +{ + vec3_t d; + VectorSubtract(v2,v1,d); + return Length(d); +} + +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; +} + + +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 ); +} + + +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; +} diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h new file mode 100644 index 00000000..64d9baeb --- /dev/null +++ b/pm_shared/pm_movevars.h @@ -0,0 +1,54 @@ +//========= 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; // + int features; // engine features that shared across network + int fog_settings; // Global fog settings (packed color+density) + float wateralpha; // World water alpha 1.0 - solid 0.0 - transparent + float skydir_x; // skybox rotate direction + float skydir_y; // + float skydir_z; // + float skyangle; // skybox rotate angle +}; + +extern movevars_t movevars; + +#endif \ No newline at end of file diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c new file mode 100644 index 00000000..2853995d --- /dev/null +++ b/pm_shared/pm_shared.c @@ -0,0 +1,3331 @@ +/*** +* +* 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; + float vJumpOrigin[3]; + float vJumpAngles[3]; +#endif + +static int pm_shared_initialized = 0; + +#pragma warning( disable : 4305 ) + +typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; + +playermove_t *pmove = NULL; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +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 hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +// 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 + +// double to float warning +#pragma warning(disable : 4244) +#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 clip; + 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 + clip = 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. + clip = 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 ); + + 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" + + int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; + int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; + + 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 *= 0.333; + pmove->cmd.sidemove *= 0.333; + pmove->cmd.upmove *= 0.333; + } + + 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; + + 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; + + AngleVectors( pmove->angles, vpn, v_right, NULL ); + if ( pmove->cmd.buttons & IN_BACK ) + forward -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_FORWARD ) + forward += MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVELEFT ) + right -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVERIGHT ) + right += MAX_CLIMB_SPEED; + + 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; + } + } + + // 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 ); + } + + // 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; + +// pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground ); + + 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/pm_shared/pm_shared.h b/pm_shared/pm_shared.h new file mode 100644 index 00000000..96a8493a --- /dev/null +++ b/pm_shared/pm_shared.h @@ -0,0 +1,32 @@ +/*** +* +* 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_SHARED_H +#define PM_SHARED_H + +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//PM_SHARED_H \ No newline at end of file diff --git a/release.bat b/release.bat new file mode 100644 index 00000000..dae2d16c --- /dev/null +++ b/release.bat @@ -0,0 +1,42 @@ +@echo off + +set MSDEV=BuildConsole +set CONFIG=/ShowTime /ShowAgent /nologo /cfg= +set MSDEV=msdev +set CONFIG=/make +set build_type=release +set BUILD_ERROR= +call vcvars32 + +%MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Release" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +%MSDEV% mainui/mainui.dsp %CONFIG%"mainui - Win32 Release" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +if "%BUILD_ERROR%"=="" goto build_ok + +echo ********************* +echo ********************* +echo *** Build Errors! *** +echo ********************* +echo ********************* +echo press any key to exit +echo ********************* +pause>nul +goto done + + +@rem +@rem Successful build +@rem +:build_ok + +rem //delete log files +if exist engine\engine.plg del /f /q engine\engine.plg +if exist mainui\mainui.plg del /f /q mainui\mainui.plg + +echo +echo Build succeeded! +echo +:done \ No newline at end of file diff --git a/utils/makefont/CreateFont.bat b/utils/makefont/CreateFont.bat new file mode 100644 index 00000000..7736ad3e --- /dev/null +++ b/utils/makefont/CreateFont.bat @@ -0,0 +1,2 @@ +makefont.exe -font "Terminal" fonts.wad +pause \ No newline at end of file diff --git a/xash.dsw b/xash.dsw new file mode 100644 index 00000000..3be1a44d --- /dev/null +++ b/xash.dsw @@ -0,0 +1,65 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "hl"=".\dlls\hl.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "client"=".\cl_dll\cl_dll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "mainui"=".\mainui\mainui.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "engine"=".\engine\engine.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xash_sdk.dsw b/xash_sdk.dsw new file mode 100644 index 00000000..ad911ba0 --- /dev/null +++ b/xash_sdk.dsw @@ -0,0 +1,65 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "hl"=".\dlls\hl.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "client"=".\cl_dll\cl_dll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "mainui"=".\mainui\mainui.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "game"=".\game_launch\game.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xash_sdk.lst b/xash_sdk.lst new file mode 100644 index 00000000..a211c3b4 --- /dev/null +++ b/xash_sdk.lst @@ -0,0 +1,22 @@ +//======================================================================= +// Copyright XashXT Group 2011 © +// list with SDK directories +//======================================================================= + +// global stuff +xash_sdk\xash_sdk.dsw +xash_sdk\cl_dll\ +xash_sdk\cl_dll\hl\ +xash_sdk\common\ +xash_sdk\dlls\ +xash_sdk\game_shared\ +xash_sdk\game_launch\ +xash_sdk\engine\ +xash_sdk\pm_shared\ +xash_sdk\mainui\ +xash_dsk\mainui\legacy +xash_sdk\utils\ +xash_sdk\makefont\ +xash_sdk\utils\vgui\ +xash_sdk\utils\vgui\include\ +xash_sdk\utils\vgui\lib\win32_vc6\ \ No newline at end of file From ac857199cf7ba046cbd9856c18fce26a680b0c4c Mon Sep 17 00:00:00 2001 From: mittorn Date: Mon, 29 Feb 2016 20:04:01 +0000 Subject: [PATCH 002/227] Apply some valve's fixes --- cl_dll/util_vector.h | 4 +- common/const.h | 4 +- dlls/animation.cpp | 3 +- dlls/bmodels.cpp | 10 +- dlls/client.cpp | 11 +- dlls/combat.cpp | 5 + dlls/doors.cpp | 12 +- dlls/effects.cpp | 2 +- dlls/extdll.h | 4 +- dlls/func_break.cpp | 9 +- dlls/saverestore.h | 2 +- dlls/sound.cpp | 2 +- dlls/util.cpp | 5114 +++++++++++++++++++++-------------------- pm_shared/pm_shared.c | 2 +- 14 files changed, 2615 insertions(+), 2569 deletions(-) diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h index 0e2aaaa3..d0c4e9f0 100644 --- a/cl_dll/util_vector.h +++ b/cl_dll/util_vector.h @@ -22,8 +22,8 @@ #include "math.h" // Header file containing definition of globalvars_t and entvars_t -typedef int func_t; // -typedef int string_t; // from engine's pr_comp.h; +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 //========================================================= diff --git a/common/const.h b/common/const.h index 9701fe07..846dfe85 100644 --- a/common/const.h +++ b/common/const.h @@ -727,8 +727,8 @@ enum kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) }; -typedef int func_t; -typedef int string_t; +typedef unsigned int func_t; +typedef unsigned int string_t; typedef unsigned char byte; typedef unsigned short word; diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 246586b3..a4658726 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -319,6 +319,7 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) { studiohdr_t *pstudiohdr; + int i; pstudiohdr = (studiohdr_t *)pmodel; if (! pstudiohdr) @@ -327,7 +328,7 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); // find first controller that matches the index - for (int i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) + for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) { if (pbonecontroller->index == iController) break; diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index 0937c1f8..1386c242 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -550,13 +550,13 @@ void CFuncRotating :: RampPitchVol (int fUp) // get current angular velocity - vecCur = abs(vecAVel.x != 0 ? vecAVel.x : (vecAVel.y != 0 ? vecAVel.y : vecAVel.z)); + vecCur = fabs(vecAVel.x != 0 ? vecAVel.x : (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(vecFinal); + vecFinal = fabs(vecFinal); // calc volume and pitch as % of final vol and pitch @@ -592,9 +592,9 @@ void CFuncRotating :: SpinUp( void ) vecAVel = pev->avelocity;// cache entity's rotational velocity // if we've met or exceeded target speed, set target speed and stop thinking - if ( abs(vecAVel.x) >= abs(pev->movedir.x * pev->speed) && - abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) && - abs(vecAVel.z) >= abs(pev->movedir.z * pev->speed) ) + if ( fabs(vecAVel.x) >= fabs(pev->movedir.x * pev->speed) && + fabs(vecAVel.y) >= fabs(pev->movedir.y * pev->speed) && + fabs(vecAVel.z) >= fabs(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), diff --git a/dlls/client.cpp b/dlls/client.cpp index a78efd99..01355bbb 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -101,8 +101,9 @@ void ClientDisconnect( edict_t *pEntity ) if (g_fGameOver) return; - char text[256]; - sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) ); + char text[256] = ""; + if ( pEntity->v.netname ) + snprintf( text, sizeof(text), "- %s has left the game\n", STRING(pEntity->v.netname) ); MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); WRITE_BYTE( ENTINDEX(pEntity) ); WRITE_STRING( text ); @@ -197,6 +198,10 @@ void ClientPutInServer( edict_t *pEntity ) // Reset interpolation during first frame pPlayer->pev->effects |= EF_NOINTERP; + + pPlayer->pev->iuser1 = 0; + pPlayer->pev->iuser2 = 0; + } #include "voice_gamemgr.h" @@ -527,7 +532,7 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + snprintf( text, 256, "* %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 ); diff --git a/dlls/combat.cpp b/dlls/combat.cpp index b56b7a2f..c99330cd 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -1225,6 +1225,11 @@ BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) Vector vecLookerOrigin; Vector vecTargetOrigin; + if(!pEntity) + return FALSE; + if(!pEntity->pev) + return FALSE; + if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) return FALSE; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 303d7385..d8233d9b 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -571,7 +571,8 @@ void CBaseDoor::DoorGoUp( void ) // 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 ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + 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; @@ -652,7 +653,8 @@ void CBaseDoor::DoorHitTop( void ) void CBaseDoor::DoorGoDown( void ) { if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + 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); @@ -753,6 +755,9 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) 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(); @@ -1054,6 +1059,9 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP 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; diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 8d6e29d1..36b49c33 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -1003,7 +1003,7 @@ void CLaser::KeyValue( KeyValueData *pkvd ) } else if (FStrEq(pkvd->szKeyName, "width")) { - SetWidth( atof(pkvd->szValue) ); + SetWidth( (int)atof(pkvd->szValue) ); pkvd->fHandled = TRUE; } else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) diff --git a/dlls/extdll.h b/dlls/extdll.h index 31e48554..3ffd5833 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -64,8 +64,8 @@ typedef int BOOL; #include "math.h" // Header file containing definition of globalvars_t and entvars_t -typedef int func_t; // -typedef int string_t; // from engine's pr_comp.h; +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 diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index c15b6d9c..4a1d20d6 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -596,7 +596,7 @@ void CBreakable::Die( void ) // The more negative pev->health, the louder // the sound should be. - fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0); + fvol = RANDOM_FLOAT(0.85, 1.0) + (fabs(pev->health) / 100.0); if (fvol > 1.0) fvol = 1.0; @@ -931,14 +931,13 @@ void CPushable :: Move( CBaseEntity *pOther, int push ) return; } - // g-cont. fix pushable acceleration bug + // g-cont. fix pushable acceleration bug (reverted as it used in mods) if ( pOther->IsPlayer() ) { // Don't push unless the player is pushing forward and NOT use (pull) - if ( push && !(pevToucher->button & (IN_FORWARD|IN_MOVERIGHT|IN_MOVELEFT|IN_BACK)) ) + if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) return; - if ( !push && !(pevToucher->button & (IN_BACK)) ) return; - playerTouch = 1; + playerTouch = 1; } float factor; diff --git a/dlls/saverestore.h b/dlls/saverestore.h index c774b62d..3814aaaf 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -60,7 +60,7 @@ public: 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, const int *value, int count ); // Save a function pointer + 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 ); diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 174e5f97..b02381e5 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1537,7 +1537,7 @@ void TEXTURETYPE_Init() char buffer[512]; int i, j; byte *pMemFile; - int fileSize, filePos; + int fileSize, filePos = 0; if (fTextureTypeInit) return; diff --git a/dlls/util.cpp b/dlls/util.cpp index ab27c186..867bb3e1 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1,2543 +1,2571 @@ -/*** -* -* 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 = 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 = 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 = 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 = gpGlobals->trace_allsolid; - tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = 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 ) -{ - SET_ORIGIN(ENT(pev), 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( 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( 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 - sizeof(int *), // FIELD_FUNCTION - 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, const int *data, int count ) -{ - const char *functionName; - - functionName = NAME_FOR_FUNCTION( *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 < 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; - } - } - 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, (int *)(char *)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; -} - +/*** +* +* 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. +* +****/ +/* + +===== 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 = 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); + a = fmod( a, 360.0f ); + if( a < 0 ) a += 360; + 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 = 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 = 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 = gpGlobals->trace_allsolid; + tr.fStartSolid = gpGlobals->trace_startsolid; + tr.fInOpen = gpGlobals->trace_inopen; + tr.fInWater = 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( 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( 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( *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 < 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; + } + } + 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: + #ifdef __VFP_FP__ + memcpy(&timeData, pInputData, 4); + // Re-base time variables + timeData += time; + memcpy(pOutputData, &timeData, 4); + #else + timeData = *(float *)pInputData; + // Re-base time variables + timeData += time; + *((float *)pOutputData) = timeData; + #endif + break; + case FIELD_FLOAT: + memcpy(pOutputData, pInputData, 4); + 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: + #ifdef __VFP_FP__ + float tmp; + memcpy(&tmp, (char *)pInputData + 0, 4); + tmp += position.x; + memcpy((char *)pOutputData + 0, &tmp, 4); + memcpy(&tmp, (char *)pInputData + 4, 4); + tmp += position.y; + memcpy((char *)pOutputData + 4, &tmp, 4); + memcpy(&tmp, (char *)pInputData + 8, 4); + tmp += position.z; + memcpy((char *)pOutputData + 8, &tmp, 4); + #else + ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; + ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; + ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; + #endif + 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/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 2853995d..2216e7e9 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -186,7 +186,7 @@ void PM_InitTextureTypes() char buffer[512]; int i, j; byte *pMemFile; - int fileSize, filePos; + int fileSize, filePos = 0; static qboolean bTextureTypeInit = false; if ( bTextureTypeInit ) From 06d38e3febd54a56ac19cee6079a9604d8237820 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 1 Mar 2016 07:19:33 +0000 Subject: [PATCH 003/227] Forgot glock.cpp --- dlls/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/Android.mk b/dlls/Android.mk index 3c0f5748..81b15c1e 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -61,6 +61,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ genericmonster.cpp \ ggrenade.cpp \ globals.cpp \ + glock.cpp \ gman.cpp \ h_ai.cpp \ h_battery.cpp \ From d254f1bd0e8d49e761ca81e6ecf9db0b1cab2db7 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 1 Mar 2016 20:18:42 +0000 Subject: [PATCH 004/227] Improve client --- Android.mk | 1 + cl_dll/MOTD.cpp | 17 ++++----- cl_dll/ammo.cpp | 2 +- cl_dll/cl_util.h | 54 +++++++++++++++++----------- cl_dll/death.cpp | 12 +++---- cl_dll/hl/hl_weapons.cpp | 8 ++++- cl_dll/hud.cpp | 17 ++++----- cl_dll/hud.h | 9 ++--- cl_dll/hud_redraw.cpp | 78 ++++++++++++++++++++++++---------------- cl_dll/hud_spectator.cpp | 10 +++--- cl_dll/in_camera.cpp | 6 ++-- cl_dll/input_xash3d.cpp | 16 ++++----- cl_dll/saytext.cpp | 4 +-- cl_dll/scoreboard.cpp | 14 ++++---- cl_dll/statusbar.cpp | 4 +-- 15 files changed, 148 insertions(+), 104 deletions(-) create mode 100644 Android.mk diff --git a/Android.mk b/Android.mk new file mode 100644 index 00000000..5053e7d6 --- /dev/null +++ b/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp index 94a06eea..68030cf9 100644 --- a/cl_dll/MOTD.cpp +++ b/cl_dll/MOTD.cpp @@ -1,9 +1,9 @@ /*** * * Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* +* 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 @@ -90,8 +90,9 @@ int CHudMOTD :: Draw( float fTime ) gHUD.DrawDarkRectangle(xpos-5, ypos_r - 5, xmax - xpos+10, height + 10); while ( *ch ) { + char *next_line; int line_length = 0; // count the length of the current line - for ( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) + for ( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) line_length += gHUD.m_scrinfo.charWidths[ *next_line ]; char *top = next_line; if ( *top == '\n' ) @@ -105,7 +106,7 @@ int CHudMOTD :: Draw( float fTime ) ypos += LINE_HEIGHT; - if ( top ) // restore + if ( top ) // restore *top = '\n'; ch = next_line; if ( *ch == '\n' ) @@ -114,7 +115,7 @@ int CHudMOTD :: Draw( float fTime ) if ( ypos > (ScreenHeight - 20) ) break; // don't let it draw too low } - + return 1; } @@ -133,7 +134,7 @@ int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) if ( is_finished ) { int length = 0; - + m_iMaxLength = 0; m_iFlags |= HUD_ACTIVE; @@ -151,7 +152,7 @@ int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) } length++; } - + m_iLines++; if( length > m_iMaxLength ) { diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 48309bd3..147709bc 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -108,7 +108,7 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcCrosshair = p->rc; } else - pWeapon->hCrosshair = NULL; + pWeapon->hCrosshair = 0; p = GetSpriteList(pList, "autoaim", iRes, i); if (p) diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index e949e2c5..17e22ee6 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -24,21 +24,21 @@ #endif // Macros to hook function calls into the HUD object - -#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ - { \ - return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ - } - - -#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); -#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ - { \ - gHUD.y.UserCmd_##x( ); \ - } - + +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); + +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ + { \ + return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } + + +#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + gHUD.y.UserCmd_##x( ); \ + } + inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } @@ -82,31 +82,45 @@ inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int fl #define ClientCmd (*gEngfuncs.pfnClientCmd) #define SetCrosshair (*gEngfuncs.pfnSetCrosshair) #define AngleVectors (*gEngfuncs.pfnAngleVectors) - - +extern cvar_t *hud_textmode; +extern float g_hud_text_color[3]; +inline int DrawSetTextColor(float r, float g, float b) +{ + if( hud_textmode->value == 1 ) + g_hud_text_color[0]=r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; + else + gEngfuncs.pfnDrawSetTextColor( r, g, b ); +} // Gets the height & width of a sprite, at the specified frame inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) -{ +{ return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); } inline int DrawConsoleString( int x, int y, const char *string ) { + if( hud_textmode->value == 1 ) + return gHUD.DrawHudString( x, y, 9999, (char*)string, 255*g_hud_text_color[0], 255*g_hud_text_color[1], 255*g_hud_text_color[2]); return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); } inline void GetConsoleStringSize( const char *string, int *width, int *height ) { - gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); + if( hud_textmode->value == 1 ) + *height = 13, *width = gHUD.DrawHudStringLen(string); + else + gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); } inline int ConsoleStringLen( const char *string ) { - int _width, _height; + int _width = 0, _height = 0; + if( hud_textmode->value == 1 ) + return gHUD.DrawHudStringLen((char*)string); GetConsoleStringSize( string, &_width, &_height ); return _width; } diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index bd940f86..760b005c 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -110,7 +110,7 @@ int CHudDeathNotice :: Draw( float flTime ) rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); // Only draw if the viewport will let me - // vgui dropped out + // vgui dropped out //if ( gViewPort && gViewPort->AllowedToPrintText() ) { // Draw the death notice @@ -125,7 +125,7 @@ int CHudDeathNotice :: Draw( float flTime ) // Draw killers name if ( rgDeathNoticeList[i].KillerColor ) - gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); } @@ -145,7 +145,7 @@ int CHudDeathNotice :: Draw( float flTime ) if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) { if ( rgDeathNoticeList[i].VictimColor ) - gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); } } @@ -184,8 +184,8 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p //if (gViewPort) // gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - + gHUD.m_Scoreboard.GetAllPlayersInfo(); + // Get the Killer's name char *killer_name = g_PlayerInfoList[ killer ].name; @@ -279,7 +279,7 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p ConsolePrint( rgDeathNoticeList[i].szVictim ); } - if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + if ( *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) { ConsolePrint( " with " ); diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 820e49ff..3572bdaa 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -579,6 +579,12 @@ void CBasePlayerWeapon::PrintState( void ) COM_Log( "c:\\hl.log", "%i ", m_iClip ); } +int RandomLong( int a, int b ) +{ + return gEngfuncs.pfnRandomLong(a, b); +} + + /* ===================== HUD_InitClientWeapons @@ -615,7 +621,7 @@ void HUD_InitClientWeapons( void ) // Pass through to engine g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; - g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + g_engfuncs.pfnRandomLong = RandomLong; // Allocate a slot for the local player HUD_PrepEntity( &player , NULL ); diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 374f3b9d..36bb50ad 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -24,12 +24,13 @@ #include #include "parsemsg.h" #include "hud_servers.h" - + #include "demo.h" #include "demo_api.h" - +cvar_t *hud_textmode; +float g_hud_text_color[3]; extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); @@ -186,7 +187,7 @@ void CHud :: Init( void ) CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round - + hud_textmode = CVAR_CREATE ( "hud_textmode", "0", FCVAR_ARCHIVE ); m_iLogo = 0; m_iFOV = 0; @@ -229,8 +230,8 @@ void CHud :: Init( void ) m_AmmoSecondary.Init(); m_TextMessage.Init(); m_StatusIcons.Init(); - m_MOTD.Init(); - m_Scoreboard.Init(); + m_MOTD.Init(); + m_Scoreboard.Init(); m_Menu.Init(); @@ -258,7 +259,7 @@ CHud :: ~CHud() m_pHudList = NULL; } - + } // GetSpriteIndex() @@ -400,8 +401,8 @@ void CHud :: VidInit( void ) m_AmmoSecondary.VidInit(); m_TextMessage.VidInit(); m_StatusIcons.VidInit(); - m_Scoreboard.VidInit(); - m_MOTD.VidInit(); + m_Scoreboard.VidInit(); + m_MOTD.VidInit(); } diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 2078ea3e..e2d56f26 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -256,7 +256,7 @@ public: void GetAllPlayersInfo( void ); }; - + // //----------------------------------------------------- @@ -610,7 +610,8 @@ public: int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); int GetNumWidth(int iNumber, int iFlags); - void DrawDarkRectangle( int x, int y, int wide, int tall); + int DrawHudStringLen( char *szIt ); + void DrawDarkRectangle( int x, int y, int wide, int tall); private: // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. @@ -651,7 +652,7 @@ public: CHudStatusIcons m_StatusIcons; CHudScoreboard m_Scoreboard; CHudMOTD m_MOTD; - + void Init( void ); void VidInit( void ); @@ -682,7 +683,7 @@ public: // sprite indexes int m_HUD_number_0; - int m_iNoConsolePrint; + int m_iNoConsolePrint; void AddHudElem(CHudBase *p); diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index ad6999d8..0d7ecba0 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -18,7 +18,7 @@ #include #include "hud.h" #include "cl_util.h" -#include "triangleapi.h" +//#include "triangleapi.h" #define MAX_LOGO_FRAMES 56 @@ -182,22 +182,58 @@ void ScaleColors( int &r, int &g, int &b, int a ) b = (int)(b * x); } +const unsigned char colors[8][3] = +{ +{127, 127, 127}, // additive cannot be black +{255, 0, 0}, +{ 0, 255, 0}, +{255, 255, 0}, +{ 0, 0, 255}, +{ 0, 255, 255}, +{255, 0, 255}, +{240, 180, 24} +}; + int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) { + if( hud_textmode->value == 2 ) + { + gEngfuncs.pfnDrawSetTextColor( r/255.0, g/255.0, b/255.0 ); + return gEngfuncs.pfnDrawConsoleString( xpos, ypos, (char*) szIt ); + } // draw the string until we hit the null character or a newline character for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) { - int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool - if ( next > iMaxX ) + int w = gHUD.m_scrinfo.charWidths[ 'M' ]; + if ( xpos + w > iMaxX ) return xpos; + if( *szIt == '^' && *(szIt + 1) >= '0' && *(szIt + 1) <= '7' ) + { + szIt++; + r = colors[ *szIt - '0' ][0]; + g = colors[ *szIt - '0' ][1]; + b = colors[ *szIt - '0' ][2]; + if( !*(++szIt)) + return xpos; + } - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - xpos = next; + xpos += TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); } return xpos; } +int CHud :: DrawHudStringLen( char *szIt ) +{ + int l = 0; + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + l += gHUD.m_scrinfo.charWidths[ (unsigned int)*szIt ]; + } + return l; +} + + int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) { char szString[32]; @@ -210,21 +246,11 @@ int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) { // find the end of the string - for ( char *szIt = szString; *szIt != 0; szIt++ ) - { // we should count the length? - } - - // iterate throug the string in reverse - for ( szIt--; szIt != (szString-1); szIt-- ) - { - int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool - if ( next < iMinX ) - return xpos; - xpos = next; - - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - } - + for( char *szIt = szString; *szIt != 0; szIt++ ) + xpos -= gHUD.m_scrinfo.charWidths[ (unsigned char) *szIt ]; + if( xpos < iMinX ) + xpos = iMinX; + DrawHudString( xpos, ypos, gHUD.m_scrinfo.iWidth, szString, r, g, b ); return xpos; } @@ -325,16 +351,8 @@ int CHud::GetNumWidth( int iNumber, int iFlags ) void CHud::DrawDarkRectangle( int x, int y, int wide, int tall ) { - FillRGBA( x, y, wide, tall, 0, 0, 0, 0 ); - float m_flScale = 1; - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pTriAPI->Begin(TRI_QUADS); - gEngfuncs.pTriAPI->Color4f(0.0, 0.0, 0.0, 0.6); - gEngfuncs.pTriAPI->Vertex3f(x * m_flScale, (y+tall)*m_flScale, 0); - gEngfuncs.pTriAPI->Vertex3f(x * m_flScale, y*m_flScale, 0); - gEngfuncs.pTriAPI->Vertex3f((x + wide)*m_flScale, y*m_flScale, 0); - gEngfuncs.pTriAPI->Vertex3f((x + wide)*m_flScale, (y+tall)*m_flScale, 0); - gEngfuncs.pTriAPI->End(); + //gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pfnFillRGBABlend( x, y, wide, tall, 0, 0, 0, 255 * 0.6 ); FillRGBA( x+1, y, wide-1, 1, 255, 140, 0, 255 ); FillRGBA( x, y, 1, tall-1, 255, 140, 0, 255 ); FillRGBA( x+wide-1, y+1, 1, tall-1, 255, 140, 0, 255 ); diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index e174ca51..be6d45e8 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -406,8 +406,8 @@ int CHudSpectator::Draw(float flTime) // make sure we have player info //gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - + gHUD.m_Scoreboard.GetAllPlayersInfo(); + // loop through all the players and draw additional infos to their sprites on the map @@ -434,7 +434,7 @@ int CHudSpectator::Draw(float flTime) lx = strlen(string)*3; // 3 is avg. character length :) - gEngfuncs.pfnDrawSetTextColor( color[0], color[1], color[2] ); + DrawSetTextColor( color[0], color[1], color[2] ); DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); } @@ -609,8 +609,8 @@ void CHudSpectator::FindNextPlayer(bool bReverse) // make sure we have player info //gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - + gHUD.m_Scoreboard.GetAllPlayersInfo(); + do diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp index 26551864..c85631c3 100644 --- a/cl_dll/in_camera.cpp +++ b/cl_dll/in_camera.cpp @@ -94,7 +94,7 @@ float MoveToward( float cur, float goal, float maxspeed ) { if( cur != goal ) { - if( abs( cur - goal ) > 180.0 ) + if( fabs( cur - goal ) > 180.0 ) { if( cur < goal ) cur += 360.0; @@ -376,7 +376,7 @@ void DLLEXPORT CAM_Think( void ) if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); - if( abs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) + if( fabs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) camAngles[ 2 ] = cam_idealdist->value; else camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; @@ -617,4 +617,4 @@ int DLLEXPORT CL_IsThirdPerson( void ) void DLLEXPORT CL_CameraOffset( float *ofs ) { VectorCopy( cam_ofs, ofs ); -} \ No newline at end of file +} diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index c3737c8f..e1023872 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -44,12 +44,12 @@ int ac_movecount; float rel_yaw; float rel_pitch; -#define F 1<<0 // Forward -#define B 1<<1 // Back -#define L 1<<2 // Left -#define R 1<<3 // Right -#define T 1<<4 // Forward stop -#define S 1<<5 // Side stop +#define F 1U<<0 // Forward +#define B 1U<<1 // Back +#define L 1U<<2 // Left +#define R 1U<<3 // Right +#define T 1U<<4 // Forward stop +#define S 1U<<5 // Side stop #define BUTTON_DOWN 1 #define IMPULSE_DOWN 2 @@ -58,7 +58,7 @@ float rel_pitch; void IN_ToggleButtons( float forwardmove, float sidemove ) { - static uint moveflags = T | S; + static unsigned int moveflags = T | S; if( forwardmove ) moveflags &= ~T; @@ -180,7 +180,7 @@ void IN_Move( float frametime, usercmd_t *cmd ) viewangles[YAW] += rel_yaw; if( fLadder ) { - if( ( cl_laddermode->value == 1 ) ) + if( cl_laddermode->value == 1 ) viewangles[YAW] -= ac_sidemove * 5; ac_sidemove = 0; } diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 47ebb142..3a7616a5 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -130,7 +130,7 @@ int CHudSayText :: Draw( float flTime ) // draw the first x characters in the player color strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; - gEngfuncs.pfnDrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); int x = DrawConsoleString( LINE_START, y, buf ); // color is reset after each string draw @@ -309,4 +309,4 @@ void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) } } } -} \ No newline at end of file +} diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 15aa9f2e..c7431328 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -113,7 +113,7 @@ int SCOREBOARD_WIDTH = 320; int CHudScoreboard :: Draw( float fTime ) { - int can_show_packetloss = 0; + int i, j, can_show_packetloss = 0; int FAR_RIGHT; gHUD.m_iNoConsolePrint &= ~( 1 << 0 ); @@ -178,7 +178,7 @@ int CHudScoreboard :: Draw( float fTime ) } // clear out team scores - for ( int i = 1; i <= m_iNumTeams; i++ ) + for ( i = 1; i <= m_iNumTeams; i++ ) { if ( !g_TeamInfo[i].scores_overriden ) g_TeamInfo[i].frags = g_TeamInfo[i].deaths = 0; @@ -195,7 +195,7 @@ int CHudScoreboard :: Draw( float fTime ) continue; // skip over players who are not in a team // find what team this player is in - for ( int j = 1; j <= m_iNumTeams; j++ ) + for ( j = 1; j <= m_iNumTeams; j++ ) { if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) break; @@ -485,6 +485,7 @@ int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *p // string: client team name int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) { + int i, j; BEGIN_READ( pbuf, iSize ); short cl = READ_BYTE(); @@ -496,7 +497,7 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb // rebuild the list of teams // clear out player counts from teams - for ( int i = 1; i <= m_iNumTeams; i++ ) + for ( i = 1; i <= m_iNumTeams; i++ ) { g_TeamInfo[i].players = 0; } @@ -513,7 +514,7 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb continue; // skip over players who are not in a team // is this player in an existing team? - for ( int j = 1; j <= m_iNumTeams; j++ ) + for ( j = 1; j <= m_iNumTeams; j++ ) { if ( g_TeamInfo[j].name[0] == '\0' ) break; @@ -559,9 +560,10 @@ int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *p { BEGIN_READ( pbuf, iSize ); char *TeamName = READ_STRING(); + int i; // find the team matching the name - for ( int i = 1; i <= m_iNumTeams; i++ ) + for ( i = 1; i <= m_iNumTeams; i++ ) { if ( !stricmp( TeamName, g_TeamInfo[i].name ) ) break; diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index 28018da9..e940187f 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -203,7 +203,7 @@ int CHudStatusBar :: Draw( float fTime ) } if ( m_pflNameColors[i] ) - gEngfuncs.pfnDrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); DrawConsoleString( x, y, m_szStatusBar[i] ); } @@ -262,4 +262,4 @@ int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void * m_bReparseString = TRUE; return 1; -} \ No newline at end of file +} From f8f80b9a0824516af861a2c9bdb5389aa86764f0 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 2 Mar 2016 08:00:09 +0000 Subject: [PATCH 005/227] Do not draw black console characters --- cl_dll/ammohistory.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp index bfe70058..cf3a2cf4 100644 --- a/cl_dll/ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -137,8 +137,10 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); } - // Draw the number - gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); + // do not draw black console string + if( !(( hud_textmode->value == 2 ) && ( scale < 200 )) ) + // Draw the number + gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); } else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) { From 9c3ffa636a2e409296a4e0fb93994e96d46b49f1 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 2 Mar 2016 08:02:02 +0000 Subject: [PATCH 006/227] Mobility interface, flashlight button switch --- cl_dll/cdll_int.cpp | 20 +++++++---- cl_dll/cl_dll.h | 10 +++--- cl_dll/flashlight.cpp | 11 +++++- cl_dll/health.cpp | 11 ++++++ engine/mobility_int.h | 82 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 engine/mobility_int.h diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index d7b50957..1ad81773 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -29,16 +29,16 @@ extern "C" #include -#ifdef _WIN32 +#ifdef _WIN32 #define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif +#else +#define DLLEXPORT +#endif cl_enginefunc_t gEngfuncs; CHud gHUD; - +mobile_engfuncs_t *gMobileEngfuncs = NULL; void InitInput (void); void EV_HookEvents( void ); void IN_Commands( void ); @@ -66,6 +66,7 @@ int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); void DLLEXPORT HUD_Frame( double time ); void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking); void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ); +void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ); } /* @@ -260,7 +261,7 @@ Called when a player starts or stops talking. void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) { - + } /* @@ -276,4 +277,9 @@ void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); } - +void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ) +{ + if( gpMobileEngfuncs->version != MOBILITY_API_VERSION ) + return; + gMobileEngfuncs = gpMobileEngfuncs; +} diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index 99020179..aeacb8be 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -36,8 +36,10 @@ typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); #include "../engine/cdll_int.h" #include "../dlls/cdll_dll.h" - -#define _cdecl -#include - + +#define _cdecl +#include + extern cl_enginefunc_t gEngfuncs; +#include "../engine/mobility_int.h" +extern mobile_engfuncs_t *gMobileEngfuncs; diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index dab2421b..ab8f70a4 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -96,7 +96,16 @@ int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *p int CHudFlashlight::Draw(float flTime) { - if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) + static bool show = ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ); + if( show != !( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) ) + { + show = !( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ); + if( gMobileEngfuncs ) + { + gMobileEngfuncs->pfnTouchHideButtons( "flashlight", !show ); + } + } + if ( !show ) return 1; int r, g, b, x, y, a; diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index da664720..0b73efca 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -27,6 +27,7 @@ #include "parsemsg.h" #include +#include "mobility_int.h" DECLARE_MESSAGE(m_Health, Health ) DECLARE_MESSAGE(m_Health, Damage ) @@ -133,8 +134,18 @@ int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) // Actually took damage? if ( damageTaken > 0 || armor > 0 ) + { CalcDamageDirection(vecFrom); + if( gMobileEngfuncs && damageTaken > 0 ) + { + float time = damageTaken * 4.0f; + + if( time > 200.0f ) time = 200.0f; + gMobileEngfuncs->pfnVibrate( time, 0 ); + } + } + return 1; } diff --git a/engine/mobility_int.h b/engine/mobility_int.h new file mode 100644 index 00000000..88f63315 --- /dev/null +++ b/engine/mobility_int.h @@ -0,0 +1,82 @@ +/* +mobility_int.h - interface between engine and client for mobile platforms +Copyright (C) 2015 a1batross + +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. +*/ + +#pragma once +#ifndef MOBILITY_INT_H +#define MOBILITY_INT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define MOBILITY_API_VERSION 2 +#define MOBILITY_CLIENT_EXPORT "HUD_MobilityInterface" + +#define VIBRATE_NORMAL (1U << 0) // just vibrate for given "life" + +#define TOUCH_FL_HIDE (1U << 0) +#define TOUCH_FL_NOEDIT (1U << 1) +#define TOUCH_FL_CLIENT (1U << 2) +#define TOUCH_FL_MP (1U << 3) +#define TOUCH_FL_SP (1U << 4) +#define TOUCH_FL_DEF_SHOW (1U << 5) +#define TOUCH_FL_DEF_HIDE (1U << 6) +#define TOUCH_FL_DRAW_ADDITIVE (1U << 7) +#define TOUCH_FL_STROKE (1U << 8) +#define TOUCH_FL_PRECISION (1U << 9) + +typedef struct mobile_engfuncs_s +{ + // indicates version of API. Should be equal to MOBILITY_API_VERSION + // version changes when existing functions are changes + int version; + + // vibration control + // life -- time to vibrate in ms + void (*pfnVibrate)( float life, char flags ); + + // enable text input + void (*pfnEnableTextInput)( int enable ); + + // add temporaty button, edit will be disabled + void (*pfnTouchAddClientButton)( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, unsigned char *color, int round, float aspect, int flags ); + + // add button to defaults list. Will be loaded on config generation + void (*pfnTouchAddDefaultButton)( const char *name, const char *texturefile, const char *command, float x1, float y1, float x2, float y2, unsigned char *color, int round, float aspect, int flags ); + + // hide/show buttons by pattern + void (*pfnTouchHideButtons)( const char *name, unsigned char hide ); + + // remove button with given name + void (*pfnTouchRemoveButton)( const char *name ); + + // when enabled, only client buttons shown + void (*pfnTouchSetClientOnly)( unsigned char state ); + + // Clean defaults list + void (*pfnTouchResetDefaultButtons)(); + + // To be continued... +} mobile_engfuncs_t; + +extern mobile_engfuncs_t *gMobileEngfuncs; + +// function exported from client +// returns 0 on no error otherwise error +typedef int (*pfnMobilityInterface)( mobile_engfuncs_t *gMobileEngfuncs ); + +#ifdef __cplusplus +} +#endif +#endif From 81207e381599dad89747bb11411bedcfa485220a Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 2 Mar 2016 11:39:18 +0000 Subject: [PATCH 007/227] Add sed script and convert all SetXXX macros --- .gitigonre | 4 ++- dlls/AI_BaseNPC_Schedule.cpp | 2 +- dlls/aflock.cpp | 18 +++++----- dlls/airtank.cpp | 4 +-- dlls/apache.cpp | 26 +++++++------- dlls/barnacle.cpp | 6 ++-- dlls/barney.cpp | 4 +-- dlls/bigmomma.cpp | 2 +- dlls/bmodels.cpp | 36 +++++++++---------- dlls/bullsquid.cpp | 4 +-- dlls/buttons.cpp | 70 ++++++++++++++++++------------------ dlls/cbase.h | 10 +++--- dlls/combat.cpp | 20 +++++------ dlls/controller.cpp | 14 ++++---- dlls/crossbow.cpp | 12 +++---- dlls/crowbar.cpp | 4 +-- dlls/doors.cpp | 26 +++++++------- dlls/effects.cpp | 58 +++++++++++++++--------------- dlls/effects.h | 4 +-- dlls/explode.cpp | 2 +- dlls/func_break.cpp | 14 ++++---- dlls/gargantua.cpp | 8 ++--- dlls/ggrenade.cpp | 22 ++++++------ dlls/h_battery.cpp | 8 ++--- dlls/h_cine.cpp | 10 +++--- dlls/h_cycler.cpp | 2 +- dlls/handgrenade.cpp | 2 +- dlls/headcrab.cpp | 6 ++-- dlls/healthkit.cpp | 8 ++--- dlls/hgrunt.cpp | 4 +-- dlls/hornet.cpp | 18 +++++----- dlls/hornetgun.cpp | 2 +- dlls/ichthyosaur.cpp | 4 +-- dlls/items.cpp | 10 +++--- dlls/leech.cpp | 10 +++--- dlls/monstermaker.cpp | 18 +++++----- dlls/monsters.cpp | 10 +++--- dlls/mortar.cpp | 6 ++-- dlls/mpstubb.cpp | 4 +-- dlls/nihilanth.cpp | 38 ++++++++++---------- dlls/nodes.cpp | 12 +++---- dlls/osprey.cpp | 20 +++++------ dlls/pathcorner.cpp | 2 +- dlls/plats.cpp | 62 ++++++++++++++++---------------- dlls/player.cpp | 16 ++++----- dlls/prop.cpp | 24 ++++++------- dlls/replace.sh | 5 +++ dlls/rpg.cpp | 12 +++---- dlls/satchel.cpp | 8 ++--- dlls/schedule.cpp | 2 +- dlls/scientist.cpp | 6 ++-- dlls/scripted.cpp | 28 +++++++-------- dlls/sound.cpp | 12 +++---- dlls/squeakgrenade.cpp | 12 +++---- dlls/subs.cpp | 6 ++-- dlls/talkmonster.cpp | 2 +- dlls/tentacle.cpp | 14 ++++---- dlls/triggers.cpp | 66 +++++++++++++++++----------------- dlls/tripmine.cpp | 16 ++++----- dlls/turret.cpp | 58 +++++++++++++++--------------- dlls/weapons.cpp | 48 ++++++++++++------------- dlls/world.cpp | 10 +++--- 62 files changed, 489 insertions(+), 482 deletions(-) create mode 100644 dlls/replace.sh diff --git a/.gitigonre b/.gitigonre index 543ea558..e01e183d 100644 --- a/.gitigonre +++ b/.gitigonre @@ -1,6 +1,8 @@ # Binaries *.o *.so +*/*.o +*/*/*.o *.a *.framework - +*.exe \ No newline at end of file diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/dlls/AI_BaseNPC_Schedule.cpp index 75886699..f1eb367d 100644 --- a/dlls/AI_BaseNPC_Schedule.cpp +++ b/dlls/AI_BaseNPC_Schedule.cpp @@ -454,7 +454,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { pev->deadflag = DEAD_DEAD; - ResetThink(); + SetThink( NULL ); StopAnimation(); if ( !BBoxFlat() ) diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index 45824287..f536b4f0 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -211,7 +211,7 @@ void CFlockingFlyerFlock :: SpawnFlock( void ) pBoid->pev->frame = 0; pBoid->pev->nextthink = gpGlobals->time + 0.2; - pBoid->SetThink( CFlockingFlyer :: IdleThink ); + pBoid->SetThink( &CFlockingFlyer :: IdleThink ); if ( pBoid != pLeader ) { @@ -229,7 +229,7 @@ void CFlockingFlyer :: Spawn( ) pev->frame = 0; pev->nextthink = gpGlobals->time + 0.1; - SetThink( IdleThink ); + SetThink( &IdleThink ); } //========================================================= @@ -292,7 +292,7 @@ void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); pev->movetype = MOVETYPE_TOSS; - SetThink ( FallHack ); + SetThink( &FallHack ); pev->nextthink = gpGlobals->time + 0.1; } @@ -308,7 +308,7 @@ void CFlockingFlyer :: FallHack( void ) else { pev->velocity = g_vecZero; - ResetThink(); + SetThink( NULL ); } } } @@ -366,7 +366,7 @@ void CFlockingFlyer :: IdleThink( void ) // see if there's a client in the same pvs as the monster if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { - SetThink( Start ); + SetThink( &Start ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -380,11 +380,11 @@ void CFlockingFlyer :: Start( void ) if ( IsLeader() ) { - SetThink( FlockLeaderThink ); + SetThink( &FlockLeaderThink ); } else { - SetThink( FlockFollowerThink ); + SetThink( &FlockFollowerThink ); } /* @@ -438,7 +438,7 @@ void CFlockingFlyer :: FormFlock( void ) } } - SetThink( IdleThink );// now that flock is formed, go to idle and wait for a player to come along. + SetThink( &IdleThink );// now that flock is formed, go to idle and wait for a player to come along. pev->nextthink = gpGlobals->time; } @@ -673,7 +673,7 @@ void CFlockingFlyer :: FlockFollowerThink( void ) if ( IsLeader() || !InSquad() ) { // the leader has been killed and this flyer suddenly finds himself the leader. - SetThink ( FlockLeaderThink ); + SetThink( &FlockLeaderThink ); return; } diff --git a/dlls/airtank.cpp b/dlls/airtank.cpp index a356744b..b244f581 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -58,8 +58,8 @@ void CAirtank :: Spawn( void ) UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( TankTouch ); - SetThink( TankThink ); + SetTouch( &TankTouch ); + SetThink( &TankThink ); pev->flags |= FL_MONSTER; pev->takedamage = DAMAGE_YES; diff --git a/dlls/apache.cpp b/dlls/apache.cpp index 233599f4..fae0ff34 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -139,12 +139,12 @@ void CApache :: Spawn( void ) if (pev->spawnflags & SF_WAITFORTRIGGER) { - SetUse( StartupUse ); + SetUse( &StartupUse ); } else { - SetThink( HuntThink ); - SetTouch( FlyTouch ); + SetThink( &HuntThink ); + SetTouch( &FlyTouch ); pev->nextthink = gpGlobals->time + 1.0; } @@ -186,10 +186,10 @@ void CApache::NullThink( void ) void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( HuntThink ); - SetTouch( FlyTouch ); + SetThink( &HuntThink ); + SetTouch( &FlyTouch ); pev->nextthink = gpGlobals->time + 0.1; - ResetUse(); + SetUse( NULL ); } void CApache :: Killed( entvars_t *pevAttacker, int iGib ) @@ -200,8 +200,8 @@ void CApache :: Killed( entvars_t *pevAttacker, int iGib ) STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( DyingThink ); - SetTouch( CrashTouch ); + SetThink( &DyingThink ); + SetTouch( &CrashTouch ); pev->nextthink = gpGlobals->time + 0.1; pev->health = 0; pev->takedamage = DAMAGE_NO; @@ -402,7 +402,7 @@ void CApache :: DyingThink( void ) WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -426,7 +426,7 @@ void CApache::CrashTouch( CBaseEntity *pOther ) // only crash if we hit something solid if ( pOther->pev->solid == SOLID_BSP) { - ResetTouch(); + SetTouch( NULL ); m_flNextRocket = gpGlobals->time; pev->nextthink = gpGlobals->time; } @@ -972,8 +972,8 @@ void CApacheHVR :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( IgniteThink ); - SetTouch( ExplodeTouch ); + SetThink( &IgniteThink ); + SetTouch( &ExplodeTouch ); UTIL_MakeAimVectors( pev->angles ); m_vecForward = gpGlobals->v_forward; @@ -1019,7 +1019,7 @@ void CApacheHVR :: IgniteThink( void ) MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) // set to accelerate - SetThink( AccelerateThink ); + SetThink( &AccelerateThink ); pev->nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp index 4042d7da..aaf8c539 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -137,7 +137,7 @@ void CBarnacle :: Spawn() SetActivity ( ACT_IDLE ); - SetThink ( BarnacleThink ); + SetThink( &BarnacleThink ); pev->nextthink = gpGlobals->time + 0.5; UTIL_SetOrigin ( pev, pev->origin ); @@ -370,7 +370,7 @@ void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) StudioFrameAdvance( 0.1 ); pev->nextthink = gpGlobals->time + 0.1; - SetThink ( WaitTillDead ); + SetThink( &WaitTillDead ); } //========================================================= @@ -386,7 +386,7 @@ void CBarnacle :: WaitTillDead ( void ) { // death anim finished. StopAnimation(); - ResetThink(); + SetThink( NULL ); } } diff --git a/dlls/barney.cpp b/dlls/barney.cpp index 1d3e23ad..7837c5c0 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -424,7 +424,7 @@ void CBarney :: Spawn() m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; MonsterInit(); - SetUse( FollowerUse ); + SetUse( &FollowerUse ); } //========================================================= @@ -623,7 +623,7 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib ) CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); } - ResetUse(); + SetUse( NULL ); CTalkMonster::Killed( pevAttacker, iGib ); } diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index ca7a1bf8..06f98da1 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -1198,7 +1198,7 @@ CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity pSpit->pev->velocity = vecVelocity; pSpit->pev->owner = pOwner; pSpit->pev->scale = 2.5; - pSpit->SetThink ( Animate ); + pSpit->SetThink( &Animate ); pSpit->pev->nextthink = gpGlobals->time + 0.1; return pSpit; diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index 1386c242..1ab8afc7 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -419,7 +419,7 @@ void CFuncRotating :: Spawn( ) UTIL_SetOrigin(pev, pev->origin); SET_MODEL( ENT(pev), STRING(pev->model) ); - SetUse( RotatingUse ); + SetUse( &RotatingUse ); // did level designer forget to assign speed? if (pev->speed <= 0) pev->speed = 0; @@ -431,13 +431,13 @@ void CFuncRotating :: Spawn( ) // instant-use brush? if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) { - SetThink( SUB_CallUseToggle ); + SetThink( &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( HurtTouch ); + SetTouch( &HurtTouch ); } Precache( ); @@ -504,7 +504,7 @@ void CFuncRotating :: Precache( void ) // 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 ( SpinUp ); + SetThink( &SpinUp ); pev->nextthink = pev->ltime + 1.5; } } @@ -600,7 +600,7 @@ void CFuncRotating :: SpinUp( void ) EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); - SetThink( Rotate ); + SetThink( &Rotate ); Rotate(); } else @@ -641,7 +641,7 @@ void CFuncRotating :: SpinDown( void ) EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), 0, 0, SND_STOP, m_pitch); - SetThink( Rotate ); + SetThink( &Rotate ); Rotate(); } else @@ -666,7 +666,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller // fan is spinning, so stop it. if ( pev->avelocity != g_vecZero ) { - SetThink ( SpinDown ); + SetThink( &SpinDown ); //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), // m_flVolume, m_flAttenuation, 0, m_pitch); @@ -674,7 +674,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller } else// fan is not moving, so start it { - SetThink ( SpinUp ); + SetThink( &SpinUp ); EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), 0.01, m_flAttenuation, 0, FANPITCHMIN); @@ -686,7 +686,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller if ( pev->avelocity != g_vecZero ) { // play stopping sound here - SetThink ( SpinDown ); + SetThink( &SpinDown ); // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), // m_flVolume, m_flAttenuation, 0, m_pitch); @@ -700,7 +700,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller m_flVolume, m_flAttenuation, 0, FANPITCHMAX); pev->avelocity = pev->movedir * pev->speed; - SetThink( Rotate ); + SetThink( &Rotate ); Rotate(); } } @@ -812,15 +812,15 @@ void CPendulum :: Spawn( void ) if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) { - SetThink( SUB_CallUseToggle ); + SetThink( &SUB_CallUseToggle ); pev->nextthink = gpGlobals->time + 0.1; } pev->speed = 0; - SetUse( PendulumUse ); + SetUse( &PendulumUse ); if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) { - SetTouch ( RopeTouch ); + SetTouch( &RopeTouch ); } } @@ -837,12 +837,12 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US pev->avelocity = m_maxSpeed * pev->movedir; pev->nextthink = pev->ltime + (delta / m_maxSpeed); - SetThink( Stop ); + SetThink( &Stop ); } else { pev->speed = 0; // Dead stop - ResetThink(); + SetThink( NULL ); pev->avelocity = g_vecZero; } } @@ -850,7 +850,7 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US { pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving m_time = gpGlobals->time; // Save time to calculate dt - SetThink( Swing ); + SetThink( &Swing ); m_dampSpeed = m_maxSpeed; } } @@ -860,7 +860,7 @@ void CPendulum :: Stop( void ) { pev->angles = m_start; pev->speed = 0; - ResetThink(); + SetThink( NULL ); pev->avelocity = g_vecZero; } @@ -901,7 +901,7 @@ void CPendulum :: Swing( void ) { pev->angles = m_center; pev->speed = 0; - ResetThink(); + SetThink( NULL ); pev->avelocity = g_vecZero; } else if ( pev->speed > m_dampSpeed ) diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index c8518b62..6a1ffe19 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -121,7 +121,7 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity pSpit->pev->velocity = vecVelocity; pSpit->pev->owner = ENT(pevOwner); - pSpit->SetThink ( Animate ); + pSpit->SetThink( &Animate ); pSpit->pev->nextthink = gpGlobals->time + 0.1; } @@ -172,7 +172,7 @@ void CSquidSpit :: Touch ( CBaseEntity *pOther ) pOther->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); } - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 5153d7ba..44f413bc 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -173,7 +173,7 @@ void CMultiSource::Spawn() pev->movetype = MOVETYPE_NONE; pev->nextthink = gpGlobals->time + 0.1; pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized - SetThink(Register); + SetThink( &Register); } void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) @@ -240,7 +240,7 @@ void CMultiSource::Register(void) m_iTotal = 0; memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); - SetThink(SUB_DoNothing); + SetThink( &SUB_DoNothing); // search for all entities which target this multisource (pev->targetname) @@ -398,7 +398,7 @@ int CBaseButton::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, fl if ( code == BUTTON_NOTHING ) return 0; // Temporarily disable the touch function, until movement is finished. - ResetTouch(); + SetTouch( NULL ); m_hActivator = CBaseEntity::Instance( pevAttacker ); if ( m_hActivator == NULL ) @@ -455,7 +455,7 @@ void CBaseButton::Spawn( ) if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state { - SetThink ( ButtonSpark ); + SetThink( &ButtonSpark ); pev->nextthink = gpGlobals->time + 0.5;// no hurry, make sure everything else spawns } @@ -495,12 +495,12 @@ void CBaseButton::Spawn( ) if ( FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button { - SetTouch( ButtonTouch ); + SetTouch( &ButtonTouch ); } else { - ResetTouch(); - SetUse ( ButtonUse ); + SetTouch( NULL ); + SetUse( &ButtonUse ); } } @@ -567,7 +567,7 @@ void DoSpark(entvars_t *pev, const Vector &location ) void CBaseButton::ButtonSpark ( void ) { - SetThink ( ButtonSpark ); + SetThink( &ButtonSpark ); pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval DoSpark( pev, pev->mins ); @@ -646,7 +646,7 @@ void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) } // Temporarily disable the touch function, until movement is finished. - ResetTouch(); + SetTouch( NULL ); if ( code == BUTTON_RETURN ) { @@ -680,7 +680,7 @@ void CBaseButton::ButtonActivate( ) ASSERT(m_toggle_state == TS_AT_BOTTOM); m_toggle_state = TS_GOING_UP; - SetMoveDone( TriggerAndWait ); + SetMoveDone( &TriggerAndWait ); if (!m_fRotating) LinearMove( m_vecPosition2, pev->speed); else @@ -706,15 +706,15 @@ void CBaseButton::TriggerAndWait( void ) if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! { // ALL buttons are now use only - ResetTouch(); + SetTouch( NULL ); } else - SetTouch( ButtonTouch ); + SetTouch( &ButtonTouch ); } else { pev->nextthink = pev->ltime + m_flWait; - SetThink( ButtonReturn ); + SetThink( &ButtonReturn ); } pev->frame = 1; // use alternate textures @@ -732,7 +732,7 @@ void CBaseButton::ButtonReturn( void ) ASSERT(m_toggle_state == TS_AT_TOP); m_toggle_state = TS_GOING_DOWN; - SetMoveDone( ButtonBackHome ); + SetMoveDone( &ButtonBackHome ); if (!m_fRotating) LinearMove( m_vecPosition1, pev->speed); else @@ -781,15 +781,15 @@ void CBaseButton::ButtonBackHome( void ) if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! { // All buttons are now use only - ResetTouch(); + SetTouch( NULL ); } else - SetTouch( ButtonTouch ); + SetTouch( &ButtonTouch ); // reset think for a sparking button if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) { - SetThink ( ButtonSpark ); + SetThink( &ButtonSpark ); pev->nextthink = gpGlobals->time + 0.5;// no hurry. } } @@ -856,13 +856,13 @@ void CRotButton::Spawn( void ) // 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 ) ) { - ResetTouch(); - SetUse ( ButtonUse ); + SetTouch( NULL ); + SetUse( &ButtonUse ); } else // touchable button - SetTouch( ButtonTouch ); + SetTouch( &ButtonTouch ); - //SetTouch( ButtonTouch ); + //SetTouch( &ButtonTouch ); } @@ -1049,7 +1049,7 @@ void CMomentaryRotButton::UpdateSelf( float value ) pev->nextthink += 0.1; pev->avelocity = (m_direction * pev->speed) * pev->movedir; - SetThink( Off ); + SetThink( &Off ); } void CMomentaryRotButton::UpdateTarget( float value ) @@ -1077,12 +1077,12 @@ void CMomentaryRotButton::Off( void ) m_lastUsed = 0; if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) { - SetThink( Return ); + SetThink( &Return ); pev->nextthink = pev->ltime + 0.1; m_direction = -1; } else - ResetThink(); + SetThink( NULL ); } void CMomentaryRotButton::Return( void ) @@ -1102,7 +1102,7 @@ void CMomentaryRotButton::UpdateSelfReturn( float value ) pev->avelocity = g_vecZero; pev->angles = m_start; pev->nextthink = -1; - ResetThink(); + SetThink( NULL ); } else { @@ -1147,21 +1147,21 @@ LINK_ENTITY_TO_CLASS(env_debris, CEnvSpark); void CEnvSpark::Spawn(void) { - ResetThink(); - ResetUse(); + SetThink( NULL ); + SetUse( NULL ); if (FBitSet(pev->spawnflags, 32)) // Use for on/off { if (FBitSet(pev->spawnflags, 64)) // Start on { - SetThink(SparkThink); // start sparking - SetUse(SparkStop); // set up +USE to stop sparking + SetThink( &SparkThink); // start sparking + SetUse( &SparkStop); // set up +USE to stop sparking } else - SetUse(SparkStart); + SetUse( &SparkStart); } else - SetThink(SparkThink); + SetThink( &SparkThink); pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); @@ -1208,15 +1208,15 @@ void EXPORT CEnvSpark::SparkThink(void) void EXPORT CEnvSpark::SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetUse(SparkStop); - SetThink(SparkThink); + SetUse( &SparkStop); + SetThink( &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(SparkStart); - ResetThink(); + SetUse( &SparkStart); + SetThink( NULL ); } #define SF_BTARGET_USE 0x0001 diff --git a/dlls/cbase.h b/dlls/cbase.h index 1381c88a..1aa64bb3 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -373,10 +373,10 @@ public: #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) +#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) #define ResetThink( ) m_pfnThink = static_cast (NULL) #define ResetTouch( ) m_pfnTouch = static_cast (NULL) #define ResetUse( ) m_pfnUse = static_cast (NULL) @@ -557,7 +557,7 @@ public: // the button will be allowed to operate. Otherwise, it will be // deactivated. }; -#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (&a) +#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) diff --git a/dlls/combat.cpp b/dlls/combat.cpp index c99330cd..2899d051 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -115,8 +115,8 @@ void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs pGib->pev->movetype = MOVETYPE_TOSS; pGib->pev->solid = SOLID_BBOX; UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); - pGib->SetTouch ( StickyGibTouch ); - pGib->ResetThink(); + pGib->SetTouch( &StickyGibTouch ); + pGib->SetThink( NULL ); } pGib->LimitVelocity(); } @@ -331,7 +331,7 @@ void CBaseMonster :: GibMonster( void ) if ( gibbed ) { // don't remove players! - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } else @@ -622,7 +622,7 @@ void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) } else if ( pev->flags & FL_MONSTER ) { - ResetTouch(); + SetTouch( NULL ); BecomeDead(); } @@ -654,7 +654,7 @@ void CBaseEntity :: SUB_StartFadeOut ( void ) pev->avelocity = g_vecZero; pev->nextthink = gpGlobals->time + 0.1; - SetThink ( SUB_FadeOut ); + SetThink( &SUB_FadeOut ); } void CBaseEntity :: SUB_FadeOut ( void ) @@ -668,7 +668,7 @@ void CBaseEntity :: SUB_FadeOut ( void ) { pev->renderamt = 0; pev->nextthink = gpGlobals->time + 0.2; - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); } } @@ -688,7 +688,7 @@ void CGib :: WaitTillLand ( void ) if ( pev->velocity == g_vecZero ) { - SetThink (SUB_StartFadeOut); + SetThink( &SUB_StartFadeOut); pev->nextthink = gpGlobals->time + m_lifeTime; // If you bleed, you stink! @@ -756,7 +756,7 @@ void CGib :: StickyGibTouch ( CBaseEntity *pOther ) Vector vecSpot; TraceResult tr; - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 10; if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) @@ -797,8 +797,8 @@ void CGib :: Spawn( const char *szGibModel ) pev->nextthink = gpGlobals->time + 4; m_lifeTime = 25; - SetThink ( WaitTillLand ); - SetTouch ( BounceGibTouch ); + SetThink( &WaitTillLand ); + SetTouch( &BounceGibTouch ); m_material = matNone; m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). diff --git a/dlls/controller.cpp b/dlls/controller.cpp index bad72429..0ade7ace 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -1170,8 +1170,8 @@ void CControllerHeadBall :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( HuntThink ); - SetTouch( BounceTouch ); + SetThink( &HuntThink ); + SetTouch( &BounceTouch ); m_vecIdeal = Vector( 0, 0, 0 ); @@ -1213,7 +1213,7 @@ void CControllerHeadBall :: HuntThink( void ) // check world boundaries if (gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) { - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); return; } @@ -1257,7 +1257,7 @@ void CControllerHeadBall :: HuntThink( void ) m_flNextAttack = gpGlobals->time + 3.0; - SetThink( DieThink ); + SetThink( &DieThink ); pev->nextthink = gpGlobals->time + 0.3; } @@ -1364,8 +1364,8 @@ void CControllerZapBall :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( AnimateThink ); - SetTouch( ExplodeTouch ); + SetThink( &AnimateThink ); + SetTouch( &ExplodeTouch ); m_hOwner = Instance( pev->owner ); pev->dmgtime = gpGlobals->time; // keep track of when ball spawned @@ -1389,7 +1389,7 @@ void CControllerZapBall :: AnimateThink( void ) if (gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10) { - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); } } diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 4a2ffd66..2a9224cd 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -71,8 +71,8 @@ void CCrossbowBolt::Spawn( ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - SetTouch( BoltTouch ); - SetThink( BubbleThink ); + SetTouch( &BoltTouch ); + SetThink( &BubbleThink ); pev->nextthink = gpGlobals->time + 0.2; } @@ -96,8 +96,8 @@ int CCrossbowBolt :: Classify ( void ) void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { - ResetTouch(); - ResetThink(); + SetTouch( NULL ); + SetThink( NULL ); if (pOther->pev->takedamage) { @@ -139,7 +139,7 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { 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( SUB_Remove ); + SetThink( &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" ) ) @@ -179,7 +179,7 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) if ( g_pGameRules->IsMultiplayer() ) { - SetThink( ExplodeThink ); + SetThink( &ExplodeThink ); pev->nextthink = gpGlobals->time + 0.1; } } diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index f301de7f..de6ad845 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -147,7 +147,7 @@ void CCrowbar::PrimaryAttack() { if (! Swing( 1 )) { - SetThink( SwingAgain ); + SetThink( &SwingAgain ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -306,7 +306,7 @@ int CCrowbar::Swing( int fFirst ) #endif m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - SetThink( Smack ); + SetThink( &Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index d8233d9b..44815efb 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -317,10 +317,10 @@ void CBaseDoor::Spawn( ) // if the door is flagged for USE button activation only, use NULL touch function if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) { - ResetTouch(); + SetTouch( NULL ); } else // touchable button - SetTouch( DoorTouch ); + SetTouch( &DoorTouch ); } @@ -509,7 +509,7 @@ void CBaseDoor::DoorTouch( CBaseEntity *pOther ) m_hActivator = pOther;// remember who activated the door if (DoorActivate( )) - ResetTouch(); // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. } @@ -576,7 +576,7 @@ void CBaseDoor::DoorGoUp( void ) m_toggle_state = TS_GOING_UP; - SetMoveDone( DoorHitTop ); + SetMoveDone( &DoorHitTop ); if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet { float sign = 1.0; @@ -625,13 +625,13 @@ void CBaseDoor::DoorHitTop( void ) { // Re-instate touch method, movement is complete if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - SetTouch( DoorTouch ); + SetTouch( &DoorTouch ); } else { // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open pev->nextthink = pev->ltime + m_flWait; - SetThink( DoorGoDown ); + SetThink( &DoorGoDown ); if ( m_flWait == -1 ) { @@ -661,7 +661,7 @@ void CBaseDoor::DoorGoDown( void ) #endif // DOOR_ASSERT m_toggle_state = TS_GOING_DOWN; - SetMoveDone( DoorHitBottom ); + SetMoveDone( &DoorHitBottom ); if ( FClassnameIs(pev, "func_door_rotating"))//rotating door AngularMove( m_vecAngle1, pev->speed); else @@ -685,10 +685,10 @@ void CBaseDoor::DoorHitBottom( void ) // Re-instate touch method, cycle is complete if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) {// use only door - ResetTouch(); + SetTouch( NULL ); } else // touchable door - SetTouch( DoorTouch ); + SetTouch( &DoorTouch ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished @@ -862,10 +862,10 @@ void CRotDoor::Spawn( void ) if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) { - ResetTouch(); + SetTouch( NULL ); } else // touchable button - SetTouch( DoorTouch ); + SetTouch( &DoorTouch ); } @@ -935,7 +935,7 @@ void CMomentaryDoor::Spawn( void ) m_vecPosition2 = m_vecPosition1; m_vecPosition1 = pev->origin; } - ResetTouch(); + SetTouch( NULL ); Precache(); } @@ -1075,7 +1075,7 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); LinearMove( move, speed ); - SetMoveDone( MomentaryMoveDone ); + SetMoveDone( &MomentaryMoveDone ); } } diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 36b49c33..933e952e 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -87,7 +87,7 @@ void CBubbling::Spawn( void ) if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) { - SetThink( FizzThink ); + SetThink( &FizzThink ); pev->nextthink = gpGlobals->time + 2.0; m_state = 1; } @@ -108,12 +108,12 @@ void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use if ( m_state ) { - SetThink( FizzThink ); + SetThink( &FizzThink ); pev->nextthink = gpGlobals->time + 0.1; } else { - ResetThink(); + SetThink( NULL ); pev->nextthink = 0; } } @@ -427,7 +427,7 @@ LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); void CTripBeam::Spawn( void ) { CLightning::Spawn(); - SetTouch( TriggerTouch ); + SetTouch( &TriggerTouch ); pev->solid = SOLID_TRIGGER; RelinkBeam(); } @@ -459,7 +459,7 @@ void CLightning::Spawn( void ) { if ( FStringNull( m_iszSpriteName ) ) { - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions @@ -469,10 +469,10 @@ void CLightning::Spawn( void ) if ( ServerSide() ) { - ResetThink(); + SetThink( NULL ); if ( pev->dmg > 0 ) { - SetThink( DamageThink ); + SetThink( &DamageThink ); pev->nextthink = gpGlobals->time + 0.1; } if ( pev->targetname ) @@ -486,7 +486,7 @@ void CLightning::Spawn( void ) else m_active = 1; - SetUse( ToggleUse ); + SetUse( &ToggleUse ); } } else @@ -494,11 +494,11 @@ void CLightning::Spawn( void ) m_active = 0; if ( !FStringNull(pev->targetname) ) { - SetUse( StrikeUse ); + SetUse( &StrikeUse ); } if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) { - SetThink( StrikeThink ); + SetThink( &StrikeThink ); pev->nextthink = gpGlobals->time + 1.0; } } @@ -612,16 +612,16 @@ void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T if ( m_active ) { m_active = 0; - ResetThink(); + SetThink( NULL ); } else { - SetThink( StrikeThink ); + SetThink( &StrikeThink ); pev->nextthink = gpGlobals->time + 0.1; } if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) - ResetUse(); + SetUse( NULL ); } @@ -961,13 +961,13 @@ void CLaser::Spawn( void ) { if ( FStringNull( pev->model ) ) { - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions Precache( ); - SetThink( StrikeThink ); + SetThink( &StrikeThink ); pev->flags |= FL_CUSTOMENTITY; PointsInit( pev->origin, pev->origin ); @@ -1264,7 +1264,7 @@ void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { pev->speed = scaleSpeed; pev->health = fadeSpeed; - SetThink( ExpandThink ); + SetThink( &ExpandThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; @@ -1319,7 +1319,7 @@ void CSprite::TurnOn( void ) pev->effects = 0; if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) { - SetThink( AnimateThink ); + SetThink( &AnimateThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; } @@ -1426,7 +1426,7 @@ void CGibShooter::KeyValue( KeyValueData *pkvd ) void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( ShootThink ); + SetThink( &ShootThink ); pev->nextthink = gpGlobals->time; } @@ -1511,12 +1511,12 @@ void CGibShooter :: ShootThink ( void ) if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) { m_iGibs = m_iGibCapacity; - ResetThink(); + SetThink( NULL ); pev->nextthink = gpGlobals->time; } else { - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } } @@ -1701,14 +1701,14 @@ void CTestEffect::TestThink( void ) m_flStartTime = gpGlobals->time; m_iBeam = 0; // pev->nextthink = gpGlobals->time; - ResetThink(); + SetThink( NULL ); } } void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( TestThink ); + SetThink( &TestThink ); pev->nextthink = gpGlobals->time + 0.1; m_flStartTime = gpGlobals->time; } @@ -2129,7 +2129,7 @@ void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us MESSAGE_END(); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } @@ -2184,7 +2184,7 @@ void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE pev->frags = 1; pev->health--; - //SetThink (SUB_Remove); + //SetThink( &SUB_Remove); //pev->nextthink = gpGlobals->time; } @@ -2228,7 +2228,7 @@ void CItemSoda::Spawn( void ) SET_MODEL ( ENT(pev), "models/can.mdl" ); UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); - SetThink (CanThink); + SetThink( &CanThink); pev->nextthink = gpGlobals->time + 0.5; } @@ -2238,8 +2238,8 @@ void CItemSoda::CanThink ( void ) pev->solid = SOLID_TRIGGER; UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); - ResetThink(); - SetTouch ( CanTouch ); + SetThink( NULL ); + SetTouch( &CanTouch ); } void CItemSoda::CanTouch ( CBaseEntity *pOther ) @@ -2262,7 +2262,7 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; pev->effects = EF_NODRAW; - ResetTouch(); - SetThink ( SUB_Remove ); + SetTouch( NULL ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } \ No newline at end of file diff --git a/dlls/effects.h b/dlls/effects.h index 1464d6a6..c62a3ee4 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -79,7 +79,7 @@ public: inline void AnimateAndDie( float framerate ) { - SetThink(AnimateUntilDead); + SetThink( &AnimateUntilDead); pev->framerate = framerate; pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); pev->nextthink = gpGlobals->time; @@ -168,7 +168,7 @@ public: static CBeam *BeamCreate( const char *pSpriteName, int width ); - inline void LiveForTime( float time ) { SetThink(SUB_Remove); pev->nextthink = gpGlobals->time + time; } + inline void LiveForTime( float time ) { SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + time; } inline void BeamDamageInstant( TraceResult *ptr, float damage ) { pev->dmg = damage; diff --git a/dlls/explode.cpp b/dlls/explode.cpp index 55dcb1c9..2427d108 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -217,7 +217,7 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); } - SetThink( Smoke ); + SetThink( &Smoke ); pev->nextthink = gpGlobals->time + 0.3; // draw sparks diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 4a1d20d6..b1cad808 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -164,9 +164,9 @@ void CBreakable::Spawn( void ) SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. - SetTouch( BreakTouch ); + SetTouch( &BreakTouch ); if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger - ResetTouch(); + SetTouch( NULL ); // Flag unbreakable glass as "worldbrush" so it will block ALL tracelines if ( !IsBreakable() && pev->rendermode != kRenderNormal ) @@ -445,7 +445,7 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) if (flDamage >= pev->health) { - ResetTouch(); + SetTouch( NULL ); TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); // do a little damage to player if we broke glass or computer @@ -459,8 +459,8 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) // play creaking sound here. DamageSound(); - SetThink ( Die ); - ResetTouch(); + SetThink( &Die ); + SetTouch( NULL ); if ( m_flDelay == 0 ) {// !!!BUGBUG - why doesn't zero delay work? @@ -743,7 +743,7 @@ void CBreakable::Die( void ) // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = pev->ltime + 0.1; if ( m_iszSpawnObject ) CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); @@ -977,7 +977,7 @@ void CPushable :: Move( CBaseEntity *pOther, int push ) { m_lastSound = RANDOM_LONG(0,2); EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM); - // SetThink( StopSound ); + // SetThink( &StopSound ); // pev->nextthink = pev->ltime + 0.1; } else diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index c448d9e8..ffe60c6b 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -161,7 +161,7 @@ void CStomp::Think( void ) 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( SUB_Remove ); + pSprite->SetThink( &SUB_Remove ); pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); } } @@ -1126,7 +1126,7 @@ void CGargantua::RunTask( Task_t *pTask ) pev->rendercolor.z = 0; StopAnimation(); pev->nextthink = gpGlobals->time + 0.15; - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); int i; int parts = MODEL_FRAMES( gGargGibModel ); for ( i = 0; i < 10; i++ ) @@ -1145,7 +1145,7 @@ void CGargantua::RunTask( Task_t *pTask ) pGib->pev->origin = pev->origin; pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); pGib->pev->nextthink = gpGlobals->time + 1.25; - pGib->SetThink( SUB_FadeOut ); + pGib->SetThink( &SUB_FadeOut ); } MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_BREAKMODEL); @@ -1359,7 +1359,7 @@ void SpawnExplosion( Vector center, float randomRange, float time, int magnitude pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; pExplosion->Spawn(); - pExplosion->SetThink( CBaseEntity::SUB_CallUseToggle ); + pExplosion->SetThink( &CBaseEntity::SUB_CallUseToggle ); pExplosion->pev->nextthink = gpGlobals->time + time; } diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index bed91293..c811207b 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -113,7 +113,7 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) } pev->effects |= EF_NODRAW; - SetThink( Smoke ); + SetThink( &Smoke ); pev->velocity = g_vecZero; pev->nextthink = gpGlobals->time + 0.3; @@ -156,7 +156,7 @@ void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) // Timed grenade, this think is called when time runs out. void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( Detonate ); + SetThink( &Detonate ); pev->nextthink = gpGlobals->time; } @@ -164,7 +164,7 @@ void CGrenade::PreDetonate( void ) { CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - SetThink( Detonate ); + SetThink( &Detonate ); pev->nextthink = gpGlobals->time + 1; } @@ -331,7 +331,7 @@ void CGrenade :: TumbleThink( void ) if (pev->dmgtime <= gpGlobals->time) { - SetThink( Detonate ); + SetThink( &Detonate ); } if (pev->waterlevel != 0) { @@ -368,14 +368,14 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->owner = ENT(pevOwner); // make monsters afaid of it while in the air - pGrenade->SetThink( DangerSoundThink ); + pGrenade->SetThink( &DangerSoundThink ); pGrenade->pev->nextthink = gpGlobals->time; // Tumble in air pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); // Explode on contact - pGrenade->SetTouch( ExplodeTouch ); + pGrenade->SetTouch( &ExplodeTouch ); pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; @@ -392,14 +392,14 @@ CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); pGrenade->pev->owner = ENT(pevOwner); - pGrenade->SetTouch( BounceTouch ); // Bounce if touched + pGrenade->SetTouch( &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( TumbleThink ); + pGrenade->SetThink( &TumbleThink ); pGrenade->pev->nextthink = gpGlobals->time + 0.1; if (time < 0.1) { @@ -442,9 +442,9 @@ CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, pGrenade->pev->owner = ENT(pevOwner); // Detonate in "time" seconds - pGrenade->SetThink( SUB_DoNothing ); - pGrenade->SetUse( DetonateUse ); - pGrenade->SetTouch( SlideTouch ); + pGrenade->SetThink( &SUB_DoNothing ); + pGrenade->SetUse( &DetonateUse ); + pGrenade->SetTouch( &SlideTouch ); pGrenade->pev->spawnflags = SF_DETONATE; pGrenade->pev->friction = 0.9; diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 3f2a9a29..68c97bd1 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -129,7 +129,7 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } pev->nextthink = pev->ltime + 0.25; - SetThink(Off); + SetThink( &Off); // Time to recharge yet? @@ -179,7 +179,7 @@ void CRecharge::Recharge(void) { m_iJuice = gSkillData.suitchargerCapacity; pev->frame = 0; - SetThink( SUB_DoNothing ); + SetThink( &SUB_DoNothing ); } void CRecharge::Off(void) @@ -193,8 +193,8 @@ void CRecharge::Off(void) if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) { pev->nextthink = pev->ltime + m_iReactivate; - SetThink(Recharge); + SetThink( &Recharge); } else - SetThink( SUB_DoNothing ); + SetThink( &SUB_DoNothing ); } \ No newline at end of file diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp index 7f681922..def27354 100644 --- a/dlls/h_cine.cpp +++ b/dlls/h_cine.cpp @@ -124,7 +124,7 @@ void CLegacyCineMonster :: CineSpawn( char *szModel ) // if no targetname, start now if ( FStringNull(pev->targetname) ) { - SetThink( CineThink ); + SetThink( &CineThink ); pev->nextthink += 1.0; } } @@ -136,7 +136,7 @@ void CLegacyCineMonster :: CineSpawn( char *szModel ) void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { pev->animtime = 0; // reset the sequence - SetThink( CineThink ); + SetThink( &CineThink ); pev->nextthink = gpGlobals->time; } @@ -145,7 +145,7 @@ void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, U // void CLegacyCineMonster :: Die( void ) { - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); } // @@ -228,14 +228,14 @@ void CCineBlood :: BloodGush ( void ) void CCineBlood :: BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( BloodGush ); + SetThink( &BloodGush ); pev->nextthink = gpGlobals->time;// now! } void CCineBlood :: Spawn ( void ) { pev->solid = SOLID_NOT; - SetUse ( BloodStart ); + SetUse( &BloodStart ); pev->health = 20;//hacked health to count iterations } diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index a306359f..d823488e 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -334,7 +334,7 @@ void CWeaponCycler::Spawn( ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch( DefaultTouch ); + SetTouch( &DefaultTouch ); } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 007ad662..2233b8a0 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -103,7 +103,7 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { // no more grenades! m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 809281aa..6f43965c 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -324,7 +324,7 @@ void CHeadCrab :: RunTask ( Task_t *pTask ) if ( m_fSequenceFinished ) { TaskComplete(); - ResetTouch(); + SetTouch( NULL ); m_IdealActivity = ACT_IDLE; } break; @@ -360,7 +360,7 @@ void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); } - ResetTouch(); + SetTouch( NULL ); } //========================================================= @@ -385,7 +385,7 @@ void CHeadCrab :: StartTask ( Task_t *pTask ) { EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch ( LeapTouch ); + SetTouch( &LeapTouch ); break; } default: diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 73931f28..fbf1d982 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -207,7 +207,7 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u } pev->nextthink = pev->ltime + 0.25; - SetThink(Off); + SetThink( &Off); // Time to recharge yet? @@ -243,7 +243,7 @@ void CWallHealth::Recharge(void) EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); m_iJuice = gSkillData.healthchargerCapacity; pev->frame = 0; - SetThink( SUB_DoNothing ); + SetThink( &SUB_DoNothing ); } void CWallHealth::Off(void) @@ -257,8 +257,8 @@ void CWallHealth::Off(void) if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) { pev->nextthink = pev->ltime + m_iReactivate; - SetThink(Recharge); + SetThink( &Recharge); } else - SetThink( SUB_DoNothing ); + SetThink( &SUB_DoNothing ); } \ No newline at end of file diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 0d2ca6c9..eab06752 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -2393,7 +2393,7 @@ void CHGruntRepel::Spawn( void ) Precache( ); pev->solid = SOLID_NOT; - SetUse( RepelUse ); + SetUse( &RepelUse ); } void CHGruntRepel::Precache( void ) @@ -2423,7 +2423,7 @@ void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( SUB_Remove ); + pBeam->SetThink( &SUB_Remove ); pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; UTIL_Remove( this ); diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index f27b79c5..f11dfb7f 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -93,8 +93,8 @@ void CHornet :: Spawn( void ) SET_MODEL(ENT( pev ), "models/hornet.mdl"); UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); - SetTouch( DieTouch ); - SetThink( StartTrack ); + SetTouch( &DieTouch ); + SetThink( &StartTrack ); edict_t *pSoundEnt = pev->owner; if ( !pSoundEnt ) @@ -169,8 +169,8 @@ void CHornet :: StartTrack ( void ) { IgniteTrail(); - SetTouch( TrackTouch ); - SetThink( TrackTarget ); + SetTouch( &TrackTouch ); + SetThink( &TrackTarget ); pev->nextthink = gpGlobals->time + 0.1; } @@ -182,9 +182,9 @@ void CHornet :: StartDart ( void ) { IgniteTrail(); - SetTouch( DartTouch ); + SetTouch( &DartTouch ); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 4; } @@ -256,8 +256,8 @@ void CHornet :: TrackTarget ( void ) if (gpGlobals->time > m_flStopAttack) { - ResetTouch(); - SetThink( SUB_Remove ); + SetTouch( NULL ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; return; } @@ -413,7 +413,7 @@ void CHornet::DieTouch ( CBaseEntity *pOther ) pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid pev->solid = SOLID_NOT; - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! } diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 76b48894..8eb58431 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -235,7 +235,7 @@ void CHgun::SecondaryAttack( void ) pHornet->pev->velocity = gpGlobals->v_forward * 1200; pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); - pHornet->SetThink( CHornet::StartDart ); + pHornet->SetThink( &CHornet::StartDart ); m_flRechargeTime = gpGlobals->time + 0.5; #endif diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index b88abf15..fa62e613 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -494,8 +494,8 @@ void CIchthyosaur :: Spawn() MonsterInit(); - SetTouch( BiteTouch ); - SetUse( CombatUse ); + SetTouch( &BiteTouch ); + SetUse( &CombatUse ); m_idealDist = 384; m_flMinSpeed = 80; diff --git a/dlls/items.cpp b/dlls/items.cpp index b1200ee9..fe88a53e 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -93,7 +93,7 @@ void CItem::Spawn( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch(ItemTouch); + SetTouch( &ItemTouch); if (DROP_TO_FLOOR(ENT(pev)) == 0) { @@ -125,7 +125,7 @@ void CItem::ItemTouch( CBaseEntity *pOther ) if (MyTouch( pPlayer )) { SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - ResetTouch(); + SetTouch( NULL ); // player grabbed the item. g_pGameRules->PlayerGotItem( pPlayer, this ); @@ -146,12 +146,12 @@ void CItem::ItemTouch( CBaseEntity *pOther ) CBaseEntity* CItem::Respawn( void ) { - ResetTouch(); + SetTouch( NULL ); pev->effects |= EF_NODRAW; UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. - SetThink ( Materialize ); + SetThink( &Materialize ); pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); return this; } @@ -166,7 +166,7 @@ void CItem::Materialize( void ) pev->effects |= EF_MUZZLEFLASH; } - SetTouch( ItemTouch ); + SetTouch( &ItemTouch ); } #define SF_SUIT_SHORTLOGON 0x0001 diff --git a/dlls/leech.cpp b/dlls/leech.cpp index 73e233e9..6c13e08d 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -196,9 +196,9 @@ void CLeech::Spawn( void ) m_flFieldOfView = -0.5; // 180 degree FOV m_flDistLook = 750; MonsterInit(); - SetThink( SwimThink ); - ResetUse(); - ResetTouch(); + SetThink( &SwimThink ); + SetUse( NULL ); + SetTouch( NULL ); pev->view_ofs = g_vecZero; m_flTurning = 0; @@ -426,7 +426,7 @@ void CLeech::DeadThink( void ) { if ( m_Activity == ACT_DIEFORWARD ) { - ResetThink(); + SetThink( NULL ); StopAnimation(); return; } @@ -717,7 +717,7 @@ void CLeech::Killed(entvars_t *pevAttacker, int iGib) pev->movetype = MOVETYPE_TOSS; pev->takedamage = DAMAGE_NO; - SetThink( DeadThink ); + SetThink( &DeadThink ); } diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index 1ee8b708..43513d0a 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -111,29 +111,29 @@ void CMonsterMaker :: Spawn( ) { if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) { - SetUse ( CyclicUse );// drop one monster each time we fire + SetUse( &CyclicUse );// drop one monster each time we fire } else { - SetUse ( ToggleUse );// so can be turned on/off + SetUse( &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 ( MakerThink ); + SetThink( &MakerThink ); } else {// wait to be activated. m_fActive = FALSE; - SetThink ( SUB_DoNothing ); + SetThink( &SUB_DoNothing ); } } else {// no targetname, just start. pev->nextthink = gpGlobals->time + m_flDelay; m_fActive = TRUE; - SetThink ( MakerThink ); + SetThink( &MakerThink ); } if ( m_cNumMonsters == 1 ) @@ -229,8 +229,8 @@ void CMonsterMaker::MakeMonster( void ) if ( m_cNumMonsters == 0 ) { // Disable this forever. Don't kill it because it still gets death notices - ResetThink(); - ResetUse(); + SetThink( NULL ); + SetUse( NULL ); } } @@ -254,12 +254,12 @@ void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, if ( m_fActive ) { m_fActive = FALSE; - ResetThink(); + SetThink( NULL ); } else { m_fActive = TRUE; - SetThink ( MakerThink ); + SetThink( &MakerThink ); } pev->nextthink = gpGlobals->time; diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index 8c734de3..ad64189d 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -2044,9 +2044,9 @@ void CBaseMonster :: MonsterInit ( void ) // set eye position SetEyePosition(); - SetThink( MonsterInitThink ); + SetThink( &MonsterInitThink ); pev->nextthink = gpGlobals->time + 0.1; - SetUse ( MonsterUse ); + SetUse( &MonsterUse ); } //========================================================= @@ -2146,7 +2146,7 @@ void CBaseMonster :: StartMonster ( void ) // 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 ( CallMonsterThink ); + SetThink( &CallMonsterThink ); pev->nextthink += RANDOM_FLOAT(0.1, 0.4); // spread think times. if ( !FStringNull(pev->targetname) )// wait until triggered @@ -3259,7 +3259,7 @@ void CBaseMonster::CorpseFallThink( void ) { if ( pev->flags & FL_ONGROUND ) { - ResetThink(); + SetThink( NULL ); SetSequenceBox( ); UTIL_SetOrigin( pev, pev->origin );// link into world. @@ -3289,7 +3289,7 @@ void CBaseMonster :: MonsterInitDead( void ) // Setup health counters, etc. BecomeDead(); - SetThink( CorpseFallThink ); + SetThink( &CorpseFallThink ); pev->nextthink = gpGlobals->time + 0.5; } diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index e23d7b60..d1d64825 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -105,7 +105,7 @@ void CFuncMortarField :: Spawn( void ) SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world pev->movetype = MOVETYPE_NONE; SetBits( pev->effects, EF_NODRAW ); - SetUse( FieldUse ); + SetUse( &FieldUse ); Precache(); } @@ -209,7 +209,7 @@ void CMortar::Spawn( ) pev->dmg = 200; - SetThink( MortarExplode ); + SetThink( &MortarExplode ); pev->nextthink = 0; Precache( ); @@ -300,7 +300,7 @@ void CMortar::MortarExplode( void ) } */ - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; #endif diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index 36d0ff94..bd5ee369 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -50,7 +50,7 @@ void CBaseMonster::CorpseFallThink( void ) { if ( pev->flags & FL_ONGROUND ) { - ResetThink(); + SetThink( NULL ); SetSequenceBox( ); UTIL_SetOrigin( pev, pev->origin );// link into world. @@ -79,7 +79,7 @@ void CBaseMonster :: MonsterInitDead( void ) // Setup health counters, etc. BecomeDead(); - SetThink( CorpseFallThink ); + SetThink( &CorpseFallThink ); pev->nextthink = gpGlobals->time + 0.5; } diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index b054e125..8e7859eb 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -300,7 +300,7 @@ void CNihilanth :: Spawn( void ) InitBoneControllers(); - SetThink( StartupThink ); + SetThink( &StartupThink ); pev->nextthink = gpGlobals->time + 0.1; m_vecDesired = Vector( 1, 0, 0 ); @@ -378,9 +378,9 @@ void CNihilanth::NullThink( void ) void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( HuntThink ); + SetThink( &HuntThink ); pev->nextthink = gpGlobals->time + 0.1; - SetUse( CommandUse ); + SetUse( &CommandUse ); } @@ -410,8 +410,8 @@ void CNihilanth::StartupThink( void ) } m_hRecharger = NULL; - SetThink( HuntThink); - SetUse( CommandUse ); + SetThink( &HuntThink); + SetUse( &CommandUse ); pev->nextthink = gpGlobals->time + 0.1; } @@ -544,7 +544,7 @@ void CNihilanth::CrashTouch( CBaseEntity *pOther ) // only crash if we hit something solid if ( pOther->pev->solid == SOLID_BSP) { - ResetTouch(); + SetTouch( NULL ); pev->nextthink = gpGlobals->time; } } @@ -846,7 +846,7 @@ void CNihilanth :: HuntThink( void ) // if dead, force cancelation of current animation if (pev->health <= 0) { - SetThink( DyingThink ); + SetThink( &DyingThink ); m_fSequenceFinished = TRUE; return; } @@ -1330,8 +1330,8 @@ void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( HoverThink ); - SetTouch( BounceTouch ); + SetThink( &HoverThink ); + SetTouch( &BounceTouch ); pev->nextthink = gpGlobals->time + 0.1; m_hTargetEnt = pTarget; @@ -1433,8 +1433,8 @@ void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) pev->velocity = (pEnemy->pev->origin - pev->origin).Normalize() * 200; m_hEnemy = pEnemy; - SetThink( ZapThink ); - SetTouch( ZapTouch ); + SetThink( &ZapThink ); + SetTouch( &ZapTouch ); pev->nextthink = gpGlobals->time + 0.1; EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); @@ -1447,7 +1447,7 @@ void CNihilanthHVR :: ZapThink( void ) // check world boundaries if (m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) { - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); return; } @@ -1495,7 +1495,7 @@ void CNihilanthHVR :: ZapThink( void ) UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); pev->nextthink = gpGlobals->time + 0.2; return; @@ -1535,7 +1535,7 @@ void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) } */ - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); pev->nextthink = gpGlobals->time + 0.2; } @@ -1559,8 +1559,8 @@ void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBa m_hTargetEnt = pTarget; m_hTouch = pTouch; - SetThink( TeleportThink ); - SetTouch( TeleportTouch ); + SetThink( &TeleportThink ); + SetTouch( &TeleportTouch ); pev->nextthink = gpGlobals->time + 0.1; EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); @@ -1579,7 +1579,7 @@ void CNihilanthHVR :: GreenBallInit( ) SET_MODEL(edict(), "sprites/exit1.spr"); - SetTouch( RemoveTouch ); + SetTouch( &RemoveTouch ); } @@ -1631,7 +1631,7 @@ void CNihilanthHVR :: TeleportThink( void ) void CNihilanthHVR :: AbsorbInit( void ) { - SetThink( DissipateThink ); + SetThink( &DissipateThink ); pev->renderamt = 255; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -1669,7 +1669,7 @@ void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) m_pNihilanth->MakeFriend( pev->origin ); } - ResetTouch(); + SetTouch( NULL ); STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); UTIL_Remove( this ); } diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index c3f896ca..058260b3 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -1459,12 +1459,12 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode ) if ( WorldGraph.m_fGraphPresent ) {// graph loaded from disk, so we don't need the test hull - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } else { - SetThink ( DropDelay ); + SetThink( &DropDelay ); pev->nextthink = gpGlobals->time + 1; } @@ -1484,7 +1484,7 @@ void CTestHull::DropDelay ( void ) UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); - SetThink ( CallBuildNodeGraph ); + SetThink( &CallBuildNodeGraph ); pev->nextthink = gpGlobals->time + 1; } @@ -1632,7 +1632,7 @@ void CTestHull :: BuildNodeGraph( void ) float flDist; int step; - SetThink ( SUB_Remove );// no matter what happens, the hull gets rid of itself. + SetThink( &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. @@ -1744,7 +1744,7 @@ void CTestHull :: BuildNodeGraph( void ) { ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - SetThink ( ShowBadNode );// send the hull off to show the offending node. + SetThink( &ShowBadNode );// send the hull off to show the offending node. //pev->solid = SOLID_NOT; pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; @@ -3559,7 +3559,7 @@ void CNodeViewer::Spawn( ) ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); m_iDraw = 0; - SetThink( DrawThink ); + SetThink( &DrawThink ); pev->nextthink = gpGlobals->time; } diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index 6dc263d3..b85fadda 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -167,8 +167,8 @@ void COsprey :: Spawn( void ) InitBoneControllers(); - SetThink( FindAllThink ); - SetUse( CommandUse ); + SetThink( &FindAllThink ); + SetUse( &CommandUse ); if (!(pev->spawnflags & SF_WAITFORTRIGGER)) { @@ -225,7 +225,7 @@ void COsprey :: FindAllThink( void ) UTIL_Remove( this ); return; } - SetThink( FlyThink ); + SetThink( &FlyThink ); pev->nextthink = gpGlobals->time + 0.1; m_startTime = gpGlobals->time; } @@ -257,7 +257,7 @@ void COsprey :: DeployThink( void ) vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; m_hRepel[3] = MakeGrunt( vecSrc ); - SetThink( HoverThink ); + SetThink( &HoverThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -308,7 +308,7 @@ CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( SUB_Remove ); + pBeam->SetThink( &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 ); @@ -336,7 +336,7 @@ void COsprey :: HoverThink( void ) if (i == 4) { m_startTime = gpGlobals->time; - SetThink( FlyThink ); + SetThink( &FlyThink ); } pev->nextthink = gpGlobals->time + 0.1; @@ -396,7 +396,7 @@ void COsprey::FlyThink( void ) { if (m_pGoalEnt->pev->speed == 0) { - SetThink( DeployThink ); + SetThink( &DeployThink ); } do { m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( m_pGoalEnt->pev->target ) ) ); @@ -518,8 +518,8 @@ void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( DyingThink ); - SetTouch( CrashTouch ); + SetThink( &DyingThink ); + SetTouch( &CrashTouch ); pev->nextthink = gpGlobals->time + 0.1; pev->health = 0; pev->takedamage = DAMAGE_NO; @@ -532,7 +532,7 @@ void COsprey::CrashTouch( CBaseEntity *pOther ) // only crash if we hit something solid if ( pOther->pev->solid == SOLID_BSP) { - ResetTouch(); + SetTouch( NULL ); m_startTime = gpGlobals->time; pev->nextthink = gpGlobals->time; m_velocity = pev->velocity; diff --git a/dlls/pathcorner.cpp b/dlls/pathcorner.cpp index b7216720..498550de 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -221,7 +221,7 @@ void CPathTrack :: Spawn( void ) m_pprevious = NULL; // DEBUGGING CODE #if PATH_SPARKLE_DEBUG - SetThink( Sparkle ); + SetThink( &Sparkle ); pev->nextthink = gpGlobals->time + 0.5; #endif } diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 418f64e9..5b62d79b 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -328,7 +328,7 @@ void CFuncPlat :: Spawn( ) { UTIL_SetOrigin (pev, m_vecPosition1); m_toggle_state = TS_AT_TOP; - SetUse( PlatUse ); + SetUse( &PlatUse ); } else { @@ -417,7 +417,7 @@ void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } else { - ResetUse(); + SetUse( NULL ); if (m_toggle_state == TS_AT_TOP) GoDown(); @@ -435,7 +435,7 @@ void CFuncPlat :: GoDown( void ) ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); m_toggle_state = TS_GOING_DOWN; - SetMoveDone(CallHitBottom); + SetMoveDone( &CallHitBottom); LinearMove(m_vecPosition2, pev->speed); } @@ -466,7 +466,7 @@ void CFuncPlat :: GoUp( void ) ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); m_toggle_state = TS_GOING_UP; - SetMoveDone(CallHitTop); + SetMoveDone( &CallHitTop); LinearMove(m_vecPosition1, pev->speed); } @@ -488,7 +488,7 @@ void CFuncPlat :: HitTop( void ) if ( !IsTogglePlat() ) { // After a delay, the platform will automatically start going down again. - SetThink( CallGoDown ); + SetThink( &CallGoDown ); pev->nextthink = pev->ltime + 3; } } @@ -738,7 +738,7 @@ void CFuncTrain :: Wait( void ) 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( Next ); + SetThink( &Next ); } else { @@ -802,7 +802,7 @@ void CFuncTrain :: Next( void ) if ( pev->noiseMovement ) EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); ClearBits(pev->effects, EF_NOINTERP); - SetMoveDone( Wait ); + SetMoveDone( &Wait ); LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); } } @@ -824,7 +824,7 @@ void CFuncTrain :: Activate( void ) if ( FStringNull(pev->targetname) ) { // not triggered, so start immediately pev->nextthink = pev->ltime + 0.1; - SetThink( Next ); + SetThink( &Next ); } else pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; @@ -920,7 +920,7 @@ void CFuncTrain::OverrideReset( void ) } else // Keep moving for 0.1 secs, then find path_corner again and restart { - SetThink( Next ); + SetThink( &Next ); pev->nextthink = pev->ltime + 0.1; } } @@ -1047,7 +1047,7 @@ void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ pev->velocity = g_vecZero; pev->avelocity = g_vecZero; StopSound(); - ResetThink(); + SetThink( NULL ); } } else @@ -1262,7 +1262,7 @@ void CFuncTrackTrain :: Next( void ) } } - SetThink( Next ); + SetThink( &Next ); NextThink( pev->ltime + time, TRUE ); } else // end of path, stop @@ -1284,7 +1284,7 @@ void CFuncTrackTrain :: Next( void ) // no, how long to get there? time = distance / m_oldSpeed; pev->velocity = pev->velocity * (m_oldSpeed / distance); - SetThink( DeadEnd ); + SetThink( &DeadEnd ); NextThink( pev->ltime + time, FALSE ); } else @@ -1402,7 +1402,7 @@ void CFuncTrackTrain :: Find( void ) pev->angles.x = 0; UTIL_SetOrigin( pev, nextPos ); NextThink( pev->ltime + 0.1, FALSE ); - SetThink( Next ); + SetThink( &Next ); pev->speed = m_startSpeed; UpdateSound(); @@ -1434,7 +1434,7 @@ void CFuncTrackTrain :: NearestPath( void ) if ( !pNearest ) { ALERT( at_console, "Can't find a nearby track !!!\n" ); - ResetThink(); + SetThink( NULL ); return; } @@ -1452,7 +1452,7 @@ void CFuncTrackTrain :: NearestPath( void ) if ( pev->speed != 0 ) { NextThink( pev->ltime + 0.1, FALSE ); - SetThink( Next ); + SetThink( &Next ); } } @@ -1460,7 +1460,7 @@ void CFuncTrackTrain :: NearestPath( void ) void CFuncTrackTrain::OverrideReset( void ) { NextThink( pev->ltime + 0.1, FALSE ); - SetThink( NearestPath ); + SetThink( &NearestPath ); } @@ -1519,7 +1519,7 @@ void CFuncTrackTrain :: Spawn( void ) // 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( Find ); + SetThink( &Find ); Precache(); } @@ -1589,7 +1589,7 @@ void CFuncTrainControls :: Spawn( void ) UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); - SetThink( Find ); + SetThink( &Find ); pev->nextthink = gpGlobals->time; } @@ -1701,7 +1701,7 @@ void CFuncTrackChange :: Spawn( void ) EnableUse(); pev->nextthink = pev->ltime + 2.0; - SetThink( Find ); + SetThink( &Find ); Precache(); } @@ -1752,7 +1752,7 @@ void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) void CFuncTrackChange::OverrideReset( void ) { pev->nextthink = pev->ltime + 1.0; - SetThink( Find ); + SetThink( &Find ); } void CFuncTrackChange :: Find( void ) @@ -1781,7 +1781,7 @@ void CFuncTrackChange :: Find( void ) m_trackBottom = m_trackBottom->Nearest( center ); m_trackTop = m_trackTop->Nearest( center ); UpdateAutoTargets( m_toggle_state ); - ResetThink(); + SetThink( NULL ); return; } else @@ -1862,14 +1862,14 @@ void CFuncTrackChange :: GoDown( void ) // If ROTMOVE, move & rotate if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { - SetMoveDone( CallHitBottom ); + SetMoveDone( &CallHitBottom ); m_toggle_state = TS_GOING_DOWN; AngularMove( m_start, pev->speed ); } else { CFuncPlat :: GoDown(); - SetMoveDone( CallHitBottom ); + SetMoveDone( &CallHitBottom ); RotMove( m_start, pev->nextthink - pev->ltime ); } // Otherwise, rotate first, move second @@ -1898,14 +1898,14 @@ void CFuncTrackChange :: GoUp( void ) if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { m_toggle_state = TS_GOING_UP; - SetMoveDone( CallHitTop ); + SetMoveDone( &CallHitTop ); AngularMove( m_end, pev->speed ); } else { // If ROTMOVE, move & rotate CFuncPlat :: GoUp(); - SetMoveDone( CallHitTop ); + SetMoveDone( &CallHitTop ); RotMove( m_end, pev->nextthink - pev->ltime ); } @@ -1980,7 +1980,7 @@ void CFuncTrackChange :: HitBottom( void ) // UpdateTrain(); m_train->SetTrack( m_trackBottom ); } - ResetThink(); + SetThink( NULL ); pev->nextthink = -1; UpdateAutoTargets( m_toggle_state ); @@ -2002,7 +2002,7 @@ void CFuncTrackChange :: HitTop( void ) } // Don't let the plat go back down - ResetThink(); + SetThink( NULL ); pev->nextthink = -1; UpdateAutoTargets( m_toggle_state ); EnableUse(); @@ -2160,7 +2160,7 @@ void CGunTarget::Spawn( void ) if ( pev->spawnflags & FGUNTARGET_START_ON ) { - SetThink( Start ); + SetThink( &Start ); pev->nextthink = pev->ltime + 0.3; } } @@ -2188,7 +2188,7 @@ void CGunTarget::Start( void ) void CGunTarget::Next( void ) { - ResetThink(); + SetThink( NULL ); m_hTargetEnt = GetNextTarget(); CBaseEntity *pTarget = m_hTargetEnt; @@ -2198,7 +2198,7 @@ void CGunTarget::Next( void ) Stop(); return; } - SetMoveDone( Wait ); + SetMoveDone( &Wait ); LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); } @@ -2224,7 +2224,7 @@ void CGunTarget::Wait( void ) m_flWait = pTarget->GetDelay(); pev->target = pTarget->pev->target; - SetThink( Next ); + SetThink( &Next ); if (m_flWait != 0) {// -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; diff --git a/dlls/player.cpp b/dlls/player.cpp index 3fc7d177..8ff7a395 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -774,7 +774,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. pWeaponBox->pev->angles.z = 0; - pWeaponBox->SetThink( CWeaponBox::Kill ); + pWeaponBox->SetThink( &CWeaponBox::Kill ); pWeaponBox->pev->nextthink = gpGlobals->time + 120; // back these two lists up to their first elements @@ -933,7 +933,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) pev->angles.x = 0; pev->angles.z = 0; - SetThink(PlayerDeathThink); + SetThink( &PlayerDeathThink); pev->nextthink = gpGlobals->time + 0.1; } @@ -3209,7 +3209,7 @@ void CBloodSplat::Spawn ( entvars_t *pevOwner ) pev->angles = pevOwner->v_angle; pev->owner = ENT(pevOwner); - SetThink ( Spray ); + SetThink( &Spray ); pev->nextthink = gpGlobals->time + 0.1; } @@ -3224,7 +3224,7 @@ void CBloodSplat::Spray ( void ) UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); } - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -3587,7 +3587,7 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) if ( pEntity ) { if ( pEntity->pev->takedamage ) - pEntity->SetThink(SUB_Remove); + pEntity->SetThink( &SUB_Remove); } break; } @@ -3663,7 +3663,7 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) ResetAutoaim( ); pItem->Holster( ); pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. - pItem->ResetThink(); + pItem->SetThink( NULL ); m_pActiveItem = NULL; pev->viewmodel = 0; pev->weaponmodel = 0; @@ -4726,7 +4726,7 @@ void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP { UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); pev->nextthink = gpGlobals->time + MessageTime(); - SetThink( MessageThink ); + SetThink( &MessageThink ); } @@ -4737,7 +4737,7 @@ void CRevertSaved :: MessageThink( void ) if ( nextThink > 0 ) { pev->nextthink = gpGlobals->time + nextThink; - SetThink( LoadThink ); + SetThink( &LoadThink ); } else LoadThink(); diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 3f4f0a98..56671736 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -566,7 +566,7 @@ void CProp::Killed(entvars_t *pevAttacker, int iGib) pev->solid = SOLID_NOT; pev->effects |= EF_NODRAW; pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( CProp::RespawnThink ); + SetThink( &CProp::RespawnThink ); ResetTouch( ); ResetUse( ); } @@ -605,7 +605,7 @@ void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, m_pHolstered->pev->weaponmodel = 0; m_pHolstered->pev->viewmodel = 0; } - SetThink( CProp::DeployThink ); + SetThink( &CProp::DeployThink ); pev->nextthink = gpGlobals->time + 0.2; } } @@ -664,7 +664,7 @@ void CProp::Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp } pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink(CProp::RespawnThink); + SetThink( &CProp::RespawnThink); } void CProp::CheckRotate() @@ -739,7 +739,7 @@ void CProp::DeployThink( void ) if( m_pfnThink == &CProp::DeployThink ) { pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( CProp::RespawnThink ); + SetThink( &CProp::RespawnThink ); } } @@ -899,8 +899,8 @@ void CProp::PropRespawn() m_oldshape = (PropShape)-1; CheckRotate(); pev->health = m_flSpawnHealth; - SetTouch(CProp::BounceTouch); - SetUse(CProp::Use); + SetTouch( &CProp::BounceTouch); + SetUse( &CProp::Use); pev->effects &= ~EF_NODRAW; pev->framerate = 1.0f; } @@ -917,7 +917,7 @@ void CProp::RespawnThink() void CProp::AngleThink() { pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink(CProp::RespawnThink); + SetThink( &CProp::RespawnThink); if (!(pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40)) { m_owner2 = m_attacker = 0; @@ -928,7 +928,7 @@ void CProp::AngleThink() pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) { - SetThink(CProp::AngleThink); + SetThink( &CProp::AngleThink); pev->nextthink = gpGlobals->time + 0.1; } //ALERT( at_console, "AngleThink: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); @@ -938,7 +938,7 @@ void CProp::AngleThink() { if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) { - SetThink(CProp::AngleThink); + SetThink( &CProp::AngleThink); pev->nextthink = gpGlobals->time + 0.1; } pev->angles.z += UTIL_AngleDiff(0, pev->angles.z) * 0.7; @@ -955,7 +955,7 @@ void CProp::AngleThink() //fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) { - SetThink(CProp::AngleThink); + SetThink( &CProp::AngleThink); pev->nextthink = gpGlobals->time + 0.1; } pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; @@ -972,7 +972,7 @@ void CProp::AngleThink() fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) { - SetThink(CProp::AngleThink); + SetThink( &CProp::AngleThink); pev->nextthink = gpGlobals->time + 0.1; } pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; @@ -1006,7 +1006,7 @@ void CProp::AngleThink() if (fabs(UTIL_AngleDiff(ianglex, pev->angles.x)) > 0.1 || fabs(UTIL_AngleDiff(ianglez, pev->angles.z)) > 0.1 ) { - SetThink(CProp::AngleThink); + SetThink( &CProp::AngleThink); pev->nextthink = gpGlobals->time + 0.1; } pev->angles.x += UTIL_AngleDiff(ianglex, pev->angles.x) * 0.6; diff --git a/dlls/replace.sh b/dlls/replace.sh new file mode 100644 index 00000000..90971faa --- /dev/null +++ b/dlls/replace.sh @@ -0,0 +1,5 @@ +f="effects.h *.cpp" +for m in SetThink SetTouch SetUse SetBlocked SetMoveDone; do +m2=`echo $m|sed -e s/Set/Reset/` +sed -e s/$m[[:space:]]\*\([[:space:]]\*/$m\(/g -e s/$m\([[:space:]]\*\\\&/$m\(/g -e s/$m\([[:space:]]\*NULL[[:space:]]\)/$m2\(\)/g -e s/$m\([[:space:]]*/$m\(\ \\\&/g -e s/$m2\(\)/$m\(\ NULL\ \)/g -i $f +done diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index a14eaa3c..e13af4ab 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -80,7 +80,7 @@ void CLaserSpot::Suspend( float flSuspendTime ) { pev->effects |= EF_NODRAW; - SetThink( Revive ); + SetThink( &Revive ); pev->nextthink = gpGlobals->time + flSuspendTime; } @@ -91,7 +91,7 @@ void CLaserSpot::Revive( void ) { pev->effects &= ~EF_NODRAW; - ResetThink(); + SetThink( NULL ); } void CLaserSpot::Precache( void ) @@ -110,7 +110,7 @@ CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBa UTIL_SetOrigin( pRocket->pev, vecOrigin ); pRocket->pev->angles = vecAngles; pRocket->Spawn(); - pRocket->SetTouch( CRpgRocket::RocketTouch ); + 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(); @@ -133,8 +133,8 @@ void CRpgRocket :: Spawn( void ) pev->classname = MAKE_STRING("rpg_rocket"); - SetThink( IgniteThink ); - SetTouch( ExplodeTouch ); + SetThink( &IgniteThink ); + SetTouch( &ExplodeTouch ); pev->angles.x -= 30; UTIL_MakeVectors( pev->angles ); @@ -200,7 +200,7 @@ void CRpgRocket :: IgniteThink( void ) m_flIgniteTime = gpGlobals->time; // set to follow laser spot - SetThink( FollowThink ); + SetThink( &FollowThink ); pev->nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 7c5ff451..0bd6513d 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -77,9 +77,9 @@ void CSatchelCharge :: Spawn( void ) 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( SatchelSlide ); - SetUse( DetonateUse ); - SetThink( SatchelThink ); + SetTouch( &SatchelSlide ); + SetUse( &DetonateUse ); + SetThink( &SatchelThink ); pev->nextthink = gpGlobals->time + 0.1; pev->gravity = 0.5; @@ -322,7 +322,7 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) { m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } } diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index 75886699..f1eb367d 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -454,7 +454,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { pev->deadflag = DEAD_DEAD; - ResetThink(); + SetThink( NULL ); StopAnimation(); if ( !BBoxFlat() ) diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index b80623ff..5b1742b3 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -686,7 +686,7 @@ void CScientist :: Spawn( void ) pev->skin = 1; MonsterInit(); - SetUse( FollowerUse ); + SetUse( &FollowerUse ); } //========================================================= @@ -813,7 +813,7 @@ void CScientist :: DeathSound ( void ) void CScientist::Killed( entvars_t *pevAttacker, int iGib ) { - ResetUse(); + SetUse( NULL ); CTalkMonster::Killed( pevAttacker, iGib ); } @@ -1240,7 +1240,7 @@ void CSittingScientist :: Spawn( ) pev->sequence = m_baseSequence + RANDOM_LONG(0,4); ResetSequenceInfo( ); - SetThink (SittingThink); + SetThink( &SittingThink); pev->nextthink = gpGlobals->time + 0.1; DROP_TO_FLOOR ( ENT(pev) ); diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index 3767a508..817e1f79 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -142,7 +142,7 @@ void CCineMonster :: Spawn( void ) // if no targetname, start now if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) { - SetThink( CineThink ); + SetThink( &CineThink ); pev->nextthink = gpGlobals->time + 1.0; // Wait to be used? if ( pev->targetname ) @@ -198,7 +198,7 @@ void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP else { // if not, try finding them - SetThink( CineThink ); + SetThink( &CineThink ); pev->nextthink = gpGlobals->time; } } @@ -253,7 +253,7 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) // void CCineMonster :: Die( void ) { - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); } // @@ -564,7 +564,7 @@ void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) { - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -827,12 +827,12 @@ BOOL CBaseMonster :: CineCleanup( ) if ( pOldCine && FBitSet( pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE ) ) { - ResetUse(); // BUGBUG -- This doesn't call Killed() - ResetThink(); // This will probably break some stuff - ResetTouch(); + SetUse( NULL ); // BUGBUG -- This doesn't call Killed() + SetThink( NULL ); // This will probably break some stuff + SetTouch( NULL ); } else - SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); + 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; @@ -1026,7 +1026,7 @@ void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, US if ( !m_active ) return; // ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); - SetThink( FindThink ); + SetThink( &FindThink ); pev->nextthink = gpGlobals->time; } @@ -1039,7 +1039,7 @@ void CScriptedSentence :: Spawn( void ) // if no targetname, start now if ( !pev->targetname ) { - SetThink( FindThink ); + SetThink( &FindThink ); pev->nextthink = gpGlobals->time + 1.0; } @@ -1078,7 +1078,7 @@ void CScriptedSentence :: FindThink( void ) StartSentence( pMonster ); if ( pev->spawnflags & SF_SENTENCE_ONCE ) UTIL_Remove( this ); - SetThink( DelayThink ); + SetThink( &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) ); @@ -1096,7 +1096,7 @@ void CScriptedSentence :: DelayThink( void ) m_active = TRUE; if ( !pev->targetname ) pev->nextthink = gpGlobals->time + 0.1; - SetThink( FindThink ); + SetThink( &FindThink ); } @@ -1219,7 +1219,7 @@ LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); //========================================================= void CFurniture :: Die ( void ) { - SetThink ( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time; } @@ -1242,7 +1242,7 @@ void CFurniture :: Spawn( ) pev->frame = 0; // pev->nextthink += 1.0; -// SetThink (WalkMonsterDelay); +// SetThink( &WalkMonsterDelay); ResetSequenceInfo( ); pev->frame = 0; diff --git a/dlls/sound.cpp b/dlls/sound.cpp index b02381e5..01038247 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -193,7 +193,7 @@ void CAmbientGeneric :: Spawn( void ) { 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( SUB_Remove ); + SetThink( &SUB_Remove ); return; } pev->solid = SOLID_NOT; @@ -203,12 +203,12 @@ void CAmbientGeneric :: Spawn( void ) // of ambient sound's pitch or volume. Don't // start thinking yet. - SetThink(RampThink); + SetThink( &RampThink); pev->nextthink = 0; // allow on/off switching via 'use' function. - SetUse ( ToggleUse ); + SetUse( &ToggleUse ); m_fActive = FALSE; @@ -1824,19 +1824,19 @@ void CSpeaker :: Spawn( void ) { 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( SUB_Remove ); + SetThink( &SUB_Remove ); return; } pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; - SetThink(SpeakerThink); + SetThink( &SpeakerThink); pev->nextthink = 0.0; // allow on/off switching via 'use' function. - SetUse ( ToggleUse ); + SetUse( &ToggleUse ); Precache( ); } diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index b3b34edc..0eacb2d8 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -120,8 +120,8 @@ void CSqueakGrenade :: Spawn( void ) UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( SuperBounceTouch ); - SetThink( HuntThink ); + SetTouch( &SuperBounceTouch ); + SetThink( &HuntThink ); pev->nextthink = gpGlobals->time + 0.1; m_flNextHunt = gpGlobals->time + 1E6; @@ -162,8 +162,8 @@ void CSqueakGrenade::Precache( void ) void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible - SetThink( SUB_Remove ); - ResetTouch(); + SetThink( &SUB_Remove ); + SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; // since squeak grenades never leave a body behind, clear out their takedamage now. @@ -203,7 +203,7 @@ void CSqueakGrenade::HuntThink( void ) if (!IsInWorld()) { - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); return; } @@ -483,7 +483,7 @@ void CSqueak::Holster( int skiplocal /* = 0 */ ) if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) { m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; return; } diff --git a/dlls/subs.cpp b/dlls/subs.cpp index a1093661..b48fc0f4 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -231,7 +231,7 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl pTemp->pev->nextthink = gpGlobals->time + m_flDelay; - pTemp->SetThink( DelayThink ); + pTemp->SetThink( &DelayThink ); // Save the useType pTemp->pev->button = (int)useType; @@ -413,7 +413,7 @@ void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) // set nextthink to trigger a call to LinearMoveDone when dest is reached pev->nextthink = pev->ltime + flTravelTime; - SetThink( LinearMoveDone ); + SetThink( &LinearMoveDone ); // scale the destdelta vector by the time spent traveling to get velocity pev->velocity = vecDestDelta / flTravelTime; @@ -473,7 +473,7 @@ void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) // set nextthink to trigger a call to AngularMoveDone when dest is reached pev->nextthink = pev->ltime + flTravelTime; - SetThink( AngularMoveDone ); + SetThink( &AngularMoveDone ); // scale the destdelta vector by the time spent traveling to get velocity pev->avelocity = vecDestDelta / flTravelTime; diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index bf4bbe87..76ac05b7 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -640,7 +640,7 @@ void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) m_hTargetEnt = NULL; // Don't finish that sentence StopTalking(); - ResetUse(); + SetUse( NULL ); CBaseMonster::Killed( pevAttacker, iGib ); } diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index ef3ab574..921a7b7d 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -265,9 +265,9 @@ void CTentacle :: Spawn( ) m_bloodColor = BLOOD_COLOR_GREEN; - SetThink( Start ); - SetTouch( HitTouch ); - SetUse( CommandUse ); + SetThink( &Start ); + SetTouch( &HitTouch ); + SetUse( &CommandUse ); pev->nextthink = gpGlobals->time + 0.2; @@ -288,7 +288,7 @@ void CTentacle :: Spawn( ) m_MonsterState = MONSTERSTATE_IDLE; - // SetThink( Test ); + // SetThink( &Test ); UTIL_SetOrigin( pev, pev->origin ); } @@ -714,7 +714,7 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T { case USE_OFF: pev->takedamage = DAMAGE_NO; - SetThink( DieThink ); + SetThink( &DieThink ); m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; break; case USE_ON: @@ -728,7 +728,7 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T break; case USE_TOGGLE: pev->takedamage = DAMAGE_NO; - SetThink( DieThink ); + SetThink( &DieThink ); m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; break; } @@ -926,7 +926,7 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) // void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) void CTentacle :: Start( void ) { - SetThink( Cycle ); + SetThink( &Cycle ); if ( !g_fFlySound ) { diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index a75cbbca..d7c82806 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -73,7 +73,7 @@ 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( ChangeFriction ); + SetTouch( &ChangeFriction ); } @@ -344,8 +344,8 @@ void CMultiManager :: KeyValue( KeyValueData *pkvd ) void CMultiManager :: Spawn( void ) { pev->solid = SOLID_NOT; - SetUse ( ManagerUse ); - SetThink ( ManagerThink); + SetUse( &ManagerUse ); + SetThink( &ManagerThink); // Sort targets // Quick and dirty bubble sort @@ -397,13 +397,13 @@ void CMultiManager :: ManagerThink ( void ) if ( m_index >= m_cTargets )// have we fired all targets? { - ResetThink(); + SetThink( NULL ); if ( IsClone() ) { UTIL_Remove( this ); return; } - SetUse ( ManagerUse );// allow manager re-use + SetUse( &ManagerUse );// allow manager re-use } else pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; @@ -442,9 +442,9 @@ void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller m_index = 0; m_startTime = gpGlobals->time; - ResetUse();// disable use until all targets have fired + SetUse( NULL );// disable use until all targets have fired - SetThink ( ManagerThink ); + SetThink( &ManagerThink ); pev->nextthink = gpGlobals->time; } @@ -618,7 +618,7 @@ void CTriggerMonsterJump :: Spawn ( void ) {// if targetted, spawn turned off pev->solid = SOLID_NOT; UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetUse( ToggleUse ); + SetUse( &ToggleUse ); } } @@ -627,7 +627,7 @@ void CTriggerMonsterJump :: Think( void ) { pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - ResetThink(); + SetThink( NULL ); } void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) @@ -729,7 +729,7 @@ void CTriggerCDAudio :: PlayTrack( void ) { PlayCDTrack( (int)pev->health ); - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); } @@ -808,20 +808,20 @@ void CTargetCDAudio::Play( void ) void CTriggerHurt :: Spawn( void ) { InitTrigger(); - SetTouch ( HurtTouch ); + SetTouch( &HurtTouch ); if ( !FStringNull ( pev->targetname ) ) { - SetUse ( ToggleUse ); + SetUse( &ToggleUse ); } else { - ResetUse(); + SetUse( NULL ); } if (m_bitsDamageInflict & DMG_RADIATION) { - SetThink ( RadiationThink ); + SetThink( &RadiationThink ); pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); } @@ -1080,7 +1080,7 @@ void CTriggerMultiple :: Spawn( void ) // } // else { - SetTouch( MultiTouch ); + SetTouch( &MultiTouch ); } } @@ -1177,16 +1177,16 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) if (m_flWait > 0) { - SetThink( MultiWaitOver ); + SetThink( &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... - ResetTouch(); + SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); } } @@ -1200,7 +1200,7 @@ void CBaseTrigger :: MultiWaitOver( void ) // pev->takedamage = DAMAGE_YES; // pev->solid = SOLID_BBOX; // } - ResetThink(); + SetThink( NULL ); } @@ -1266,7 +1266,7 @@ void CTriggerCounter :: Spawn( void ) if (m_cTriggersLeft == 0) m_cTriggersLeft = 2; - SetUse( CounterUse ); + SetUse( &CounterUse ); } // ====================== TRIGGER_CHANGELEVEL ================================ @@ -1411,11 +1411,11 @@ void CChangeLevel :: Spawn( void ) if (!FStringNull ( pev->targetname ) ) { - SetUse ( UseChangeLevel ); + SetUse( &UseChangeLevel ); } InitTrigger(); if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) - SetTouch( TouchChangeLevel ); + SetTouch( &TouchChangeLevel ); // ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); } @@ -1732,7 +1732,7 @@ void NextLevel( void ) if (pChange->pev->nextthink < gpGlobals->time) { - pChange->SetThink( CChangeLevel::ExecuteChangeLevel ); + pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); pChange->pev->nextthink = gpGlobals->time + 0.1; } } @@ -1820,7 +1820,7 @@ void CTriggerPush :: Spawn( ) if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. pev->solid = SOLID_NOT; - SetUse( ToggleUse ); + SetUse( &ToggleUse ); UTIL_SetOrigin( pev, pev->origin ); // Link into the list } @@ -1938,7 +1938,7 @@ void CTriggerTeleport :: Spawn( void ) { InitTrigger(); - SetTouch( TeleportTouch ); + SetTouch( &TeleportTouch ); } @@ -1963,7 +1963,7 @@ void CTriggerSave::Spawn( void ) } InitTrigger(); - SetTouch( SaveTouch ); + SetTouch( &SaveTouch ); } void CTriggerSave::SaveTouch( CBaseEntity *pOther ) @@ -1975,7 +1975,7 @@ void CTriggerSave::SaveTouch( CBaseEntity *pOther ) if ( !pOther->IsPlayer() ) return; - ResetTouch(); + SetTouch( NULL ); UTIL_Remove( this ); SERVER_COMMAND( "autosave\n" ); } @@ -1999,7 +1999,7 @@ void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pC if ( pActivator && !pActivator->IsNetClient() ) return; - ResetUse(); + SetUse( NULL ); if ( pev->message ) { @@ -2018,10 +2018,10 @@ void CTriggerEndSection::Spawn( void ) InitTrigger(); - SetUse ( EndSectionUse ); + SetUse( &EndSectionUse ); // If it is a "use only" trigger, then don't set the touch function. if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) - SetTouch( EndSectionTouch ); + SetTouch( &EndSectionTouch ); } void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) @@ -2030,7 +2030,7 @@ void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) if ( !pOther->IsNetClient() ) return; - ResetTouch(); + SetTouch( NULL ); if (pev->message) { @@ -2064,7 +2064,7 @@ LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); void CTriggerGravity::Spawn( void ) { InitTrigger(); - SetTouch( GravityTouch ); + SetTouch( &GravityTouch ); } void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) @@ -2321,7 +2321,7 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); // follow the player down - SetThink( FollowTarget ); + SetThink( &FollowTarget ); pev->nextthink = gpGlobals->time; m_moveDistance = 0; diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 6b039080..ce140f6c 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -120,7 +120,7 @@ void CTripmineGrenade :: Spawn( void ) m_flPowerUp = gpGlobals->time + 2.5; } - SetThink( PowerupThink ); + SetThink( &PowerupThink ); pev->nextthink = gpGlobals->time + 0.2; pev->takedamage = DAMAGE_YES; @@ -158,7 +158,7 @@ void CTripmineGrenade :: WarningThink( void ) // EMIT_SOUND( ENT(pev), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); // set to power up - SetThink( PowerupThink ); + SetThink( &PowerupThink ); pev->nextthink = gpGlobals->time + 1.0; } @@ -191,7 +191,7 @@ void CTripmineGrenade :: PowerupThink( void ) { STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); - SetThink( SUB_Remove ); + SetThink( &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(); @@ -206,7 +206,7 @@ void CTripmineGrenade :: PowerupThink( void ) CBaseEntity *pMine = Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); pMine->pev->spawnflags |= SF_NORESPAWN; - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); KillBeam(); pev->nextthink = gpGlobals->time + 0.1; return; @@ -249,7 +249,7 @@ void CTripmineGrenade :: MakeBeam( void ) m_flBeamLength = tr.flFraction; // set to follow laser spot - SetThink( BeamBreakThink ); + SetThink( &BeamBreakThink ); pev->nextthink = gpGlobals->time + 0.1; Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; @@ -317,7 +317,7 @@ int CTripmineGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttac { // disable // Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; KillBeam(); return FALSE; @@ -335,7 +335,7 @@ void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) pev->owner = ENT( pevAttacker ); } - SetThink( DelayDeathThink ); + SetThink( &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 @@ -420,7 +420,7 @@ void CTripmine::Holster( int skiplocal /* = 0 */ ) { // out of mines m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/turret.cpp b/dlls/turret.cpp index efd9b5a5..cc28f0bb 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -257,7 +257,7 @@ void CBaseTurret::Spawn() pev->takedamage = DAMAGE_AIM; SetBits (pev->flags, FL_MONSTER); - SetUse( TurretUse ); + SetUse( &TurretUse ); if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) @@ -307,7 +307,7 @@ void CTurret::Spawn() m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - SetThink(Initialize); + SetThink( &Initialize); m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); @@ -339,7 +339,7 @@ void CMiniTurret::Spawn() m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - SetThink(Initialize); + SetThink( &Initialize); pev->nextthink = gpGlobals->time + 0.3; } @@ -381,11 +381,11 @@ void CBaseTurret::Initialize(void) if (m_iAutoStart) { m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(AutoSearchThink); + SetThink( &AutoSearchThink); pev->nextthink = gpGlobals->time + .1; } else - SetThink(SUB_DoNothing); + SetThink( &SUB_DoNothing); } void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) @@ -399,7 +399,7 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ pev->nextthink = gpGlobals->time + 0.1; m_iAutoStart = FALSE;// switching off a turret disables autostart //!!!! this should spin down first!!BUGBUG - SetThink(Retire); + SetThink( &Retire); } else { @@ -411,7 +411,7 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ m_iAutoStart = TRUE; } - SetThink(Deploy); + SetThink( &Deploy); } } @@ -472,7 +472,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(SearchThink); + SetThink( &SearchThink); return; } @@ -489,7 +489,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(SearchThink); + SetThink( &SearchThink); return; } } @@ -518,7 +518,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(SearchThink); + SetThink( &SearchThink); return; } } @@ -670,7 +670,7 @@ void CBaseTurret::Deploy(void) SetTurretAnim(TURRET_ANIM_SPIN); pev->framerate = 0; - SetThink(SearchThink); + SetThink( &SearchThink); } m_flLastSight = gpGlobals->time + m_flMaxWait; @@ -710,11 +710,11 @@ void CBaseTurret::Retire(void) UTIL_SetSize(pev, pev->mins, pev->maxs); if (m_iAutoStart) { - SetThink(AutoSearchThink); + SetThink( &AutoSearchThink); pev->nextthink = gpGlobals->time + .1; } else - SetThink(SUB_DoNothing); + SetThink( &SUB_DoNothing); } } else @@ -746,7 +746,7 @@ void CTurret::SpinUpCall(void) { pev->nextthink = gpGlobals->time + 0.1; // retarget delay EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink(ActiveThink); + SetThink( &ActiveThink); m_iStartSpin = 0; m_iSpin = 1; } @@ -758,7 +758,7 @@ void CTurret::SpinUpCall(void) if (m_iSpin) { - SetThink(ActiveThink); + SetThink( &ActiveThink); } } @@ -856,7 +856,7 @@ void CBaseTurret::SearchThink(void) { m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink(ActiveThink); + SetThink( &ActiveThink); } else { @@ -866,7 +866,7 @@ void CBaseTurret::SearchThink(void) //Before we retrace, make sure that we are spun down. m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink(Retire); + SetThink( &Retire); } // should we stop the spin? else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) @@ -911,7 +911,7 @@ void CBaseTurret::AutoSearchThink(void) if (m_hEnemy != NULL) { - SetThink(Deploy); + SetThink( &Deploy); EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); } } @@ -979,7 +979,7 @@ void CBaseTurret :: TurretDeath( void ) if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) { pev->framerate = 0; - ResetThink(); + SetThink( NULL ); } } @@ -1024,8 +1024,8 @@ int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, flo ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - ResetUse(); - SetThink(TurretDeath); + SetUse( NULL ); + SetThink( &TurretDeath); SUB_UseTargets( this, USE_ON, 0 ); // wake up others pev->nextthink = gpGlobals->time + 0.1; @@ -1037,7 +1037,7 @@ int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, flo if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) { m_fBeserk = 1; - SetThink(SearchThink); + SetThink( &SearchThink); } } @@ -1179,8 +1179,8 @@ void CSentry::Spawn() m_iMinPitch = -60; UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - SetTouch(SentryTouch); - SetThink(Initialize); + SetTouch( &SentryTouch); + SetThink( &Initialize); pev->nextthink = gpGlobals->time + 0.3; } @@ -1204,8 +1204,8 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f if (!m_iOn) { - SetThink( Deploy ); - ResetUse(); + SetThink( &Deploy ); + SetUse( NULL ); pev->nextthink = gpGlobals->time + 0.1; } @@ -1218,8 +1218,8 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - ResetUse(); - SetThink(SentryDeath); + SetUse( NULL ); + SetThink( &SentryDeath); SUB_UseTargets( this, USE_ON, 0 ); // wake up others pev->nextthink = gpGlobals->time + 0.1; @@ -1299,7 +1299,7 @@ void CSentry :: SentryDeath( void ) if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) { pev->framerate = 0; - ResetThink(); + SetThink( NULL ); } } diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 4a28819a..264edb88 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -477,8 +477,8 @@ void CBasePlayerItem :: FallInit( void ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. - SetTouch( DefaultTouch ); - SetThink( FallThink ); + SetTouch( &DefaultTouch ); + SetThink( &FallThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -528,8 +528,8 @@ void CBasePlayerItem::Materialize( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch (DefaultTouch); - ResetThink(); + SetTouch( &DefaultTouch); + SetThink( NULL ); } @@ -580,8 +580,8 @@ CBaseEntity* CBasePlayerItem::Respawn( void ) if ( pNewWeapon ) { pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now - pNewWeapon->ResetTouch();// no touch - pNewWeapon->SetThink( AttemptToMaterialize ); + pNewWeapon->SetTouch( NULL );// no touch + pNewWeapon->SetThink( &AttemptToMaterialize ); DROP_TO_FLOOR ( ENT(pev) ); @@ -738,15 +738,15 @@ int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) void CBasePlayerItem::Drop( void ) { - ResetTouch(); - SetThink(SUB_Remove); + SetTouch( NULL ); + SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + .1; } void CBasePlayerItem::Kill( void ) { - ResetTouch(); - SetThink(SUB_Remove); + SetTouch( NULL ); + SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + .1; } @@ -766,8 +766,8 @@ void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) pev->model = iStringNull; pev->owner = pPlayer->edict(); pev->nextthink = gpGlobals->time + .1; - ResetTouch(); - ResetThink(); + SetTouch( NULL ); + SetThink( NULL ); } // CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal @@ -1066,17 +1066,17 @@ void CBasePlayerAmmo::Spawn( void ) UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( DefaultTouch ); + SetTouch( &DefaultTouch ); } CBaseEntity* CBasePlayerAmmo::Respawn( void ) { pev->effects |= EF_NODRAW; - ResetTouch(); + SetTouch( NULL ); UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. - SetThink( Materialize ); + SetThink( &Materialize ); pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); return this; @@ -1092,7 +1092,7 @@ void CBasePlayerAmmo::Materialize( void ) pev->effects |= EF_MUZZLEFLASH; } - SetTouch( DefaultTouch ); + SetTouch( &DefaultTouch ); } void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) @@ -1110,16 +1110,16 @@ void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) } else { - ResetTouch(); - SetThink(SUB_Remove); + SetTouch( NULL ); + SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + .1; } } else if (gEvilImpulse101) { // evil impulse 101 hack, kill always - ResetTouch(); - SetThink(SUB_Remove); + SetTouch( NULL ); + SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + .1; } } @@ -1256,7 +1256,7 @@ void CWeaponBox::Kill( void ) while ( pWeapon ) { - pWeapon->SetThink(SUB_Remove); + pWeapon->SetThink( &SUB_Remove); pWeapon->pev->nextthink = gpGlobals->time + 0.1; pWeapon = pWeapon->m_pNext; } @@ -1334,7 +1334,7 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) } EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - ResetTouch(); + SetTouch( NULL ); UTIL_Remove(this); } @@ -1380,8 +1380,8 @@ BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) pWeapon->pev->modelindex = 0; pWeapon->pev->model = iStringNull; pWeapon->pev->owner = edict(); - pWeapon->ResetThink();// crowbar may be trying to swing again, etc. - pWeapon->ResetTouch(); + 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) ); diff --git a/dlls/world.cpp b/dlls/world.cpp index 82a6e822..cb20add3 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -125,15 +125,15 @@ void CDecal :: Spawn( void ) if ( FStringNull ( pev->targetname ) ) { - SetThink( StaticDecal ); + SetThink( &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 ( SUB_DoNothing ); - SetUse(TriggerDecal); + SetThink( &SUB_DoNothing ); + SetUse( &TriggerDecal); } } @@ -158,7 +158,7 @@ void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); MESSAGE_END(); - SetThink( SUB_Remove ); + SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -642,7 +642,7 @@ void CWorld :: Precache( void ) CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); if ( pEntity ) { - pEntity->SetThink( SUB_CallUseToggle ); + pEntity->SetThink( &SUB_CallUseToggle ); pEntity->pev->message = pev->netname; pev->netname = 0; pEntity->pev->nextthink = gpGlobals->time + 0.3; From 344364cc71dc9772918b249f2b3ce4b0e9e17c51 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 2 Mar 2016 14:22:22 +0000 Subject: [PATCH 008/227] Fix prop bugs --- dlls/prop.cpp | 1773 +++++++++++++++++++++++++------------------------ 1 file changed, 889 insertions(+), 884 deletions(-) diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 56671736..f87edf5a 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -39,1108 +39,1113 @@ typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCei //extern "C" void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); Vector UTIL_AngleVectorsF(const Vector &angles) { - float rgflVecOut[3]; - float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, rgflVecOut, NULL, NULL); - return Vector(rgflVecOut); + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, rgflVecOut, NULL, NULL); + return Vector(rgflVecOut); } Vector UTIL_AngleVectorsR(const Vector &angles) { - float rgflVecOut[3]; - float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); - return Vector(rgflVecOut); + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); + return Vector(rgflVecOut); } Vector UTIL_AngleVectorsU(const Vector &angles) { - float rgflVecOut[3]; - float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); - return Vector(rgflVecOut); + float rgflVecOut[3]; + float rgflVecIn[3]; + angles.CopyToArray(rgflVecIn); + g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); + return Vector(rgflVecOut); } //===================grenade enum PropShape { - SHAPE_CYL_H = 0, - SHAPE_CYL_V, - SHAPE_BOX, - SHAPE_GENERIC, - SHAPE_SPHERE, - SHAPE_NOROTATE + SHAPE_CYL_H = 0, + SHAPE_CYL_V, + SHAPE_BOX, + SHAPE_GENERIC, + SHAPE_SPHERE, + SHAPE_NOROTATE }; class CProp : public CBaseEntity { public: - void Spawn(void); - void Precache(); + void Spawn(void); + void Precache(); - void EXPORT BounceTouch(CBaseEntity *pOther); - //void EXPORT SlideTouch(CBaseEntity *pOther); - virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - virtual void Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual int ObjectCaps(void) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE; } - virtual void BounceSound(void); - virtual int BloodColor(void) { return DONT_BLEED; } - virtual void Killed(entvars_t *pevAttacker, int iGib); - void CheckRotate(); - void RespawnThink(); - void AngleThink(); - void DeployThink(); - void DamageSound( void ); - void PropRespawn(); - void KeyValue( KeyValueData* pkvd); + void EXPORT BounceTouch(CBaseEntity *pOther); + //void EXPORT SlideTouch(CBaseEntity *pOther); + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + virtual void Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + virtual int ObjectCaps(void) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE; } + virtual void BounceSound(void); + virtual int BloodColor(void) { return DONT_BLEED; } + virtual void Killed(entvars_t *pevAttacker, int iGib); + void CheckRotate(); + void RespawnThink(); + void AngleThink(); + void DeployThink(); + void DamageSound( void ); + void PropRespawn(); + void KeyValue( KeyValueData* pkvd); - 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 const char *pSoundsWood[]; + static const char *pSoundsFlesh[]; + static const char *pSoundsGlass[]; + static const char *pSoundsMetal[]; + static const char *pSoundsConcrete[]; + static const char *pSpawnObjects[]; - inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } - inline int ExplosionMagnitude( void ) { return pev->impulse; } - inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } + 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 ); - void EXPORT Die( void ); + static void MaterialSoundPrecache( Materials precacheMaterial ); + static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ); + static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); + void EXPORT Die( void ); - BOOL m_bBarrel; - float m_flFloorFriction; - float m_flCollideFriction; + BOOL m_bBarrel; + float m_flFloorFriction; + float m_flCollideFriction; - // hull sizes - Vector minsH, maxsH; - Vector minsV, maxsV; + // hull sizes + Vector minsH, maxsH; + Vector minsV, maxsV; - // spawn backup; - Vector spawnOrigin; - Vector spawnAngles; + // spawn backup; + Vector spawnOrigin; + Vector spawnAngles; - edict_t *m_owner2; - edict_t *m_attacker; - float m_flNextAttack; - float m_flRespawnTime; - PropShape m_shape; - PropShape m_oldshape; - CBasePlayer *m_pHolstered; - float m_flSpawnHealth; - int m_idShard; - float m_angle; - int m_iszGibModel; - Materials m_Material; - Explosions m_Explosion; - int m_iaCustomAnglesX[10]; - int m_iaCustomAnglesZ[10]; + edict_t *m_owner2; + edict_t *m_attacker; + float m_flNextAttack; + float m_flRespawnTime; + PropShape m_shape; + PropShape m_oldshape; + CBasePlayer *m_pHolstered; + float m_flSpawnHealth; + int m_idShard; + float m_angle; + int m_iszGibModel; + Materials m_Material; + Explosions m_Explosion; + int m_iaCustomAnglesX[10]; + int m_iaCustomAnglesZ[10]; }; LINK_ENTITY_TO_CLASS(prop, CProp); const char *CProp::pSoundsWood[] = { - "debris/wood1.wav", - "debris/wood2.wav", - "debris/wood3.wav", + "debris/wood1.wav", + "debris/wood2.wav", + "debris/wood3.wav", }; const char *CProp::pSoundsFlesh[] = { - "debris/flesh1.wav", - "debris/flesh2.wav", - "debris/flesh3.wav", - "debris/flesh5.wav", - "debris/flesh6.wav", - "debris/flesh7.wav", + "debris/flesh1.wav", + "debris/flesh2.wav", + "debris/flesh3.wav", + "debris/flesh5.wav", + "debris/flesh6.wav", + "debris/flesh7.wav", }; const char *CProp::pSoundsMetal[] = { - "debris/metal1.wav", - "debris/metal2.wav", - "debris/metal3.wav", + "debris/metal1.wav", + "debris/metal2.wav", + "debris/metal3.wav", }; const char *CProp::pSoundsConcrete[] = { - "debris/concrete1.wav", - "debris/concrete2.wav", - "debris/concrete3.wav", + "debris/concrete1.wav", + "debris/concrete2.wav", + "debris/concrete3.wav", }; const char *CProp::pSoundsGlass[] = { - "debris/glass1.wav", - "debris/glass2.wav", - "debris/glass3.wav", + "debris/glass1.wav", + "debris/glass2.wav", + "debris/glass3.wav", }; const char **CProp::MaterialSoundList( Materials precacheMaterial, int &soundCount ) { - const char **pSoundList = NULL; + 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; + 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 matMetal: + pSoundList = pSoundsMetal; + soundCount = ARRAYSIZE(pSoundsMetal); + break; - case matCinderBlock: - case matRocks: - pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); - break; + case matCinderBlock: + case matRocks: + pSoundList = pSoundsConcrete; + soundCount = ARRAYSIZE(pSoundsConcrete); + break; - case matCeilingTile: - case matNone: - default: - soundCount = 0; - break; - } + case matCeilingTile: + case matNone: + default: + soundCount = 0; + break; + } - return pSoundList; + return pSoundList; } void CProp::MaterialSoundPrecache( Materials precacheMaterial ) { - const char **pSoundList; - int i, soundCount = 0; + const char **pSoundList; + int i, soundCount = 0; - pSoundList = MaterialSoundList( precacheMaterial, soundCount ); + pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - for ( i = 0; i < soundCount; i++ ) - { - PRECACHE_SOUND( (char *)pSoundList[i] ); - } + for ( i = 0; i < soundCount; i++ ) + { + PRECACHE_SOUND( (char *)pSoundList[i] ); + } } void CProp::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) { - const char **pSoundList; - int soundCount = 0; + const char **pSoundList; + int soundCount = 0; - pSoundList = MaterialSoundList( soundMaterial, soundCount ); + pSoundList = MaterialSoundList( soundMaterial, soundCount ); - if ( soundCount ) - EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); + if ( soundCount ) + EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); } void CProp::Precache( void ) { - const char *pGibName; + const char *pGibName; - switch (m_Material) - { - case matWood: - pGibName = "models/woodgibs.mdl"; + if( !pev->model ) + pev->model = MAKE_STRING( "models/xash/barrel_brown.mdl" ); - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - break; - case matFlesh: - pGibName = "models/fleshgibs.mdl"; + switch (m_Material) + { + case matWood: + pGibName = "models/woodgibs.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/bustcrate1.wav"); + PRECACHE_SOUND("debris/bustcrate2.wav"); + break; + case matFlesh: + pGibName = "models/fleshgibs.mdl"; - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; + 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"; - case matUnbreakableGlass: - case matGlass: - pGibName = "models/glassgibs.mdl"; + PRECACHE_SOUND("debris/bustmetal1.wav"); + PRECACHE_SOUND("debris/bustmetal2.wav"); + break; - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - break; - case matMetal: - pGibName = "models/metalplategibs.mdl"; + case matUnbreakableGlass: + case matGlass: + pGibName = "models/glassgibs.mdl"; - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - case matCinderBlock: - pGibName = "models/cindergibs.mdl"; + PRECACHE_SOUND("debris/bustglass1.wav"); + PRECACHE_SOUND("debris/bustglass2.wav"); + break; + case matMetal: + pGibName = "models/metalplategibs.mdl"; - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matRocks: - pGibName = "models/rockgibs.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 matCeilingTile: - pGibName = "models/ceilinggibs.mdl"; + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + break; + case matRocks: + pGibName = "models/rockgibs.mdl"; - PRECACHE_SOUND ("debris/bustceiling.wav"); - break; - } - MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); + PRECACHE_SOUND("debris/bustconcrete1.wav"); + PRECACHE_SOUND("debris/bustconcrete2.wav"); + break; + case matCeilingTile: + pGibName = "models/ceilinggibs.mdl"; - m_idShard = PRECACHE_MODEL( (char *)pGibName ); - PRECACHE_MODEL( (char *)STRING(pev->model) ); + PRECACHE_SOUND ("debris/bustceiling.wav"); + break; + } + MaterialSoundPrecache( m_Material ); + if ( m_iszGibModel ) + pGibName = STRING(m_iszGibModel); + + m_idShard = PRECACHE_MODEL( (char *)pGibName ); + PRECACHE_MODEL( (char *)STRING(pev->model) ); } void CProp::DamageSound( void ) { - int pitch; - float fvol; - char *rgpsz[6]; - int i; - int material = m_Material; + int pitch; + float fvol; + char *rgpsz[6]; + int i; + 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); + if (RANDOM_LONG(0,2)) + pitch = PITCH_NORM; + else + pitch = 95 + RANDOM_LONG(0,34); - fvol = RANDOM_FLOAT(0.75, 1.0); + fvol = RANDOM_FLOAT(0.75, 1.0); - if (material == matComputer && RANDOM_LONG(0,1)) - material = matMetal; + 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; + 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 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 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 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 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; - } + 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); + if (i) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); } void CProp::Die( void ) { - Vector vecSpot;// shard origin - Vector vecVelocity;// shard velocity - CBaseEntity *pEntity = NULL; - char cFlag = 0; - int pitch; - float fvol; + Vector vecSpot;// shard origin + Vector vecVelocity;// shard velocity + CBaseEntity *pEntity = NULL; + char cFlag = 0; + int pitch; + float fvol; - pitch = 95 + RANDOM_LONG(0,29); + pitch = 95 + RANDOM_LONG(0,29); - if (pitch > 97 && pitch < 103) - pitch = 100; + if (pitch > 97 && pitch < 103) + pitch = 100; - // The more negative pev->health, the louder - // the sound should be. + // The more negative pev->health, the louder + // the sound should be. - fvol = RANDOM_FLOAT(0.85, 1.0) + (fabs(pev->health) / 100.0); + fvol = RANDOM_FLOAT(0.85, 1.0) + (fabs(pev->health) / 100.0); - if (fvol > 1.0) - fvol = 1.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; + 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 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 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 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 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; - } + case matCeilingTile: + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); + break; + } - if (m_Explosion == expDirected) - vecVelocity = g_vecAttackDir * 200; - else - { - vecVelocity.x = 0; - vecVelocity.y = 0; - vecVelocity.z = 0; - } + 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); + 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 ); + // 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); + // 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 ); + // velocity + WRITE_COORD( vecVelocity.x ); + WRITE_COORD( vecVelocity.y ); + WRITE_COORD( vecVelocity.z ); - // randomization - WRITE_BYTE( 10 ); + // randomization + WRITE_BYTE( 10 ); - // Model - WRITE_SHORT( m_idShard ); //model id# + // Model + WRITE_SHORT( m_idShard ); //model id# - // # of shards - WRITE_BYTE( 0 ); // let client decide + // # of shards + WRITE_BYTE( 0 ); // let client decide - // duration - WRITE_BYTE( 25 );// 2.5 seconds + // duration + WRITE_BYTE( 25 );// 2.5 seconds - // flags - WRITE_BYTE( cFlag ); - MESSAGE_END(); + // 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; + 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; + // !!! 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; - } - } + // 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; + // 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 ); + pev->solid = SOLID_NOT; + // Fire targets on break + SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - if ( Explodable() ) - { - ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), TRUE ); - } + if ( Explodable() ) + { + ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), TRUE ); + } } void CProp::Killed(entvars_t *pevAttacker, int iGib) { - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( &CProp::RespawnThink ); - ResetTouch( ); - ResetUse( ); + pev->takedamage = DAMAGE_NO; + pev->deadflag = DEAD_DEAD; + pev->solid = SOLID_NOT; + pev->effects |= EF_NODRAW; + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( &CProp::RespawnThink ); + ResetTouch( ); + ResetUse( ); } void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - if (m_owner2 != pActivator->edict()) - { - if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) - { - m_owner2 = m_attacker = pActivator->edict(); - } - else - return; - } - if( pActivator->IsPlayer() ) - { - m_pHolstered = (CBasePlayer *) pActivator; - if( m_pHolstered ) - { + if (m_owner2 != pActivator->edict()) + { + if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + { + m_owner2 = m_attacker = pActivator->edict(); + } + else + return; + } + if( pActivator->IsPlayer() ) + { + m_pHolstered = (CBasePlayer *) pActivator; + if( m_pHolstered ) + { - if ( m_pHolstered->m_pActiveItem ) - { - CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); + if ( m_pHolstered->m_pActiveItem ) + { + CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); - //m_Holstered->m_pActiveItem->Holster(); // strange bug here. ValveWHY? + //m_Holstered->m_pActiveItem->Holster(); // strange bug here. ValveWHY? - // HACK: prevent attack - if( weapon ) - { - weapon->m_flNextPrimaryAttack += 0.1; - weapon->m_flNextSecondaryAttack += 0.1; - } - m_pHolstered->m_iHideHUD |= HIDEHUD_WEAPONS; - m_pHolstered->pev->weaponmodel = 0; - m_pHolstered->pev->viewmodel = 0; - } - SetThink( &CProp::DeployThink ); - pev->nextthink = gpGlobals->time + 0.2; - } - } - Vector target = pActivator->pev->origin + UTIL_GetAimVector(m_owner2, 1000) * 50; - target.z = target.z + 32; - pev->velocity = (target - VecBModelOrigin(pev)) * 10; - Vector atarget = UTIL_VecToAngles(UTIL_GetAimVector(m_owner2, 1000)); - pev->angles.x = UTIL_AngleMod(pev->angles.x); - pev->angles.y = UTIL_AngleMod(pev->angles.y); - pev->angles.z = UTIL_AngleMod(pev->angles.z); - atarget.x = UTIL_AngleMod(atarget.x); - atarget.y = UTIL_AngleMod(atarget.y); - atarget.z = UTIL_AngleMod(atarget.z); - pev->avelocity.x = UTIL_AngleDiff(atarget.x, pev->angles.x) * 10; - pev->avelocity.y = UTIL_AngleDiff(atarget.y, pev->angles.y) * 10; - pev->avelocity.z = UTIL_AngleDiff(atarget.z, pev->angles.z) * 10; - //pev->angles.z += (0 - pev->angles.z) * 0.06; - if ((pActivator->pev->button & (IN_ATTACK))) - { - pev->velocity = UTIL_GetAimVector(m_owner2, 1000) * 1000; - pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); - } - if ((pActivator->pev->button & (IN_ATTACK2))) - { - //m_Horizontal = false; - //pev->angles.z = 0; - } - // m_Horizontal = (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || ( sin(pev->angles.x/180*M_PI) > 0.1); - // CheckRotate(); - //ALERT( at_console, "Prop use!\n"); + // HACK: prevent attack + if( weapon ) + { + weapon->m_flNextPrimaryAttack += 0.1; + weapon->m_flNextSecondaryAttack += 0.1; + } + m_pHolstered->m_iHideHUD |= HIDEHUD_WEAPONS; + m_pHolstered->pev->weaponmodel = 0; + m_pHolstered->pev->viewmodel = 0; + } + SetThink( &CProp::DeployThink ); + pev->nextthink = gpGlobals->time + 0.2; + } + } + Vector target = pActivator->pev->origin + UTIL_GetAimVector(m_owner2, 1000) * 50; + target.z = target.z + 32; + pev->velocity = (target - VecBModelOrigin(pev)) * 10; + Vector atarget = UTIL_VecToAngles(UTIL_GetAimVector(m_owner2, 1000)); + pev->angles.x = UTIL_AngleMod(pev->angles.x); + pev->angles.y = UTIL_AngleMod(pev->angles.y); + pev->angles.z = UTIL_AngleMod(pev->angles.z); + atarget.x = UTIL_AngleMod(atarget.x); + atarget.y = UTIL_AngleMod(atarget.y); + atarget.z = UTIL_AngleMod(atarget.z); + pev->avelocity.x = UTIL_AngleDiff(atarget.x, pev->angles.x) * 10; + pev->avelocity.y = UTIL_AngleDiff(atarget.y, pev->angles.y) * 10; + pev->avelocity.z = UTIL_AngleDiff(atarget.z, pev->angles.z) * 10; + //pev->angles.z += (0 - pev->angles.z) * 0.06; + if ((pActivator->pev->button & (IN_ATTACK))) + { + pev->velocity = UTIL_GetAimVector(m_owner2, 1000) * 1000; + pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + } + if ((pActivator->pev->button & (IN_ATTACK2))) + { + //m_Horizontal = false; + //pev->angles.z = 0; + } + // m_Horizontal = (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || ( sin(pev->angles.x/180*M_PI) > 0.1); + // CheckRotate(); + //ALERT( at_console, "Prop use!\n"); } void CProp::Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - if (m_owner2 != pActivator->edict()) - { - if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) - m_attacker = pActivator->edict(); - else - return; - } + if (m_owner2 != pActivator->edict()) + { + if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + m_attacker = pActivator->edict(); + else + return; + } - if ((pActivator->pev->button & (IN_ATTACK))) - { - pev->velocity = UTIL_GetAimVector(m_owner2, 3000) * 1000; - pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); - } - if ((pActivator->pev->button & (IN_ATTACK2))) - { - //m_Horizontal = false; - //pev->angles.z = 0; - } + if ((pActivator->pev->button & (IN_ATTACK))) + { + pev->velocity = UTIL_GetAimVector(m_owner2, 3000) * 1000; + pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + } + if ((pActivator->pev->button & (IN_ATTACK2))) + { + //m_Horizontal = false; + //pev->angles.z = 0; + } - pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( &CProp::RespawnThink); + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( &CProp::RespawnThink); } void CProp::CheckRotate() { - if( m_shape != SHAPE_CYL_H && m_shape != SHAPE_CYL_V ) - { - UTIL_SetSize(pev, minsH, maxsH); - return; - } - if( (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || - (fabs(sin(pev->angles.x / 180 * M_PI)) > 0.3) ) - m_shape = SHAPE_CYL_H; - else - m_shape = SHAPE_CYL_V; + if( m_shape != SHAPE_CYL_H && m_shape != SHAPE_CYL_V ) + { + UTIL_SetSize(pev, minsH, maxsH); + return; + } + if( (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || + (fabs(sin(pev->angles.x / 180 * M_PI)) > 0.3) ) + m_shape = SHAPE_CYL_H; + else + m_shape = SHAPE_CYL_V; - if (m_oldshape != m_shape) - { + if (m_oldshape != m_shape) + { - if (m_shape == SHAPE_CYL_H) - { - pev->angles.y += 90; + if (m_shape == SHAPE_CYL_H) + { + pev->angles.y += 90; - ALERT(at_console, "setHorizontal: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); + ALERT(at_console, "setH: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); - UTIL_SetSize(pev, minsH, maxsH); - } - else if (m_shape == SHAPE_CYL_V) - { - Vector mins = pev->absmin; - Vector maxs = pev->absmax; + UTIL_SetSize(pev, minsH, maxsH); + } + else if (m_shape == SHAPE_CYL_V) + { + Vector mins = pev->absmin; + Vector maxs = pev->absmax; - mins.z = pev->absmax.z; - maxs.z += 10; + mins.z = pev->absmax.z; + maxs.z += 10; + ALERT(at_console, "setV: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); - // BUGBUG -- can only find 256 entities on a prop -- 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++ ) - { - pList[i]->pev->origin.z += 10; - } - } - pev->origin.z += 10; - //pev->angles.y -= 90; - UTIL_SetSize(pev, minsV, maxsV); - } - //DROP_TO_FLOOR(edict()); - //pev->origin.z += 0.5; - m_oldshape = m_shape; - } + // BUGBUG -- can only find 256 entities on a prop -- 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++ ) + { + pList[i]->pev->origin.z += 10; + } + } + pev->origin.z += 10; + //pev->angles.y -= 90; + UTIL_SetSize(pev, minsV, maxsV); + } + //DROP_TO_FLOOR(edict()); + //pev->origin.z += 0.5; + m_oldshape = m_shape; + } } void CProp::DeployThink( void ) { - if( m_pHolstered ) - { - if( m_pHolstered->m_pActiveItem ) - { - m_pHolstered->m_pActiveItem->Deploy(); - CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); - if( weapon ) - { - weapon->m_flNextPrimaryAttack = 0; - weapon->m_flNextSecondaryAttack = 0; - } - } - m_pHolstered ->m_iHideHUD &= ~HIDEHUD_WEAPONS; - m_pHolstered = NULL; - } - if( m_pfnThink == &CProp::DeployThink ) - { - pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( &CProp::RespawnThink ); - } + if( m_pHolstered ) + { + if( m_pHolstered->m_pActiveItem ) + { + m_pHolstered->m_pActiveItem->Deploy(); + CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); + if( weapon ) + { + weapon->m_flNextPrimaryAttack = 0; + weapon->m_flNextSecondaryAttack = 0; + } + } + m_pHolstered ->m_iHideHUD &= ~HIDEHUD_WEAPONS; + m_pHolstered = NULL; + } + if( m_pfnThink == &CProp::DeployThink ) + { + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( &CProp::RespawnThink ); + } } void CProp::BounceTouch(CBaseEntity *pOther) { - //ALERT( at_console, "BounceTouch: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); - // only do damage if we're moving fairly fast - DeployThink(); + //ALERT( at_console, "BounceTouch: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); + // only do damage if we're moving fairly fast + DeployThink(); - if ( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 300) - { - entvars_t *pevOwner = VARS(m_attacker); - if (pevOwner) - { - float dmg = 50 + pev->velocity.Length() / 40; - if (pOther->edict() == m_owner2) - { - dmg = 5; - if (pOther->pev->button & (IN_USE)) - { - dmg = 1; - } - } - TraceResult tr = UTIL_GetGlobalTrace(); - ClearMultiDamage(); - pOther->TraceAttack(pevOwner, dmg, gpGlobals->v_forward, &tr, DMG_CLUB); - ApplyMultiDamage(pev, pevOwner); - } - m_flNextAttack = gpGlobals->time + 1.0; // debounce - } - if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 700) ) - { - Killed( VARS(m_attacker), GIB_NORMAL ); - Die(); - } + if ( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 300) + { + entvars_t *pevOwner = VARS(m_attacker); + if (pevOwner) + { + float dmg = 50 + pev->velocity.Length() / 40; + if (pOther->edict() == m_owner2) + { + dmg = 5; + if (pOther->pev->button & (IN_USE)) + { + dmg = 1; + } + } + TraceResult tr = UTIL_GetGlobalTrace(); + ClearMultiDamage(); + pOther->TraceAttack(pevOwner, dmg, gpGlobals->v_forward, &tr, DMG_CLUB); + ApplyMultiDamage(pev, pevOwner); + } + m_flNextAttack = gpGlobals->time + 1.0; // debounce + } + if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 700) ) + { + Killed( VARS(m_attacker), GIB_NORMAL ); + Die(); + } - pev->velocity = pev->velocity + pOther->pev->velocity; - float dp = cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y)); - if (pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40) - { - CheckRotate(); - if (m_shape == SHAPE_CYL_H) - { + pev->velocity = pev->velocity + pOther->pev->velocity; + float dp = cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y)); + if (pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40) + { + CheckRotate(); + if (m_shape == SHAPE_CYL_H) + { - pev->velocity.x *= fabs(dp) * 0.8 + 0.2; - pev->velocity.y *= fabs(dp) * 0.8 + 0.2; - pev->velocity.z -= 20; - pev->avelocity.x = -dp*pev->velocity.Length()* 1.5; - pev->avelocity.y = 0; - pev->avelocity.z = 0; - pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; - //AngleThink(); - } - else if (m_shape == SHAPE_CYL_V) - { - // pev->angles.z *= 0.3; - //pev->angles.x *= 0.3; - //AngleThink(); - //CheckRotate(); - pev->velocity.z *= m_flFloorFriction; - pev->velocity.x *= m_flFloorFriction; - pev->velocity.y *= m_flFloorFriction; - pev->velocity.z -= 10; - pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(30, -30); - } - else if( m_shape == SHAPE_SPHERE ) - { - pev->velocity.z -= 20; - pev->avelocity.x = -cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5; - pev->avelocity.y = -sin(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5;; - pev->avelocity.z = 0; - } - else if( m_shape == SHAPE_BOX || m_shape == SHAPE_GENERIC ) - { - pev->velocity.z *= m_flFloorFriction; - pev->velocity.x *= m_flFloorFriction; - pev->velocity.y *= m_flFloorFriction; - pev->velocity.z -= 10; - } + pev->velocity.x *= fabs(dp) * 0.8 + 0.2; + pev->velocity.y *= fabs(dp) * 0.8 + 0.2; + pev->velocity.z -= 20; + pev->avelocity.x = -dp*pev->velocity.Length()* 1.5; + pev->avelocity.y = 0; + pev->avelocity.z = 0; + pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; + //AngleThink(); + } + else if (m_shape == SHAPE_CYL_V) + { + // pev->angles.z *= 0.3; + //pev->angles.x *= 0.3; + //AngleThink(); + //CheckRotate(); + pev->velocity.z *= m_flFloorFriction; + pev->velocity.x *= m_flFloorFriction; + pev->velocity.y *= m_flFloorFriction; + pev->velocity.z -= 10; + pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(30, -30); + } + else if( m_shape == SHAPE_SPHERE ) + { + pev->velocity.z -= 20; + pev->avelocity.x = -cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5; + pev->avelocity.y = -sin(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5;; + pev->avelocity.z = 0; + } + else if( m_shape == SHAPE_BOX || m_shape == SHAPE_GENERIC ) + { + pev->velocity.z *= m_flFloorFriction; + pev->velocity.x *= m_flFloorFriction; + pev->velocity.y *= m_flFloorFriction; + pev->velocity.z -= 10; + } - } - else - { - { - pev->velocity.z *= 0.3; - pev->velocity.y *= m_flCollideFriction; - pev->velocity.x *= m_flCollideFriction; - if( m_shape != SHAPE_SPHERE ) - { - pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); - } - } - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 1, -1 ); - BounceSound(); - } - pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) - pev->framerate = 1; - else if (pev->framerate < 0.2) - { - CheckRotate(); - AngleThink(); - if (pev->angles.z == 0 || pev->angles.z == 90) - pev->framerate = 0; - else - pev->framerate = 0.2; - } + } + else + { + { + pev->velocity.z *= 0.3; + pev->velocity.y *= m_flCollideFriction; + pev->velocity.x *= m_flCollideFriction; + if( m_shape != SHAPE_SPHERE ) + { + pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(100, -100); + pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + } + } + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 1, -1 ); + BounceSound(); + } + pev->framerate = pev->velocity.Length() / 200.0; + if (pev->framerate > 1.0) + pev->framerate = 1; + else if (pev->framerate < 0.2) + { + CheckRotate(); + AngleThink(); + if (pev->angles.z == 0 || pev->angles.z == 90) + pev->framerate = 0; + else + pev->framerate = 0.2; + } } void CProp::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; - } + 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 CProp::Spawn(void) { - Precache(); + Precache(); - if( !pev->model ) - pev->model = MAKE_STRING( "models/xash/barrel_brown.mdl" ); - - if( minsH == g_vecZero ) - { - // default barrel parameters - minsV = Vector(-10, -10, -17); - maxsV = Vector(10, 10, 18); - minsH = Vector(-10, -10, -10); - maxsH = Vector(10, 10, 13); - } - m_flCollideFriction = 0.7; - m_flFloorFriction = 0.5; - spawnOrigin = pev->origin; - spawnAngles = pev->angles; - m_flSpawnHealth = pev->health; - if( !m_flRespawnTime ) - m_flRespawnTime = 20; - pev->dmg = 100; - PropRespawn(); + if( minsH == g_vecZero ) + { + // default barrel parameters + minsV = Vector(-10, -10, -17); + maxsV = Vector(10, 10, 18); + minsH = Vector(-10, -10, -10); + maxsH = Vector(10, 10, 13); + } + m_flCollideFriction = 0.7; + m_flFloorFriction = 0.5; + spawnOrigin = pev->origin; + spawnAngles = pev->angles; + m_flSpawnHealth = pev->health; + if( m_flSpawnHealth <= 0 ) + m_flSpawnHealth = 30; + if( !m_flRespawnTime ) + m_flRespawnTime = 20; + pev->dmg = 100; + PropRespawn(); } void CProp::PropRespawn() { - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_SLIDEBOX; - pev->angles = spawnAngles; - pev->takedamage = DAMAGE_YES; - pev->velocity = pev->avelocity = g_vecZero; - SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetOrigin( pev, spawnOrigin ); - m_oldshape = (PropShape)-1; - CheckRotate(); - pev->health = m_flSpawnHealth; - SetTouch( &CProp::BounceTouch); - SetUse( &CProp::Use); - pev->effects &= ~EF_NODRAW; - pev->framerate = 1.0f; + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_SLIDEBOX; + pev->angles = spawnAngles; + pev->takedamage = DAMAGE_YES; + pev->velocity = pev->avelocity = g_vecZero; + SET_MODEL( ENT(pev), STRING(pev->model) ); + UTIL_SetOrigin( pev, spawnOrigin ); + + m_oldshape = (PropShape)-1; + CheckRotate(); + pev->health = m_flSpawnHealth; + SetTouch( &CProp::BounceTouch); + SetUse( &CProp::Use); + pev->effects &= ~EF_NODRAW; + pev->framerate = 1.0f; + UTIL_SetOrigin( pev, spawnOrigin ); } void CProp::RespawnThink() { - if( !(pev->spawnflags & SF_PROP_RESPAWN)) - return; - PropRespawn(); + if( !(pev->spawnflags & SF_PROP_RESPAWN)) + return; + PropRespawn(); } void CProp::AngleThink() { - pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( &CProp::RespawnThink); - if (!(pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40)) - { - m_owner2 = m_attacker = 0; - return; - } - if (m_shape == SHAPE_CYL_H) - { - pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; - if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) - { - SetThink( &CProp::AngleThink); - pev->nextthink = gpGlobals->time + 0.1; - } - //ALERT( at_console, "AngleThink: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); - pev->avelocity.y = pev->avelocity.z = 0; - } - else if (m_shape == SHAPE_CYL_V) - { - if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) - { - SetThink( &CProp::AngleThink); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->angles.z += UTIL_AngleDiff(0, pev->angles.z) * 0.7; - //pev->angles.x += UTIL_AngleDiff( 0, pev->angles.x ) * 0.3; - pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; - } - else if (m_shape == SHAPE_BOX) - { - Vector iangles; - iangles.x = round( pev->angles.x / 90 ) * 90; - iangles.y = round( pev->angles.y / 90 ) * 90; - iangles.z = round( pev->angles.z / 90 ) * 90; - if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || - //fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) - { - SetThink( &CProp::AngleThink); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; - //pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; - pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + pev->nextthink = gpGlobals->time + m_flRespawnTime; + SetThink( &CProp::RespawnThink); + if (!(pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40)) + { + m_owner2 = m_attacker = 0; + return; + } + if (m_shape == SHAPE_CYL_H) + { + pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; + if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + { + SetThink( &CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + //ALERT( at_console, "AngleThink: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); + pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_CYL_V) + { + if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + { + SetThink( &CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.z += UTIL_AngleDiff(0, pev->angles.z) * 0.7; + //pev->angles.x += UTIL_AngleDiff( 0, pev->angles.x ) * 0.3; + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_BOX) + { + Vector iangles; + iangles.x = round( pev->angles.x / 90 ) * 90; + iangles.y = round( pev->angles.y / 90 ) * 90; + iangles.z = round( pev->angles.z / 90 ) * 90; + if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || + //fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + { + SetThink( &CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; + //pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; + pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; - pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; - } - else if (m_shape == SHAPE_NOROTATE) - { - pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; - Vector iangles = spawnAngles; - if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) - { - SetThink( &CProp::AngleThink); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; - pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; - pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; - } - else if (m_shape == SHAPE_GENERIC) - { - float ianglex = 0, ianglez = 0, imaxanglediff=360.0f; - // if first number is zero, it is angle - // all other zeroes is array end - for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesX[i] ); i++) - { - float anglediff = fabs(UTIL_AngleDiff(pev->angles.x, m_iaCustomAnglesX[i])); - if( imaxanglediff > anglediff ) - { - ianglex = m_iaCustomAnglesX[i]; - imaxanglediff = anglediff; - } - } - imaxanglediff=360.0f; - for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesZ[i] ); i++) - { - float anglediff = fabs(UTIL_AngleDiff(pev->angles.z, m_iaCustomAnglesZ[i])); - if( imaxanglediff > anglediff ) - { - ianglez = m_iaCustomAnglesZ[i]; - imaxanglediff = anglediff; - } - } - if (fabs(UTIL_AngleDiff(ianglex, pev->angles.x)) > 0.1 || - fabs(UTIL_AngleDiff(ianglez, pev->angles.z)) > 0.1 ) - { - SetThink( &CProp::AngleThink); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->angles.x += UTIL_AngleDiff(ianglex, pev->angles.x) * 0.6; - pev->angles.z += UTIL_AngleDiff(ianglez, pev->angles.z) * 0.6; - pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; - } - pev->angles.x = UTIL_AngleMod(pev->angles.x); - pev->angles.y = UTIL_AngleMod(pev->angles.y); - pev->angles.z = UTIL_AngleMod(pev->angles.z); + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + else if (m_shape == SHAPE_NOROTATE) + { + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + Vector iangles = spawnAngles; + if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || + fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + { + SetThink( &CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; + pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; + pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + } + else if (m_shape == SHAPE_GENERIC) + { + float ianglex = 0, ianglez = 0, imaxanglediff=360.0f; + // if first number is zero, it is angle + // all other zeroes is array end + for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesX[i] ); i++) + { + float anglediff = fabs(UTIL_AngleDiff(pev->angles.x, m_iaCustomAnglesX[i])); + if( imaxanglediff > anglediff ) + { + ianglex = m_iaCustomAnglesX[i]; + imaxanglediff = anglediff; + } + } + imaxanglediff=360.0f; + for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesZ[i] ); i++) + { + float anglediff = fabs(UTIL_AngleDiff(pev->angles.z, m_iaCustomAnglesZ[i])); + if( imaxanglediff > anglediff ) + { + ianglez = m_iaCustomAnglesZ[i]; + imaxanglediff = anglediff; + } + } + if (fabs(UTIL_AngleDiff(ianglex, pev->angles.x)) > 0.1 || + fabs(UTIL_AngleDiff(ianglez, pev->angles.z)) > 0.1 ) + { + SetThink( &CProp::AngleThink); + pev->nextthink = gpGlobals->time + 0.1; + } + pev->angles.x += UTIL_AngleDiff(ianglex, pev->angles.x) * 0.6; + pev->angles.z += UTIL_AngleDiff(ianglez, pev->angles.z) * 0.6; + pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; + } + pev->angles.x = UTIL_AngleMod(pev->angles.x); + pev->angles.y = UTIL_AngleMod(pev->angles.y); + pev->angles.z = UTIL_AngleMod(pev->angles.z); } int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { - Vector r = (pevInflictor->origin - pev->origin); - if (flDamage > 200 && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) - m_attacker = ENT(pevAttacker); - DeployThink(); + Vector r = (pevInflictor->origin - pev->origin); + if (flDamage > 200 && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) + m_attacker = ENT(pevAttacker); + DeployThink(); - pev->velocity = r * flDamage / -7; - pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + pev->velocity = r * flDamage / -7; + pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); - // now some func_breakable code + // now some func_breakable code - if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) - return 0; - // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) - flDamage *= 2; + if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) + 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; - g_vecAttackDir = r.Normalize(); + // 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; + g_vecAttackDir = r.Normalize(); - // do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - Killed( VARS(m_attacker), GIB_NORMAL ); - Die(); - return 0; - } + // do the damage + pev->health -= flDamage; + if (pev->health <= 0) + { + Killed( VARS(m_attacker), GIB_NORMAL ); + Die(); + return 0; + } - // Make a shard noise each time func breakable is hit. - // Don't play shard noise if cbreakable actually died. + // Make a shard noise each time func breakable is hit. + // Don't play shard noise if cbreakable actually died. - DamageSound(); - return 1; + DamageSound(); + return 1; } void CProp::KeyValue( KeyValueData* pkvd ) { - ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue); - // 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; + ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue); + // 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); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "material")) + { + int i = atoi( pkvd->szValue); - // 0:glass, 1:metal, 2:flesh, 3:wood + // 0:glass, 1:metal, 2:flesh, 3:wood - if ((i < 0) || (i >= matLastMaterial)) - m_Material = matWood; - else - m_Material = (Materials)i; + if ((i < 0) || (i >= matLastMaterial)) + m_Material = matWood; + else + m_Material = (Materials)i; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shape")) - { - int i = atoi( pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "shape")) + { + int i = atoi( pkvd->szValue); - if ((i < 0) || (i >= SHAPE_NOROTATE)) - m_shape = SHAPE_NOROTATE; - else - m_shape = (PropShape)i; + if ((i < 0) || (i >= SHAPE_NOROTATE)) + m_shape = SHAPE_NOROTATE; + else + m_shape = (PropShape)i; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) - { - ExplosionSetMagnitude( atoi( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "respawntime") ) - { - m_flRespawnTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "customanglesx")) - { - UTIL_StringToIntArray( m_iaCustomAnglesX, ARRAYSIZE( m_iaCustomAnglesX ), pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "customanglesz")) - { - UTIL_StringToIntArray( m_iaCustomAnglesZ, ARRAYSIZE( m_iaCustomAnglesZ ), pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "hmin")) - { - UTIL_StringToVector( minsH, pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "hmax")) - { - UTIL_StringToVector( maxsH, pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "vmin")) - { - UTIL_StringToVector( minsV, pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "vmax")) - { - UTIL_StringToVector( maxsV, pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "gibmodel") ) + { + m_iszGibModel = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) + { + ExplosionSetMagnitude( atoi( pkvd->szValue ) ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "respawntime") ) + { + m_flRespawnTime = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "customanglesx")) + { + UTIL_StringToIntArray( m_iaCustomAnglesX, ARRAYSIZE( m_iaCustomAnglesX ), pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "customanglesz")) + { + UTIL_StringToIntArray( m_iaCustomAnglesZ, ARRAYSIZE( m_iaCustomAnglesZ ), pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "hmin")) + { + UTIL_StringToVector( minsH, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "hmax")) + { + UTIL_StringToVector( maxsH, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "vmin")) + { + UTIL_StringToVector( minsV, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "vmax")) + { + UTIL_StringToVector( maxsV, pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); } From 700a102f86198f299d65c370839b9e4cd0bc9da0 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 2 Mar 2016 15:01:27 +0000 Subject: [PATCH 009/227] Delayed explosion --- dlls/prop.cpp | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/dlls/prop.cpp b/dlls/prop.cpp index f87edf5a..3d8587ee 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -89,9 +89,10 @@ public: virtual int BloodColor(void) { return DONT_BLEED; } virtual void Killed(entvars_t *pevAttacker, int iGib); void CheckRotate(); - void RespawnThink(); - void AngleThink(); - void DeployThink(); + void EXPORT RespawnThink(); + void EXPORT AngleThink(); + void EXPORT DeployThink(); + void EXPORT DieThink(); void DamageSound( void ); void PropRespawn(); void KeyValue( KeyValueData* pkvd); @@ -576,6 +577,8 @@ void CProp::Killed(entvars_t *pevAttacker, int iGib) void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { + if( pev->health <= 0) + return; if (m_owner2 != pActivator->edict()) { if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) @@ -645,6 +648,8 @@ void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, void CProp::Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { + if( pev->health <= 0 ) + return; if (m_owner2 != pActivator->edict()) { if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) @@ -749,6 +754,8 @@ void CProp::DeployThink( void ) void CProp::BounceTouch(CBaseEntity *pOther) { + if( pev->health <= 0 ) + return; //ALERT( at_console, "BounceTouch: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); // only do damage if we're moving fairly fast DeployThink(); @@ -776,8 +783,8 @@ void CProp::BounceTouch(CBaseEntity *pOther) } if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 700) ) { - Killed( VARS(m_attacker), GIB_NORMAL ); - Die(); + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CProp::DieThink ); } pev->velocity = pev->velocity + pOther->pev->velocity; @@ -913,7 +920,14 @@ void CProp::PropRespawn() void CProp::RespawnThink() { if( !(pev->spawnflags & SF_PROP_RESPAWN)) + { + if( pev->health <= 0 ) + { + pev->nextthink = gpGlobals->time + 0.1; + SetThink( &CBaseEntity::SUB_Remove ); + } return; + } PropRespawn(); } @@ -1023,6 +1037,11 @@ void CProp::AngleThink() pev->angles.z = UTIL_AngleMod(pev->angles.z); } +void CProp::DieThink() +{ + Killed( VARS(m_attacker), GIB_NORMAL ); + Die(); +} int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { @@ -1038,6 +1057,8 @@ int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flD if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) return 0; + if ( pev->health <= 0 ) + return; // Breakables take double damage from the crowbar if ( bitsDamageType & DMG_CLUB ) flDamage *= 2; @@ -1049,10 +1070,11 @@ int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flD // do the damage pev->health -= flDamage; - if (pev->health <= 0) + if ( pev->health <= 0 ) { - Killed( VARS(m_attacker), GIB_NORMAL ); - Die(); + // delayed explode + SetThink( &CProp::DieThink ); + pev->nextthink = gpGlobals->time + 0.2; return 0; } From db3aeb6ebf8bc828aec83e862fadfb0d466ae869 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 3 Mar 2016 20:31:01 +0000 Subject: [PATCH 010/227] Change explosion damage type --- dlls/prop.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 3d8587ee..48f43de2 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -397,7 +397,6 @@ void CProp::Die( void ) { Vector vecSpot;// shard origin Vector vecVelocity;// shard velocity - CBaseEntity *pEntity = NULL; char cFlag = 0; int pitch; float fvol; @@ -557,10 +556,12 @@ void CProp::Die( void ) // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - if ( Explodable() ) + if ( Explodable() && (m_attacker != NULL) ) { - ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), TRUE ); + ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), FALSE ); + RadiusDamage ( pev->origin, pev, VARS(m_attacker), ExplosionMagnitude(), ExplosionMagnitude() * 2.5 , CLASS_NONE, DMG_BLAST ); } + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); } void CProp::Killed(entvars_t *pevAttacker, int iGib) @@ -571,8 +572,8 @@ void CProp::Killed(entvars_t *pevAttacker, int iGib) pev->effects |= EF_NODRAW; pev->nextthink = gpGlobals->time + m_flRespawnTime; SetThink( &CProp::RespawnThink ); - ResetTouch( ); - ResetUse( ); + SetTouch( NULL ); + SetUse( NULL ); } void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) @@ -899,20 +900,21 @@ void CProp::Spawn(void) void CProp::PropRespawn() { + UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); + pev->effects &= ~EF_NODRAW; pev->movetype = MOVETYPE_BOUNCE; pev->solid = SOLID_SLIDEBOX; - pev->angles = spawnAngles; pev->takedamage = DAMAGE_YES; + pev->health = m_flSpawnHealth; pev->velocity = pev->avelocity = g_vecZero; + pev->angles = spawnAngles; + pev->deadflag = DEAD_NO; SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetOrigin( pev, spawnOrigin ); - m_oldshape = (PropShape)-1; CheckRotate(); - pev->health = m_flSpawnHealth; - SetTouch( &CProp::BounceTouch); - SetUse( &CProp::Use); - pev->effects &= ~EF_NODRAW; + SetTouch( &CProp::BounceTouch ); + SetUse( &CProp::Use ); + pev->framerate = 1.0f; UTIL_SetOrigin( pev, spawnOrigin ); } From 833bd215d78e5fb898945995d727e1b30f50f3c3 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 3 Mar 2016 20:36:58 +0000 Subject: [PATCH 011/227] Increase detonate threshold --- dlls/prop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 48f43de2..207c1386 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -782,7 +782,7 @@ void CProp::BounceTouch(CBaseEntity *pOther) } m_flNextAttack = gpGlobals->time + 1.0; // debounce } - if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 700) ) + if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 999) ) { pev->nextthink = gpGlobals->time + 0.1; SetThink( &CProp::DieThink ); From d9422fdb86ac25611598177a37ed4b9c44e97a31 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 6 Mar 2016 20:12:08 +0000 Subject: [PATCH 012/227] Text print tweak --- cl_dll/hud_redraw.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 0d7ecba0..f58ffd39 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -201,13 +201,17 @@ int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int gEngfuncs.pfnDrawSetTextColor( r/255.0, g/255.0, b/255.0 ); return gEngfuncs.pfnDrawConsoleString( xpos, ypos, (char*) szIt ); } + + // xash3d: reset unicode state + TextMessageDrawChar( 0, 0, 0, 0, 0, 0 ); + // draw the string until we hit the null character or a newline character for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) { int w = gHUD.m_scrinfo.charWidths[ 'M' ]; if ( xpos + w > iMaxX ) return xpos; - if( *szIt == '^' && *(szIt + 1) >= '0' && *(szIt + 1) <= '7' ) + if( (*szIt == '^') && (*(szIt + 1) >= '0') && (*(szIt + 1) <= '7') ) { szIt++; r = colors[ *szIt - '0' ][0]; @@ -216,8 +220,9 @@ int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int if( !*(++szIt)) return xpos; } + int c = (unsigned int)(unsigned char)*szIt; - xpos += TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + xpos += TextMessageDrawChar( xpos, ypos, c, r, g, b ); } return xpos; @@ -228,7 +233,7 @@ int CHud :: DrawHudStringLen( char *szIt ) int l = 0; for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) { - l += gHUD.m_scrinfo.charWidths[ (unsigned int)*szIt ]; + l += gHUD.m_scrinfo.charWidths[ (unsigned char)*szIt ]; } return l; } From 1ca34fcb4381682bd517612b530db22a1354a795 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 6 Mar 2016 20:12:29 +0000 Subject: [PATCH 013/227] Fix nodes --- dlls/nodes.cpp | 18 +++++++++--------- dlls/nodes.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 058260b3..1a55cd43 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -42,7 +42,7 @@ LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); #ifdef __linux__ #include -#include +#include #define CreateDirectory(p, n) mkdir(p, 0777) #endif //========================================================= @@ -515,13 +515,13 @@ 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]; + signed char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; // Until we decode the next best node // while (nCount > 0) { - char ch = *pRoute++; + signed char ch = *pRoute++; //ALERT(at_aiconsole, "C(%d)", ch); if (ch < 0) { @@ -2420,7 +2420,7 @@ int CGraph :: FLoadGraph ( char *szMapName ) // Malloc for the routing info. // m_fRoutingComplete = FALSE; - m_pRouteInfo = (char *)calloc( sizeof(char), m_nRouteInfo ); + m_pRouteInfo = (signed char *)calloc( sizeof(signed char), m_nRouteInfo ); if ( !m_pRouteInfo ) { ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d route bytes!\n", m_nRouteInfo ); @@ -2534,7 +2534,7 @@ int CGraph :: FSaveGraph ( char *szMapName ) // if ( m_pRouteInfo && m_nRouteInfo ) { - fwrite ( m_pRouteInfo, sizeof( char ), m_nRouteInfo, file ); + fwrite ( m_pRouteInfo, sizeof( signed char ), m_nRouteInfo, file ); } if (m_pHashLinks && m_nHashLinks) @@ -3035,7 +3035,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) int *pMyPath = new int[m_cNodes]; unsigned short *BestNextNodes = new unsigned short[m_cNodes]; - char *pRoute = new char[m_cNodes*2]; + signed char *pRoute = new signed char[m_cNodes*2]; if (Routes && pMyPath && BestNextNodes && pRoute) @@ -3129,7 +3129,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) int cSequence = 0; int cRepeats = 0; int CompressedSize = 0; - char *p = pRoute; + signed char *p = pRoute; for (int i = 0; i < m_cNodes; i++) { BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); @@ -3289,7 +3289,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) } else { - char *Tmp = (char *)calloc(sizeof(char), (m_nRouteInfo + nRoute)); + signed char *Tmp = (signed char *)calloc(sizeof(signed char), (m_nRouteInfo + nRoute)); memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); free(m_pRouteInfo); m_pRouteInfo = Tmp; @@ -3302,7 +3302,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) else { m_nRouteInfo = nRoute; - m_pRouteInfo = (char *)calloc(sizeof(char), nRoute); + m_pRouteInfo = (signed char *)calloc(sizeof(signed char), nRoute); memcpy(m_pRouteInfo, pRoute, nRoute); m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; nTotalCompressedSize += CompressedSize; diff --git a/dlls/nodes.h b/dlls/nodes.h index 6b6739d6..cc1b6e20 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -116,7 +116,7 @@ public: 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. + signed char *m_pRouteInfo; // compressed routing information the nodes use. int m_cNodes;// total number of nodes int m_cLinks;// total number of links From f2ea272c0265d142027e17213d99136609b32c40 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 6 Mar 2016 20:13:35 +0000 Subject: [PATCH 014/227] [prop] Attacker/owner/damage tweak --- dlls/prop.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 207c1386..86b1bf8a 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -782,7 +782,7 @@ void CProp::BounceTouch(CBaseEntity *pOther) } m_flNextAttack = gpGlobals->time + 1.0; // debounce } - if( (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 999) ) + if( (pOther->edict() != m_owner2) && (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 900) ) { pev->nextthink = gpGlobals->time + 0.1; SetThink( &CProp::DieThink ); @@ -1048,12 +1048,15 @@ void CProp::DieThink() int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { Vector r = (pevInflictor->origin - pev->origin); - if (flDamage > 200 && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) + if ( (!m_attacker + || (pev->velocity.Length() < 700)) + && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) m_attacker = ENT(pevAttacker); DeployThink(); pev->velocity = r * flDamage / -7; pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + ALERT(at_console, "Takedmg: %s %s %f %f\n", STRING(pevInflictor->classname), STRING(pevAttacker->classname), flDamage, pev->health ); // now some func_breakable code From 9fd279a9741fc0bf9b29dac7e1d2e764b80e3351 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 9 Mar 2016 17:11:16 +0600 Subject: [PATCH 015/227] Fix DLLEXPORT macro and move it's defination to separate file --- cl_dll/GameStudioModelRenderer.cpp | 5 ---- cl_dll/GameStudioModelRenderer_Sample.cpp | 2 +- cl_dll/cdll_int.cpp | 7 ------ cl_dll/cl_dll.h | 5 ++-- cl_dll/cl_util.h | 2 +- cl_dll/demo.cpp | 8 +------ cl_dll/entity.cpp | 6 ----- cl_dll/hud_iface.h | 10 ++------ cl_dll/in_defs.h | 2 -- cl_dll/tri.cpp | 8 +------ dlls/cbase.h | 28 ++++++++++------------- dlls/exportdef.h | 18 +++++++++++++++ dlls/h_export.cpp | 5 +++- dlls/util.h | 15 ++++-------- 14 files changed, 48 insertions(+), 73 deletions(-) create mode 100644 dlls/exportdef.h diff --git a/cl_dll/GameStudioModelRenderer.cpp b/cl_dll/GameStudioModelRenderer.cpp index 7d60d6ea..9cfca965 100644 --- a/cl_dll/GameStudioModelRenderer.cpp +++ b/cl_dll/GameStudioModelRenderer.cpp @@ -99,11 +99,6 @@ HUD_GetStudioModelInterface Export this function for the engine to use the studio renderer class to render objects. ==================== */ -#ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) { if ( version != STUDIO_INTERFACE_VERSION ) diff --git a/cl_dll/GameStudioModelRenderer_Sample.cpp b/cl_dll/GameStudioModelRenderer_Sample.cpp index 5ea50b51..ec31e479 100644 --- a/cl_dll/GameStudioModelRenderer_Sample.cpp +++ b/cl_dll/GameStudioModelRenderer_Sample.cpp @@ -972,7 +972,7 @@ HUD_GetStudioModelInterface Export this function for the engine to use the studio renderer class to render objects. ==================== */ -#define DLLEXPORT __declspec( dllexport ) + extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) { if ( version != STUDIO_INTERFACE_VERSION ) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 1ad81773..ea512306 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -29,13 +29,6 @@ extern "C" #include -#ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif - - cl_enginefunc_t gEngfuncs; CHud gHUD; mobile_engfuncs_t *gMobileEngfuncs = NULL; diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index aeacb8be..4b28b3a6 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -31,13 +31,14 @@ typedef float vec_t; typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); #include "util_vector.h" -#define EXPORT _declspec( dllexport ) #include "../engine/cdll_int.h" #include "../dlls/cdll_dll.h" - +#ifndef __MSC_VER #define _cdecl +#endif +#include "exportdef.h" #include extern cl_enginefunc_t gEngfuncs; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 17e22ee6..4876ca27 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -15,7 +15,7 @@ // // cl_util.h // - +#include "exportdef.h" #include "cvardef.h" #ifndef TRUE diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp index 88e7f66f..a62b239f 100644 --- a/cl_dll/demo.cpp +++ b/cl_dll/demo.cpp @@ -18,12 +18,6 @@ #include "demo_api.h" #include -#ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif - int g_demosniper = 0; int g_demosniperdamage = 0; float g_demosniperorg[3]; @@ -104,4 +98,4 @@ void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); break; } -} \ No newline at end of file +} diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index ad4a8411..d8d8f015 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -20,12 +20,6 @@ #include "pmtrace.h" #include "pm_shared.h" -#ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif - void Game_AddObjects( void ); diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h index 8427d77f..3f6dd599 100644 --- a/cl_dll/hud_iface.h +++ b/cl_dll/hud_iface.h @@ -9,17 +9,11 @@ #define HUD_IFACEH #pragma once -#ifdef _WIN32 -#define EXPORT _declspec( dllexport ) -#define _DLLEXPORT __declspec( dllexport ) -#else -#define EXPORT -#define _DLLEXPORT -#endif +#include "exportdef.h" typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); #include "wrect.h" #include "../engine/cdll_int.h" extern cl_enginefunc_t gEngfuncs; -#endif \ No newline at end of file +#endif diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index b78ffa9e..9ab880e9 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -17,9 +17,7 @@ #define ROLL 2 #ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) #else -#define DLLEXPORT typedef struct point_s{ int x; int y; diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp index 02be4ef4..ef37c7a4 100644 --- a/cl_dll/tri.cpp +++ b/cl_dll/tri.cpp @@ -17,12 +17,6 @@ #include "cl_entity.h" #include "triangleapi.h" -#ifdef _WIN32 -#define DLLEXPORT __declspec( dllexport ) -#else -#define DLLEXPORT -#endif - extern "C" { void DLLEXPORT HUD_DrawNormalTriangles( void ); @@ -125,4 +119,4 @@ void DLLEXPORT HUD_DrawTransparentTriangles( void ) #if defined( TEST_IT ) // Draw_Triangles(); #endif -} \ No newline at end of file +} diff --git a/dlls/cbase.h b/dlls/cbase.h index 1aa64bb3..1aefe687 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -51,11 +51,7 @@ CBaseEntity // C functions for external declarations that call the appropriate C++ methods -#ifdef _WIN32 -#define EXPORT _declspec( dllexport ) -#else -#define EXPORT /* */ -#endif +#include "exportdef.h" extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); @@ -373,15 +369,15 @@ public: #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) -#define ResetThink( ) m_pfnThink = static_cast (NULL) -#define ResetTouch( ) m_pfnTouch = static_cast (NULL) -#define ResetUse( ) m_pfnUse = static_cast (NULL) -#define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) - +#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) +#define ResetThink( ) m_pfnThink = static_cast (NULL) +#define ResetTouch( ) m_pfnTouch = static_cast (NULL) +#define ResetUse( ) m_pfnUse = static_cast (NULL) +#define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) + #endif @@ -557,8 +553,8 @@ public: // the button will be allowed to operate. Otherwise, it will be // deactivated. }; -#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) - +#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) + // people gib if their health is <= this at the time of death diff --git a/dlls/exportdef.h b/dlls/exportdef.h new file mode 100644 index 00000000..77a46734 --- /dev/null +++ b/dlls/exportdef.h @@ -0,0 +1,18 @@ +#ifndef EXPORTDEF_H +#define EXPORTDEF_H +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define EXPORT __attribute__ ((dllexport)) + #else + #define EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. + #endif +#else + #if __GNUC__ >= 4 + #define EXPORT __attribute__ ((visibility ("default"))) + #else + #define EXPORT + #endif +#endif +#define DLLEXPORT EXPORT +#define _DLLEXPORT EXPORT +#endif // EXPORTDEF_H diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index 0d56d045..bdbad2c6 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -47,7 +47,10 @@ BOOL WINAPI DllMain( return TRUE; } -void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) __attribute__((__stdcall__)) ; + + +extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; diff --git a/dlls/util.h b/dlls/util.h index ab3dfd5c..1edc0411 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -27,9 +27,9 @@ #include "physcallback.h" #endif - -#include -#include + +#include +#include 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; @@ -92,13 +92,8 @@ typedef int BOOL; // 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 -#ifdef _WIN32 -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ - extern "C" _declspec( dllexport ) void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } -#else -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" void mapClassName( entvars_t *pev ); void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } -#endif + +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" EXPORT void mapClassName( entvars_t *pev ); void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } // From dccb3f4aab3ddd6e88275625d827c5482f76cc87 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 9 Mar 2016 18:43:27 +0600 Subject: [PATCH 016/227] Fix mingw --- cl_dll/in_defs.h | 1 + cl_dll/input_xash3d.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index 9ab880e9..9f30b17a 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -17,6 +17,7 @@ #define ROLL 2 #ifdef _WIN32 +#include #else typedef struct point_s{ int x; diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index e1023872..69980a39 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -5,7 +5,6 @@ #include "keydefs.h" cvar_t *sensitivity; cvar_t *in_joystick; -#define DLLEXPORT #define PITCH 0 #define YAW 1 #define ROLL 2 @@ -208,7 +207,7 @@ void IN_Move( float frametime, usercmd_t *cmd ) ac_movecount = 0; } -extern "C" void IN_MouseEvent( int mstate ) +extern "C" void DLLEXPORT IN_MouseEvent( int mstate ) { static int mouse_oldbuttonstate; // perform button actions @@ -230,22 +229,22 @@ extern "C" void IN_MouseEvent( int mstate ) // Stubs -extern "C" void IN_ClearStates ( void ) +extern "C" void DLLEXPORT IN_ClearStates ( void ) { //gEngfuncs.Con_Printf("IN_ClearStates\n"); } -extern "C" void IN_ActivateMouse ( void ) +extern "C" void DLLEXPORT IN_ActivateMouse ( void ) { //gEngfuncs.Con_Printf("IN_ActivateMouse\n"); } -extern "C" void IN_DeactivateMouse ( void ) +extern "C" void DLLEXPORT IN_DeactivateMouse ( void ) { //gEngfuncs.Con_Printf("IN_DeactivateMouse\n"); } -extern "C" void IN_Accumulate ( void ) +extern "C" void DLLEXPORT IN_Accumulate ( void ) { //gEngfuncs.Con_Printf("IN_Accumulate\n"); } From c16d00c170cffbf984eb218434568b86868487d8 Mon Sep 17 00:00:00 2001 From: a1batross Date: Sat, 2 Apr 2016 19:24:11 +0300 Subject: [PATCH 017/227] Remove prop.cpp from Android.mk, because we need a clean Half-Life in master branch --- dlls/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index 81b15c1e..38e6a019 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -124,7 +124,6 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ world.cpp \ xen.cpp \ zombie.cpp \ - prop.cpp \ ../pm_shared/pm_debug.c \ ../pm_shared/pm_math.c \ ../pm_shared/pm_shared.c \ From 5d96c43c65f4e26dbcbbcaffeb265a6353a245b4 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 5 Apr 2016 15:39:01 +0000 Subject: [PATCH 018/227] Fix crash --- cl_dll/view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index d547496e..2af0f8c9 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -1333,7 +1333,7 @@ int V_FindViewModelByWeaponModel(int weaponindex) int len = strlen( weaponModel->name ); int i = 0; - while ( modelmap[i] != NULL ) + while ( modelmap[i][0] != NULL ) { if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) { From b98bfe7578876a23b562842bd99c595db4f62ff8 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Fri, 15 Apr 2016 00:48:22 +0500 Subject: [PATCH 019/227] Remove duplicate header. --- cl_dll/wrect.h | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 cl_dll/wrect.h diff --git a/cl_dll/wrect.h b/cl_dll/wrect.h deleted file mode 100644 index 620b8163..00000000 --- a/cl_dll/wrect.h +++ /dev/null @@ -1,16 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( WRECTH ) -#define WRECTH - -typedef struct rect_s -{ - int left, right, top, bottom; -} wrect_t; - -#endif \ No newline at end of file From 3348f5d21431578f401c0684fb031d964c2ad580 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 17 Apr 2016 14:31:24 +0000 Subject: [PATCH 020/227] Check +speed value --- cl_dll/Android.mk | 2 +- cl_dll/input_xash3d.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 83417047..b5f3f311 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -21,7 +21,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard) LOCAL_MODULE_FILENAME = libclient_hardfp endif -LOCAL_CFLAGS += -fsigned-char -DCLIENT_DLL=1 +LOCAL_CFLAGS += -DCLIENT_DLL=1 SRCS= SRCS_C= diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index 69980a39..dd621d19 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -201,6 +201,12 @@ void IN_Move( float frametime, usercmd_t *cmd ) IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); if( ac_forwardmove ) cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; if( ac_sidemove ) cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; + if (in_speed.state & 1) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + } + } ac_sidemove = ac_forwardmove = rel_pitch = rel_yaw = 0; From 0adbd65d8a3bb95c7408814e002a3d1dae4bd370 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 18 Apr 2016 01:30:05 +0500 Subject: [PATCH 021/227] Fix build clang. Fix UB. --- cl_dll/StudioModelRenderer.cpp | 4 +- cl_dll/camera.h | 2 +- cl_dll/cl_util.h | 4 +- cl_dll/death.cpp | 3 +- cl_dll/entity.cpp | 4 +- cl_dll/geiger.cpp | 2 +- cl_dll/health.cpp | 6 +-- cl_dll/hl/hl_weapons.cpp | 2 +- cl_dll/hud.cpp | 5 ++- cl_dll/hud_spectator.cpp | 3 ++ cl_dll/menu.cpp | 4 +- cl_dll/message.cpp | 2 +- cl_dll/saytext.cpp | 3 +- cl_dll/scoreboard.cpp | 2 +- cl_dll/status_icons.cpp | 4 +- cl_dll/view.cpp | 5 +-- dlls/aflock.cpp | 14 +++---- dlls/airtank.cpp | 4 +- dlls/apache.cpp | 24 ++++++------ dlls/barnacle.cpp | 4 +- dlls/barney.cpp | 2 +- dlls/bigmomma.cpp | 2 +- dlls/bmodels.cpp | 30 +++++++-------- dlls/bullsquid.cpp | 4 +- dlls/buttons.cpp | 46 +++++++++++------------ dlls/client.cpp | 4 +- dlls/combat.cpp | 16 ++++---- dlls/controller.cpp | 10 ++--- dlls/crossbow.cpp | 10 ++--- dlls/crowbar.cpp | 4 +- dlls/doors.cpp | 20 +++++----- dlls/effects.cpp | 40 ++++++++++---------- dlls/effects.h | 4 +- dlls/explode.cpp | 2 +- dlls/func_break.cpp | 8 ++-- dlls/gargantua.cpp | 8 ++-- dlls/ggrenade.cpp | 22 +++++------ dlls/h_battery.cpp | 10 ++--- dlls/h_cine.cpp | 10 ++--- dlls/h_cycler.cpp | 2 +- dlls/handgrenade.cpp | 2 +- dlls/headcrab.cpp | 2 +- dlls/healthkit.cpp | 10 ++--- dlls/hgrunt.cpp | 4 +- dlls/hornet.cpp | 16 ++++---- dlls/houndeye.cpp | 2 +- dlls/ichthyosaur.cpp | 6 +-- dlls/items.cpp | 6 +-- dlls/leech.cpp | 4 +- dlls/monstermaker.cpp | 12 +++--- dlls/monsters.cpp | 8 ++-- dlls/mortar.cpp | 6 +-- dlls/multiplay_gamerules.cpp | 2 +- dlls/nihilanth.cpp | 33 +++++++++-------- dlls/nodes.cpp | 68 +++++++++++++++++++--------------- dlls/osprey.cpp | 18 ++++----- dlls/plats.cpp | 50 ++++++++++++------------- dlls/player.cpp | 18 ++++----- dlls/player.h | 2 +- dlls/roach.cpp | 2 +- dlls/rpg.cpp | 12 +++--- dlls/satchel.cpp | 10 ++--- dlls/saverestore.h | 2 +- dlls/scientist.cpp | 6 +-- dlls/scripted.cpp | 18 ++++----- dlls/sound.cpp | 14 +++---- dlls/soundent.cpp | 4 +- dlls/squeakgrenade.cpp | 12 +++--- dlls/subs.cpp | 6 +-- dlls/talkmonster.cpp | 12 +++--- dlls/tempmonster.cpp | 2 +- dlls/tentacle.cpp | 14 +++---- dlls/triggers.cpp | 46 +++++++++++------------ dlls/tripmine.cpp | 16 ++++---- dlls/turret.cpp | 48 ++++++++++++------------ dlls/util.cpp | 4 +- dlls/util.h | 4 +- dlls/weapons.cpp | 24 ++++++------ dlls/weapons.h | 2 +- dlls/world.cpp | 12 +++--- game_shared/bitvec.h | 2 +- game_shared/voice_gamemgr.cpp | 4 +- 82 files changed, 459 insertions(+), 441 deletions(-) diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index e0845c29..ee8ae56f 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -782,7 +782,7 @@ StudioSetupBones */ void CStudioModelRenderer::StudioSetupBones ( void ) { - int i; + int i, j; double f; mstudiobone_t *pbones; @@ -911,7 +911,7 @@ void CStudioModelRenderer::StudioSetupBones ( void ) for (i = 0; i < m_pStudioHeader->numbones; i++) { - for( int j = 0; j < LEGS_BONES_COUNT; j++ ) + for( j = 0; j < LEGS_BONES_COUNT; j++ ) { if( !strcmp( pbones[i].name, legs_bones[j] )) break; diff --git a/cl_dll/camera.h b/cl_dll/camera.h index af1591d7..83dc04ff 100644 --- a/cl_dll/camera.h +++ b/cl_dll/camera.h @@ -9,7 +9,7 @@ // NOTE: must include quakedef.h first #ifndef _CAMERA_H_ -#define _CAMEA_H_ +#define _CAMERA_H_ // pitch, yaw, dist extern vec3_t cam_ofs; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 4876ca27..436b122b 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -84,7 +84,7 @@ inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int fl #define AngleVectors (*gEngfuncs.pfnAngleVectors) extern cvar_t *hud_textmode; extern float g_hud_text_color[3]; -inline int DrawSetTextColor(float r, float g, float b) +inline void DrawSetTextColor(float r, float g, float b) { if( hud_textmode->value == 1 ) g_hud_text_color[0]=r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; @@ -111,7 +111,7 @@ inline int DrawConsoleString( int x, int y, const char *string ) inline void GetConsoleStringSize( const char *string, int *width, int *height ) { if( hud_textmode->value == 1 ) - *height = 13, *width = gHUD.DrawHudStringLen(string); + *height = 13, *width = gHUD.DrawHudStringLen( (char*)string ); else gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); } diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 760b005c..fdeaae46 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -157,6 +157,7 @@ int CHudDeathNotice :: Draw( float flTime ) // This message handler may be better off elsewhere int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) { + int i; m_iFlags |= HUD_ACTIVE; BEGIN_READ( pbuf, iSize ); @@ -171,7 +172,7 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p gHUD.m_Spectator.DeathMessage(victim); - for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + for ( i = 0; i < MAX_DEATHNOTICES; i++ ) { if ( rgDeathNoticeList[i].iId == 0 ) break; diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index d8d8f015..fb5770c6 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -723,8 +723,8 @@ void DLLEXPORT HUD_TempEntUpdate ( s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); - pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); - pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)(size_t)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)(size_t)pTemp ); pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; } diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 6f5f984f..1a514815 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -64,7 +64,7 @@ int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) int CHudGeiger::Draw (float flTime) { int pct; - float flvol; + float flvol = 0.0f; int rg[3]; int i; diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index 0b73efca..9a4ff660 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -377,7 +377,7 @@ int CHudHealth::DrawPain(float flTime) int CHudHealth::DrawDamage(float flTime) { - int r, g, b, a; + int i, r, g, b, a; DAMAGE_IMAGE *pdmg; if (!m_bitsDamage) @@ -390,7 +390,7 @@ int CHudHealth::DrawDamage(float flTime) ScaleColors(r, g, b, a); // Draw all the items - for (int i = 0; i < NUM_DMG_TYPES; i++) + for (i = 0; i < NUM_DMG_TYPES; i++) { if (m_bitsDamage & giDmgFlags[i]) { @@ -404,7 +404,7 @@ int CHudHealth::DrawDamage(float flTime) // check for bits that should be expired for ( i = 0; i < NUM_DMG_TYPES; i++ ) { - DAMAGE_IMAGE *pdmg = &m_dmg[i]; + pdmg = &m_dmg[i]; if ( m_bitsDamage & giDmgFlags[i] ) { diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 3572bdaa..581b2e89 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -621,7 +621,7 @@ void HUD_InitClientWeapons( void ) // Pass through to engine g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; - g_engfuncs.pfnRandomLong = RandomLong; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; // Allocate a slot for the local player HUD_PrepEntity( &player , NULL ); diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 36bb50ad..d99ce6bb 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -280,6 +280,7 @@ int CHud :: GetSpriteIndex( const char *SpriteName ) void CHud :: VidInit( void ) { + int j; m_scrinfo.iSize = sizeof(m_scrinfo); GetScreenInfo(&m_scrinfo); @@ -307,7 +308,7 @@ void CHud :: VidInit( void ) // count the number of sprites of the appropriate res m_iSpriteCount = 0; client_sprite_t *p = m_pSpriteList; - for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) { if ( p->iRes == m_iRes ) m_iSpriteCount++; @@ -346,7 +347,7 @@ void CHud :: VidInit( void ) // count the number of sprites of the appropriate res m_iSpriteCount = 0; - for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) { if ( p->iRes == m_iRes ) m_iSpriteCount++; diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index be6d45e8..33a95d35 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -874,6 +874,9 @@ bool CHudSpectator::ParseOverviewFile( ) char *pfile = NULL; + memset( filename, 0, 255 ); + memset( levelname, 0, 255 ); + memset( token, 0, 1024 ); memset( &m_OverviewData, 0, sizeof(m_OverviewData)); // fill in standrd values diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index 60ae2403..f43984dd 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -64,6 +64,8 @@ int CHudMenu :: VidInit( void ) int CHudMenu :: Draw( float flTime ) { + int i; + // check for if menu is set to disappear if ( m_flShutoffTime > 0 ) { @@ -83,7 +85,7 @@ int CHudMenu :: Draw( float flTime ) // count the number of newlines int nlc = 0; - for ( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) { if ( g_szMenuString[i] == '\n' ) nlc++; diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index 61ea55a7..e6bb857d 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -140,7 +140,7 @@ int CHudMessage::YPosition( float y, int height ) void CHudMessage::MessageScanNextChar( void ) { - int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue; + int srcRed, srcGreen, srcBlue, destRed = 0, destGreen = 0, destBlue = 0; int blend; srcRed = m_parms.pMessage->r1; diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 3a7616a5..ddfa00fe 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -162,10 +162,11 @@ int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) { + int i; ConsolePrint( pszBuf ); // find an empty string slot - for ( int i = 0; i < MAX_LINES; i++ ) + for ( i = 0; i < MAX_LINES; i++ ) { if ( ! *g_szLineBuffer[i] ) break; diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index c7431328..9fca2b7a 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -526,7 +526,7 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb if ( j > m_iNumTeams ) { // they aren't in a listed team, so make a new one // search through for an empty team slot - for ( int j = 1; j <= m_iNumTeams; j++ ) + for ( j = 1; j <= m_iNumTeams; j++ ) { if ( g_TeamInfo[j].name[0] == '\0' ) break; diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index 9207143e..10ca630a 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -106,8 +106,10 @@ int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *p // add the icon to the icon list, and set it's drawing color void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) { + int i; + // check to see if the sprite is in the current list - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + for ( i = 0; i < MAX_ICONSPRITES; i++ ) { if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) break; diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index 2af0f8c9..5c022148 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -134,7 +134,7 @@ void V_NormalizeAngles( float *angles ) } } -/* + =================== V_InterpolateAngles @@ -466,7 +466,7 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) waterOffset = 0; if ( pparams->waterlevel >= 2 ) { - int i, contents, waterDist, waterEntity; + int contents, waterDist, waterEntity; vec3_t point; waterDist = cl_waterdist->value; @@ -661,7 +661,6 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) { int foundidx; - int i; float t; if ( cl_vsmoothing->value < 0.0 ) diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index f536b4f0..95e3dc16 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -229,7 +229,7 @@ void CFlockingFlyer :: Spawn( ) pev->frame = 0; pev->nextthink = gpGlobals->time + 0.1; - SetThink( &IdleThink ); + SetThink( &CFlockingFlyer::IdleThink ); } //========================================================= @@ -292,7 +292,7 @@ void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); pev->movetype = MOVETYPE_TOSS; - SetThink( &FallHack ); + SetThink( &CFlockingFlyer::FallHack ); pev->nextthink = gpGlobals->time + 0.1; } @@ -366,7 +366,7 @@ void CFlockingFlyer :: IdleThink( void ) // see if there's a client in the same pvs as the monster if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { - SetThink( &Start ); + SetThink( &CFlockingFlyer::Start ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -380,11 +380,11 @@ void CFlockingFlyer :: Start( void ) if ( IsLeader() ) { - SetThink( &FlockLeaderThink ); + SetThink( &CFlockingFlyer::FlockLeaderThink ); } else { - SetThink( &FlockFollowerThink ); + SetThink( &CFlockingFlyer::FlockFollowerThink ); } /* @@ -438,7 +438,7 @@ void CFlockingFlyer :: FormFlock( void ) } } - SetThink( &IdleThink );// now that flock is formed, go to idle and wait for a player to come along. + SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along. pev->nextthink = gpGlobals->time; } @@ -673,7 +673,7 @@ void CFlockingFlyer :: FlockFollowerThink( void ) if ( IsLeader() || !InSquad() ) { // the leader has been killed and this flyer suddenly finds himself the leader. - SetThink( &FlockLeaderThink ); + SetThink( &CFlockingFlyer::FlockLeaderThink ); return; } diff --git a/dlls/airtank.cpp b/dlls/airtank.cpp index b244f581..27901fc7 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -58,8 +58,8 @@ void CAirtank :: Spawn( void ) UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( &TankTouch ); - SetThink( &TankThink ); + SetTouch( &CAirtank::TankTouch ); + SetThink( &CAirtank::TankThink ); pev->flags |= FL_MONSTER; pev->takedamage = DAMAGE_YES; diff --git a/dlls/apache.cpp b/dlls/apache.cpp index fae0ff34..607679bf 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -139,12 +139,12 @@ void CApache :: Spawn( void ) if (pev->spawnflags & SF_WAITFORTRIGGER) { - SetUse( &StartupUse ); + SetUse( &CApache::StartupUse ); } else { - SetThink( &HuntThink ); - SetTouch( &FlyTouch ); + SetThink( &CApache::HuntThink ); + SetTouch( &CApache::FlyTouch ); pev->nextthink = gpGlobals->time + 1.0; } @@ -186,8 +186,8 @@ void CApache::NullThink( void ) void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &HuntThink ); - SetTouch( &FlyTouch ); + SetThink( &CApache::HuntThink ); + SetTouch( &CApache::FlyTouch ); pev->nextthink = gpGlobals->time + 0.1; SetUse( NULL ); } @@ -200,8 +200,8 @@ void CApache :: Killed( entvars_t *pevAttacker, int iGib ) STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( &DyingThink ); - SetTouch( &CrashTouch ); + SetThink( &CApache::DyingThink ); + SetTouch( &CApache::CrashTouch ); pev->nextthink = gpGlobals->time + 0.1; pev->health = 0; pev->takedamage = DAMAGE_NO; @@ -402,7 +402,7 @@ void CApache :: DyingThink( void ) WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -972,8 +972,8 @@ void CApacheHVR :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( &IgniteThink ); - SetTouch( &ExplodeTouch ); + SetThink( &CApacheHVR::IgniteThink ); + SetTouch( &CGrenade::ExplodeTouch ); UTIL_MakeAimVectors( pev->angles ); m_vecForward = gpGlobals->v_forward; @@ -1019,7 +1019,7 @@ void CApacheHVR :: IgniteThink( void ) MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) // set to accelerate - SetThink( &AccelerateThink ); + SetThink( &CApacheHVR::AccelerateThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -1047,4 +1047,4 @@ void CApacheHVR :: AccelerateThink( void ) } -#endif \ No newline at end of file +#endif diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp index aaf8c539..1681b5a3 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -137,7 +137,7 @@ void CBarnacle :: Spawn() SetActivity ( ACT_IDLE ); - SetThink( &BarnacleThink ); + SetThink( &CBarnacle::BarnacleThink ); pev->nextthink = gpGlobals->time + 0.5; UTIL_SetOrigin ( pev, pev->origin ); @@ -370,7 +370,7 @@ void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) StudioFrameAdvance( 0.1 ); pev->nextthink = gpGlobals->time + 0.1; - SetThink( &WaitTillDead ); + SetThink( &CBarnacle::WaitTillDead ); } //========================================================= diff --git a/dlls/barney.cpp b/dlls/barney.cpp index 7837c5c0..9cfa6a37 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -424,7 +424,7 @@ void CBarney :: Spawn() m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; MonsterInit(); - SetUse( &FollowerUse ); + SetUse( &CTalkMonster::FollowerUse ); } //========================================================= diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index 06f98da1..b7f999d1 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -1198,7 +1198,7 @@ CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity pSpit->pev->velocity = vecVelocity; pSpit->pev->owner = pOwner; pSpit->pev->scale = 2.5; - pSpit->SetThink( &Animate ); + pSpit->SetThink( &CBMortar::Animate ); pSpit->pev->nextthink = gpGlobals->time + 0.1; return pSpit; diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index 1ab8afc7..bc788a93 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -419,7 +419,7 @@ void CFuncRotating :: Spawn( ) UTIL_SetOrigin(pev, pev->origin); SET_MODEL( ENT(pev), STRING(pev->model) ); - SetUse( &RotatingUse ); + SetUse( &CFuncRotating::RotatingUse ); // did level designer forget to assign speed? if (pev->speed <= 0) pev->speed = 0; @@ -431,13 +431,13 @@ void CFuncRotating :: Spawn( ) // instant-use brush? if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) { - SetThink( &SUB_CallUseToggle ); + SetThink( &CBaseEntity::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( &HurtTouch ); + SetTouch( &CFuncRotating::HurtTouch ); } Precache( ); @@ -504,7 +504,7 @@ void CFuncRotating :: Precache( void ) // 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( &SpinUp ); + SetThink( &CFuncRotating::SpinUp ); pev->nextthink = pev->ltime + 1.5; } } @@ -600,7 +600,7 @@ void CFuncRotating :: SpinUp( void ) EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); - SetThink( &Rotate ); + SetThink( &CFuncRotating::Rotate ); Rotate(); } else @@ -641,7 +641,7 @@ void CFuncRotating :: SpinDown( void ) EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), 0, 0, SND_STOP, m_pitch); - SetThink( &Rotate ); + SetThink( &CFuncRotating::Rotate ); Rotate(); } else @@ -666,7 +666,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller // fan is spinning, so stop it. if ( pev->avelocity != g_vecZero ) { - SetThink( &SpinDown ); + SetThink( &CFuncRotating::SpinDown ); //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), // m_flVolume, m_flAttenuation, 0, m_pitch); @@ -674,7 +674,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller } else// fan is not moving, so start it { - SetThink( &SpinUp ); + SetThink( &CFuncRotating::SpinUp ); EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), 0.01, m_flAttenuation, 0, FANPITCHMIN); @@ -686,7 +686,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller if ( pev->avelocity != g_vecZero ) { // play stopping sound here - SetThink( &SpinDown ); + SetThink( &CFuncRotating::SpinDown ); // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), // m_flVolume, m_flAttenuation, 0, m_pitch); @@ -700,7 +700,7 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller m_flVolume, m_flAttenuation, 0, FANPITCHMAX); pev->avelocity = pev->movedir * pev->speed; - SetThink( &Rotate ); + SetThink( &CFuncRotating::Rotate ); Rotate(); } } @@ -812,15 +812,15 @@ void CPendulum :: Spawn( void ) if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) { - SetThink( &SUB_CallUseToggle ); + SetThink( &CBaseEntity::SUB_CallUseToggle ); pev->nextthink = gpGlobals->time + 0.1; } pev->speed = 0; - SetUse( &PendulumUse ); + SetUse( &CPendulum::PendulumUse ); if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) { - SetTouch( &RopeTouch ); + SetTouch( &CPendulum::RopeTouch ); } } @@ -837,7 +837,7 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US pev->avelocity = m_maxSpeed * pev->movedir; pev->nextthink = pev->ltime + (delta / m_maxSpeed); - SetThink( &Stop ); + SetThink( &CPendulum::Stop ); } else { @@ -850,7 +850,7 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US { pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving m_time = gpGlobals->time; // Save time to calculate dt - SetThink( &Swing ); + SetThink( &CPendulum::Swing ); m_dampSpeed = m_maxSpeed; } } diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 6a1ffe19..0e34a537 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -121,7 +121,7 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity pSpit->pev->velocity = vecVelocity; pSpit->pev->owner = ENT(pevOwner); - pSpit->SetThink( &Animate ); + pSpit->SetThink( &CSquidSpit::Animate ); pSpit->pev->nextthink = gpGlobals->time + 0.1; } @@ -172,7 +172,7 @@ void CSquidSpit :: Touch ( CBaseEntity *pOther ) pOther->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); } - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 44f413bc..8ca2ad60 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -173,7 +173,7 @@ void CMultiSource::Spawn() pev->movetype = MOVETYPE_NONE; pev->nextthink = gpGlobals->time + 0.1; pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized - SetThink( &Register); + SetThink( &CMultiSource::Register); } void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) @@ -240,7 +240,7 @@ void CMultiSource::Register(void) m_iTotal = 0; memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); - SetThink( &SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing); // search for all entities which target this multisource (pev->targetname) @@ -455,7 +455,7 @@ void CBaseButton::Spawn( ) if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state { - SetThink( &ButtonSpark ); + SetThink( &CBaseButton::ButtonSpark ); pev->nextthink = gpGlobals->time + 0.5;// no hurry, make sure everything else spawns } @@ -495,12 +495,12 @@ void CBaseButton::Spawn( ) if ( FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button { - SetTouch( &ButtonTouch ); + SetTouch( &CBaseButton::ButtonTouch ); } else { SetTouch( NULL ); - SetUse( &ButtonUse ); + SetUse( &CBaseButton::ButtonUse ); } } @@ -567,7 +567,7 @@ void DoSpark(entvars_t *pev, const Vector &location ) void CBaseButton::ButtonSpark ( void ) { - SetThink( &ButtonSpark ); + SetThink( &CBaseButton::ButtonSpark ); pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval DoSpark( pev, pev->mins ); @@ -680,7 +680,7 @@ void CBaseButton::ButtonActivate( ) ASSERT(m_toggle_state == TS_AT_BOTTOM); m_toggle_state = TS_GOING_UP; - SetMoveDone( &TriggerAndWait ); + SetMoveDone( &CBaseButton::TriggerAndWait ); if (!m_fRotating) LinearMove( m_vecPosition2, pev->speed); else @@ -709,12 +709,12 @@ void CBaseButton::TriggerAndWait( void ) SetTouch( NULL ); } else - SetTouch( &ButtonTouch ); + SetTouch( &CBaseButton::ButtonTouch ); } else { pev->nextthink = pev->ltime + m_flWait; - SetThink( &ButtonReturn ); + SetThink( &CBaseButton::ButtonReturn ); } pev->frame = 1; // use alternate textures @@ -732,7 +732,7 @@ void CBaseButton::ButtonReturn( void ) ASSERT(m_toggle_state == TS_AT_TOP); m_toggle_state = TS_GOING_DOWN; - SetMoveDone( &ButtonBackHome ); + SetMoveDone( &CBaseButton::ButtonBackHome ); if (!m_fRotating) LinearMove( m_vecPosition1, pev->speed); else @@ -784,12 +784,12 @@ void CBaseButton::ButtonBackHome( void ) SetTouch( NULL ); } else - SetTouch( &ButtonTouch ); + SetTouch( &CBaseButton::ButtonTouch ); // reset think for a sparking button if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) { - SetThink( &ButtonSpark ); + SetThink( &CBaseButton::ButtonSpark ); pev->nextthink = gpGlobals->time + 0.5;// no hurry. } } @@ -857,10 +857,10 @@ void CRotButton::Spawn( void ) if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) { SetTouch( NULL ); - SetUse( &ButtonUse ); + SetUse( &CBaseButton::ButtonUse ); } else // touchable button - SetTouch( &ButtonTouch ); + SetTouch( &CBaseButton::ButtonTouch ); //SetTouch( &ButtonTouch ); } @@ -1049,7 +1049,7 @@ void CMomentaryRotButton::UpdateSelf( float value ) pev->nextthink += 0.1; pev->avelocity = (m_direction * pev->speed) * pev->movedir; - SetThink( &Off ); + SetThink( &CMomentaryRotButton::Off ); } void CMomentaryRotButton::UpdateTarget( float value ) @@ -1077,7 +1077,7 @@ void CMomentaryRotButton::Off( void ) m_lastUsed = 0; if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) { - SetThink( &Return ); + SetThink( &CMomentaryRotButton::Return ); pev->nextthink = pev->ltime + 0.1; m_direction = -1; } @@ -1154,14 +1154,14 @@ void CEnvSpark::Spawn(void) { if (FBitSet(pev->spawnflags, 64)) // Start on { - SetThink( &SparkThink); // start sparking - SetUse( &SparkStop); // set up +USE to stop sparking + SetThink( &CEnvSpark::SparkThink); // start sparking + SetUse( &CEnvSpark::SparkStop); // set up +USE to stop sparking } else - SetUse( &SparkStart); + SetUse( &CEnvSpark::SparkStart); } else - SetThink( &SparkThink); + SetThink( &CEnvSpark::SparkThink); pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); @@ -1208,14 +1208,14 @@ void EXPORT CEnvSpark::SparkThink(void) void EXPORT CEnvSpark::SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetUse( &SparkStop); - SetThink( &SparkThink); + 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( &SparkStart); + SetUse( &CEnvSpark::SparkStart); SetThink( NULL ); } diff --git a/dlls/client.cpp b/dlls/client.cpp index 01355bbb..f17b6e54 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -217,7 +217,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) { CBasePlayer *client; int j; - char *p; + char *p, *pc; char text[128]; char szTemp[256]; const char *cpSay = "say"; @@ -269,7 +269,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) } // make sure the text has content - for ( char *pc = p; pc != NULL && *pc != 0; pc++ ) + for ( pc = p; pc != NULL && *pc != 0; pc++ ) { if ( !isspace( *pc ) ) { diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 2899d051..9fec6047 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -115,7 +115,7 @@ void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs pGib->pev->movetype = MOVETYPE_TOSS; pGib->pev->solid = SOLID_BBOX; UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); - pGib->SetTouch( &StickyGibTouch ); + pGib->SetTouch( &CGib::StickyGibTouch ); pGib->SetThink( NULL ); } pGib->LimitVelocity(); @@ -331,7 +331,7 @@ void CBaseMonster :: GibMonster( void ) if ( gibbed ) { // don't remove players! - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } else @@ -654,7 +654,7 @@ void CBaseEntity :: SUB_StartFadeOut ( void ) pev->avelocity = g_vecZero; pev->nextthink = gpGlobals->time + 0.1; - SetThink( &SUB_FadeOut ); + SetThink( &CBaseEntity::SUB_FadeOut ); } void CBaseEntity :: SUB_FadeOut ( void ) @@ -668,7 +668,7 @@ void CBaseEntity :: SUB_FadeOut ( void ) { pev->renderamt = 0; pev->nextthink = gpGlobals->time + 0.2; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); } } @@ -688,7 +688,7 @@ void CGib :: WaitTillLand ( void ) if ( pev->velocity == g_vecZero ) { - SetThink( &SUB_StartFadeOut); + SetThink( &CBaseEntity::SUB_StartFadeOut); pev->nextthink = gpGlobals->time + m_lifeTime; // If you bleed, you stink! @@ -756,7 +756,7 @@ void CGib :: StickyGibTouch ( CBaseEntity *pOther ) Vector vecSpot; TraceResult tr; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 10; if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) @@ -797,8 +797,8 @@ void CGib :: Spawn( const char *szGibModel ) pev->nextthink = gpGlobals->time + 4; m_lifeTime = 25; - SetThink( &WaitTillLand ); - SetTouch( &BounceGibTouch ); + 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). diff --git a/dlls/controller.cpp b/dlls/controller.cpp index 0ade7ace..7e4dc1d0 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -1170,8 +1170,8 @@ void CControllerHeadBall :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( &HuntThink ); - SetTouch( &BounceTouch ); + SetThink( &CControllerHeadBall::HuntThink ); + SetTouch( &CControllerHeadBall::BounceTouch ); m_vecIdeal = Vector( 0, 0, 0 ); @@ -1257,7 +1257,7 @@ void CControllerHeadBall :: HuntThink( void ) m_flNextAttack = gpGlobals->time + 3.0; - SetThink( &DieThink ); + SetThink( &CControllerHeadBall::DieThink ); pev->nextthink = gpGlobals->time + 0.3; } @@ -1364,8 +1364,8 @@ void CControllerZapBall :: Spawn( void ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( &AnimateThink ); - SetTouch( &ExplodeTouch ); + SetThink( &CControllerZapBall::AnimateThink ); + SetTouch( &CControllerZapBall::ExplodeTouch ); m_hOwner = Instance( pev->owner ); pev->dmgtime = gpGlobals->time; // keep track of when ball spawned diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 2a9224cd..59870b87 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -71,8 +71,8 @@ void CCrossbowBolt::Spawn( ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - SetTouch( &BoltTouch ); - SetThink( &BubbleThink ); + SetTouch( &CCrossbowBolt::BoltTouch ); + SetThink( &CCrossbowBolt::BubbleThink ); pev->nextthink = gpGlobals->time + 0.2; } @@ -139,7 +139,7 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { 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( &SUB_Remove ); + SetThink( &CBaseEntity::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" ) ) @@ -179,7 +179,7 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) if ( g_pGameRules->IsMultiplayer() ) { - SetThink( &ExplodeThink ); + SetThink( &CCrossbowBolt::ExplodeThink ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -561,4 +561,4 @@ LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); -#endif \ No newline at end of file +#endif diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index de6ad845..ef21e503 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -147,7 +147,7 @@ void CCrowbar::PrimaryAttack() { if (! Swing( 1 )) { - SetThink( &SwingAgain ); + SetThink( &CCrowbar::SwingAgain ); pev->nextthink = gpGlobals->time + 0.1; } } @@ -306,7 +306,7 @@ int CCrowbar::Swing( int fFirst ) #endif m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - SetThink( &Smack ); + SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 44815efb..5a5249c5 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -320,7 +320,7 @@ void CBaseDoor::Spawn( ) SetTouch( NULL ); } else // touchable button - SetTouch( &DoorTouch ); + SetTouch( &CBaseDoor::DoorTouch ); } @@ -520,7 +520,7 @@ void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use { 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) + if ( m_toggle_state == TS_AT_BOTTOM || ( FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP ) ) DoorActivate(); } @@ -576,7 +576,7 @@ void CBaseDoor::DoorGoUp( void ) m_toggle_state = TS_GOING_UP; - SetMoveDone( &DoorHitTop ); + SetMoveDone( &CBaseDoor::DoorHitTop ); if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet { float sign = 1.0; @@ -625,13 +625,13 @@ void CBaseDoor::DoorHitTop( void ) { // Re-instate touch method, movement is complete if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - SetTouch( &DoorTouch ); + 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( &DoorGoDown ); + SetThink( &CBaseDoor::DoorGoDown ); if ( m_flWait == -1 ) { @@ -661,7 +661,7 @@ void CBaseDoor::DoorGoDown( void ) #endif // DOOR_ASSERT m_toggle_state = TS_GOING_DOWN; - SetMoveDone( &DoorHitBottom ); + SetMoveDone( &CBaseDoor::DoorHitBottom ); if ( FClassnameIs(pev, "func_door_rotating"))//rotating door AngularMove( m_vecAngle1, pev->speed); else @@ -688,7 +688,7 @@ void CBaseDoor::DoorHitBottom( void ) SetTouch( NULL ); } else // touchable door - SetTouch( &DoorTouch ); + SetTouch( &CBaseDoor::DoorTouch ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished @@ -865,7 +865,7 @@ void CRotDoor::Spawn( void ) SetTouch( NULL ); } else // touchable button - SetTouch( &DoorTouch ); + SetTouch( &CBaseDoor::DoorTouch ); } @@ -1075,7 +1075,7 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); LinearMove( move, speed ); - SetMoveDone( &MomentaryMoveDone ); + SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); } } @@ -1084,4 +1084,4 @@ void CMomentaryDoor::MomentaryMoveDone( void ) { STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving)); EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); -} \ No newline at end of file +} diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 933e952e..9868aeb9 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -87,7 +87,7 @@ void CBubbling::Spawn( void ) if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) { - SetThink( &FizzThink ); + SetThink( &CBubbling::FizzThink ); pev->nextthink = gpGlobals->time + 2.0; m_state = 1; } @@ -108,7 +108,7 @@ void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use if ( m_state ) { - SetThink( &FizzThink ); + SetThink( &CBubbling::FizzThink ); pev->nextthink = gpGlobals->time + 0.1; } else @@ -459,7 +459,7 @@ void CLightning::Spawn( void ) { if ( FStringNull( m_iszSpriteName ) ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions @@ -472,7 +472,7 @@ void CLightning::Spawn( void ) SetThink( NULL ); if ( pev->dmg > 0 ) { - SetThink( &DamageThink ); + SetThink( &CLightning::DamageThink ); pev->nextthink = gpGlobals->time + 0.1; } if ( pev->targetname ) @@ -486,7 +486,7 @@ void CLightning::Spawn( void ) else m_active = 1; - SetUse( &ToggleUse ); + SetUse( &CLightning::ToggleUse ); } } else @@ -494,11 +494,11 @@ void CLightning::Spawn( void ) m_active = 0; if ( !FStringNull(pev->targetname) ) { - SetUse( &StrikeUse ); + SetUse( &CLightning::StrikeUse ); } if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) { - SetThink( &StrikeThink ); + SetThink( &CLightning::StrikeThink ); pev->nextthink = gpGlobals->time + 1.0; } } @@ -616,7 +616,7 @@ void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T } else { - SetThink( &StrikeThink ); + SetThink( &CLightning::StrikeThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -961,13 +961,13 @@ void CLaser::Spawn( void ) { if ( FStringNull( pev->model ) ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions Precache( ); - SetThink( &StrikeThink ); + SetThink( &CLaser::StrikeThink ); pev->flags |= FL_CUSTOMENTITY; PointsInit( pev->origin, pev->origin ); @@ -1264,7 +1264,7 @@ void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { pev->speed = scaleSpeed; pev->health = fadeSpeed; - SetThink( &ExpandThink ); + SetThink( &CSprite::ExpandThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; @@ -1319,7 +1319,7 @@ void CSprite::TurnOn( void ) pev->effects = 0; if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) { - SetThink( &AnimateThink ); + SetThink( &CSprite::CSprite::AnimateThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; } @@ -1426,7 +1426,7 @@ void CGibShooter::KeyValue( KeyValueData *pkvd ) void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &ShootThink ); + SetThink( &CGibShooter::ShootThink ); pev->nextthink = gpGlobals->time; } @@ -1516,7 +1516,7 @@ void CGibShooter :: ShootThink ( void ) } else { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } } @@ -1708,7 +1708,7 @@ void CTestEffect::TestThink( void ) void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &TestThink ); + SetThink( &CTestEffect::TestThink ); pev->nextthink = gpGlobals->time + 0.1; m_flStartTime = gpGlobals->time; } @@ -2129,7 +2129,7 @@ void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us MESSAGE_END(); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } @@ -2228,7 +2228,7 @@ void CItemSoda::Spawn( void ) SET_MODEL ( ENT(pev), "models/can.mdl" ); UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); - SetThink( &CanThink); + SetThink( &CItemSoda::CanThink); pev->nextthink = gpGlobals->time + 0.5; } @@ -2239,7 +2239,7 @@ void CItemSoda::CanThink ( void ) pev->solid = SOLID_TRIGGER; UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); SetThink( NULL ); - SetTouch( &CanTouch ); + SetTouch( &CItemSoda::CanTouch ); } void CItemSoda::CanTouch ( CBaseEntity *pOther ) @@ -2263,6 +2263,6 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) pev->movetype = MOVETYPE_NONE; pev->effects = EF_NODRAW; SetTouch( NULL ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; -} \ No newline at end of file +} diff --git a/dlls/effects.h b/dlls/effects.h index c62a3ee4..c95ff1b1 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -79,7 +79,7 @@ public: inline void AnimateAndDie( float framerate ) { - SetThink( &AnimateUntilDead); + SetThink( &CSprite::AnimateUntilDead); pev->framerate = framerate; pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); pev->nextthink = gpGlobals->time; @@ -168,7 +168,7 @@ public: static CBeam *BeamCreate( const char *pSpriteName, int width ); - inline void LiveForTime( float time ) { SetThink( &SUB_Remove); pev->nextthink = gpGlobals->time + time; } + inline void LiveForTime( float time ) { SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + time; } inline void BeamDamageInstant( TraceResult *ptr, float damage ) { pev->dmg = damage; diff --git a/dlls/explode.cpp b/dlls/explode.cpp index 2427d108..c884fa54 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -217,7 +217,7 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); } - SetThink( &Smoke ); + SetThink( &CEnvExplosion::Smoke ); pev->nextthink = gpGlobals->time + 0.3; // draw sparks diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index b1cad808..5d682dcb 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -164,7 +164,7 @@ void CBreakable::Spawn( void ) SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. - SetTouch( &BreakTouch ); + SetTouch( &CBreakable::BreakTouch ); if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger SetTouch( NULL ); @@ -359,7 +359,7 @@ void CBreakable::DamageSound( void ) int pitch; float fvol; char *rgpsz[6]; - int i; + int i = 0; int material = m_Material; // if (RANDOM_LONG(0,1)) @@ -459,7 +459,7 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) // play creaking sound here. DamageSound(); - SetThink( &Die ); + SetThink( &CBreakable::Die ); SetTouch( NULL ); if ( m_flDelay == 0 ) @@ -743,7 +743,7 @@ void CBreakable::Die( void ) // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = pev->ltime + 0.1; if ( m_iszSpawnObject ) CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index ffe60c6b..3dc763da 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -161,7 +161,7 @@ void CStomp::Think( void ) 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( &SUB_Remove ); + pSprite->SetThink( &CBaseEntity::SUB_Remove ); pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); } } @@ -1126,7 +1126,7 @@ void CGargantua::RunTask( Task_t *pTask ) pev->rendercolor.z = 0; StopAnimation(); pev->nextthink = gpGlobals->time + 0.15; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); int i; int parts = MODEL_FRAMES( gGargGibModel ); for ( i = 0; i < 10; i++ ) @@ -1145,7 +1145,7 @@ void CGargantua::RunTask( Task_t *pTask ) pGib->pev->origin = pev->origin; pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); pGib->pev->nextthink = gpGlobals->time + 1.25; - pGib->SetThink( &SUB_FadeOut ); + pGib->SetThink( &CBaseEntity::SUB_FadeOut ); } MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_BREAKMODEL); @@ -1365,4 +1365,4 @@ void SpawnExplosion( Vector center, float randomRange, float time, int magnitude -#endif \ No newline at end of file +#endif diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index c811207b..6cf34576 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -113,7 +113,7 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) } pev->effects |= EF_NODRAW; - SetThink( &Smoke ); + SetThink( &CGrenade::Smoke ); pev->velocity = g_vecZero; pev->nextthink = gpGlobals->time + 0.3; @@ -156,7 +156,7 @@ void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) // Timed grenade, this think is called when time runs out. void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &Detonate ); + SetThink( &CGrenade::Detonate ); pev->nextthink = gpGlobals->time; } @@ -164,7 +164,7 @@ void CGrenade::PreDetonate( void ) { CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - SetThink( &Detonate ); + SetThink( &CGrenade::Detonate ); pev->nextthink = gpGlobals->time + 1; } @@ -331,7 +331,7 @@ void CGrenade :: TumbleThink( void ) if (pev->dmgtime <= gpGlobals->time) { - SetThink( &Detonate ); + SetThink( &CGrenade::Detonate ); } if (pev->waterlevel != 0) { @@ -368,14 +368,14 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->owner = ENT(pevOwner); // make monsters afaid of it while in the air - pGrenade->SetThink( &DangerSoundThink ); + 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( &ExplodeTouch ); + pGrenade->SetTouch( &CGrenade::ExplodeTouch ); pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; @@ -392,14 +392,14 @@ CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); pGrenade->pev->owner = ENT(pevOwner); - pGrenade->SetTouch( &BounceTouch ); // Bounce if touched + 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( &TumbleThink ); + pGrenade->SetThink( &CGrenade::TumbleThink ); pGrenade->pev->nextthink = gpGlobals->time + 0.1; if (time < 0.1) { @@ -442,9 +442,9 @@ CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, pGrenade->pev->owner = ENT(pevOwner); // Detonate in "time" seconds - pGrenade->SetThink( &SUB_DoNothing ); - pGrenade->SetUse( &DetonateUse ); - pGrenade->SetTouch( &SlideTouch ); + pGrenade->SetThink( &CBaseEntity::SUB_DoNothing ); + pGrenade->SetUse( &CGrenade::DetonateUse ); + pGrenade->SetTouch( &CGrenade::SlideTouch ); pGrenade->pev->spawnflags = SF_DETONATE; pGrenade->pev->friction = 0.9; diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 68c97bd1..b8a3e7b0 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -129,7 +129,7 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } pev->nextthink = pev->ltime + 0.25; - SetThink( &Off); + SetThink( &CRecharge::Off); // Time to recharge yet? @@ -179,7 +179,7 @@ void CRecharge::Recharge(void) { m_iJuice = gSkillData.suitchargerCapacity; pev->frame = 0; - SetThink( &SUB_DoNothing ); + SetThink( &CBaseEntity::SUB_DoNothing ); } void CRecharge::Off(void) @@ -193,8 +193,8 @@ void CRecharge::Off(void) if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) { pev->nextthink = pev->ltime + m_iReactivate; - SetThink( &Recharge); + SetThink( &CRecharge::Recharge); } else - SetThink( &SUB_DoNothing ); -} \ No newline at end of file + SetThink( &CBaseEntity::SUB_DoNothing ); +} diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp index def27354..d25902a2 100644 --- a/dlls/h_cine.cpp +++ b/dlls/h_cine.cpp @@ -124,7 +124,7 @@ void CLegacyCineMonster :: CineSpawn( char *szModel ) // if no targetname, start now if ( FStringNull(pev->targetname) ) { - SetThink( &CineThink ); + SetThink( &CLegacyCineMonster::CineThink ); pev->nextthink += 1.0; } } @@ -136,7 +136,7 @@ void CLegacyCineMonster :: CineSpawn( char *szModel ) void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { pev->animtime = 0; // reset the sequence - SetThink( &CineThink ); + SetThink( &CLegacyCineMonster::CineThink ); pev->nextthink = gpGlobals->time; } @@ -145,7 +145,7 @@ void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, U // void CLegacyCineMonster :: Die( void ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); } // @@ -228,14 +228,14 @@ void CCineBlood :: BloodGush ( void ) void CCineBlood :: BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &BloodGush ); + SetThink( &CCineBlood::BloodGush ); pev->nextthink = gpGlobals->time;// now! } void CCineBlood :: Spawn ( void ) { pev->solid = SOLID_NOT; - SetUse( &BloodStart ); + SetUse( &CCineBlood::BloodStart ); pev->health = 20;//hacked health to count iterations } diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index d823488e..e7d5109b 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -334,7 +334,7 @@ void CWeaponCycler::Spawn( ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch( &DefaultTouch ); + SetTouch( &CBasePlayerItem::DefaultTouch ); } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 2233b8a0..56ce9ee6 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -103,7 +103,7 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { // no more grenades! m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 6f43965c..8796769a 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -385,7 +385,7 @@ void CHeadCrab :: StartTask ( Task_t *pTask ) { EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch( &LeapTouch ); + SetTouch( &CHeadCrab::LeapTouch ); break; } default: diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index fbf1d982..87b9a221 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -207,7 +207,7 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u } pev->nextthink = pev->ltime + 0.25; - SetThink( &Off); + SetThink( &CWallHealth::Off ); // Time to recharge yet? @@ -243,7 +243,7 @@ void CWallHealth::Recharge(void) EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); m_iJuice = gSkillData.healthchargerCapacity; pev->frame = 0; - SetThink( &SUB_DoNothing ); + SetThink( &CBaseEntity::SUB_DoNothing ); } void CWallHealth::Off(void) @@ -257,8 +257,8 @@ void CWallHealth::Off(void) if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) { pev->nextthink = pev->ltime + m_iReactivate; - SetThink( &Recharge); + SetThink( &CWallHealth::Recharge ); } else - SetThink( &SUB_DoNothing ); -} \ No newline at end of file + SetThink( &CBaseEntity::SUB_DoNothing ); +} diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index eab06752..86544534 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -2393,7 +2393,7 @@ void CHGruntRepel::Spawn( void ) Precache( ); pev->solid = SOLID_NOT; - SetUse( &RepelUse ); + SetUse( &CHGruntRepel::RepelUse ); } void CHGruntRepel::Precache( void ) @@ -2423,7 +2423,7 @@ void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &SUB_Remove ); + pBeam->SetThink( &CBaseEntity::SUB_Remove ); pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; UTIL_Remove( this ); diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index f11dfb7f..5e64f4ef 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -93,8 +93,8 @@ void CHornet :: Spawn( void ) SET_MODEL(ENT( pev ), "models/hornet.mdl"); UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); - SetTouch( &DieTouch ); - SetThink( &StartTrack ); + SetTouch( &CHornet::DieTouch ); + SetThink( &CHornet::StartTrack ); edict_t *pSoundEnt = pev->owner; if ( !pSoundEnt ) @@ -169,8 +169,8 @@ void CHornet :: StartTrack ( void ) { IgniteTrail(); - SetTouch( &TrackTouch ); - SetThink( &TrackTarget ); + SetTouch( &CHornet::TrackTouch ); + SetThink( &CHornet::TrackTarget ); pev->nextthink = gpGlobals->time + 0.1; } @@ -182,9 +182,9 @@ void CHornet :: StartDart ( void ) { IgniteTrail(); - SetTouch( &DartTouch ); + SetTouch( &CHornet::DartTouch ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 4; } @@ -257,7 +257,7 @@ void CHornet :: TrackTarget ( void ) if (gpGlobals->time > m_flStopAttack) { SetTouch( NULL ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; return; } @@ -413,7 +413,7 @@ void CHornet::DieTouch ( CBaseEntity *pOther ) pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid pev->solid = SOLID_NOT; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! } diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index e8bfacfd..5b9e0126 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -97,7 +97,7 @@ public: BOOL FValidateHintType ( short sHint ); BOOL FCanActiveIdle ( void ); Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *CHoundeye :: GetSchedule( void ); + Schedule_t *GetSchedule( void ); int Save( CSave &save ); int Restore( CRestore &restore ); diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index fa62e613..f4cc3888 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -494,8 +494,8 @@ void CIchthyosaur :: Spawn() MonsterInit(); - SetTouch( &BiteTouch ); - SetUse( &CombatUse ); + SetTouch( &CIchthyosaur::BiteTouch ); + SetUse( &CIchthyosaur::CombatUse ); m_idealDist = 384; m_flMinSpeed = 80; @@ -1105,4 +1105,4 @@ Vector CIchthyosaur::DoProbe(const Vector &Probe) return Vector(0, 0, 0); } -#endif \ No newline at end of file +#endif diff --git a/dlls/items.cpp b/dlls/items.cpp index fe88a53e..930b187d 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -93,7 +93,7 @@ void CItem::Spawn( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch( &ItemTouch); + SetTouch( &CItem::ItemTouch ); if (DROP_TO_FLOOR(ENT(pev)) == 0) { @@ -151,7 +151,7 @@ CBaseEntity* CItem::Respawn( void ) UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. - SetThink( &Materialize ); + SetThink( &CItem::Materialize ); pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); return this; } @@ -166,7 +166,7 @@ void CItem::Materialize( void ) pev->effects |= EF_MUZZLEFLASH; } - SetTouch( &ItemTouch ); + SetTouch( &CItem::ItemTouch ); } #define SF_SUIT_SHORTLOGON 0x0001 diff --git a/dlls/leech.cpp b/dlls/leech.cpp index 6c13e08d..390588db 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -196,7 +196,7 @@ void CLeech::Spawn( void ) m_flFieldOfView = -0.5; // 180 degree FOV m_flDistLook = 750; MonsterInit(); - SetThink( &SwimThink ); + SetThink( &CLeech::SwimThink ); SetUse( NULL ); SetTouch( NULL ); pev->view_ofs = g_vecZero; @@ -717,7 +717,7 @@ void CLeech::Killed(entvars_t *pevAttacker, int iGib) pev->movetype = MOVETYPE_TOSS; pev->takedamage = DAMAGE_NO; - SetThink( &DeadThink ); + SetThink( &CLeech::DeadThink ); } diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index 43513d0a..72e44575 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -111,29 +111,29 @@ void CMonsterMaker :: Spawn( ) { if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) { - SetUse( &CyclicUse );// drop one monster each time we fire + SetUse( &CMonsterMaker::CyclicUse );// drop one monster each time we fire } else { - SetUse( &ToggleUse );// so can be turned on/off + 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( &MakerThink ); + SetThink( &CMonsterMaker::MakerThink ); } else {// wait to be activated. m_fActive = FALSE; - SetThink( &SUB_DoNothing ); + SetThink( &CBaseEntity::SUB_DoNothing ); } } else {// no targetname, just start. pev->nextthink = gpGlobals->time + m_flDelay; m_fActive = TRUE; - SetThink( &MakerThink ); + SetThink( &CMonsterMaker::MakerThink ); } if ( m_cNumMonsters == 1 ) @@ -259,7 +259,7 @@ void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, else { m_fActive = TRUE; - SetThink( &MakerThink ); + SetThink( &CMonsterMaker::MakerThink ); } pev->nextthink = gpGlobals->time; diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index ad64189d..1e6191d1 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -2044,9 +2044,9 @@ void CBaseMonster :: MonsterInit ( void ) // set eye position SetEyePosition(); - SetThink( &MonsterInitThink ); + SetThink( &CBaseMonster::MonsterInitThink ); pev->nextthink = gpGlobals->time + 0.1; - SetUse( &MonsterUse ); + SetUse( &CBaseMonster::MonsterUse ); } //========================================================= @@ -2146,7 +2146,7 @@ void CBaseMonster :: StartMonster ( void ) // 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( &CallMonsterThink ); + SetThink( &CBaseMonster::CallMonsterThink ); pev->nextthink += RANDOM_FLOAT(0.1, 0.4); // spread think times. if ( !FStringNull(pev->targetname) )// wait until triggered @@ -3289,7 +3289,7 @@ void CBaseMonster :: MonsterInitDead( void ) // Setup health counters, etc. BecomeDead(); - SetThink( &CorpseFallThink ); + SetThink( &CBaseMonster::CorpseFallThink ); pev->nextthink = gpGlobals->time + 0.5; } diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index d1d64825..e9e47630 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -105,7 +105,7 @@ void CFuncMortarField :: Spawn( void ) SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world pev->movetype = MOVETYPE_NONE; SetBits( pev->effects, EF_NODRAW ); - SetUse( &FieldUse ); + SetUse( &CFuncMortarField::FieldUse ); Precache(); } @@ -209,7 +209,7 @@ void CMortar::Spawn( ) pev->dmg = 200; - SetThink( &MortarExplode ); + SetThink( &CMortar::MortarExplode ); pev->nextthink = 0; Precache( ); @@ -320,4 +320,4 @@ void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) UTIL_SetOrigin( pMortar->pev, tr.vecEndPos ); } -#endif \ No newline at end of file +#endif diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 2e2cab75..fb3d3e18 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -563,7 +563,7 @@ void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) addDefault = TRUE; - while ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" )) + while ( ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" ) ) ) { pWeaponEntity->Touch( pPlayer ); addDefault = FALSE; diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 8e7859eb..9456fad7 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -300,7 +300,7 @@ void CNihilanth :: Spawn( void ) InitBoneControllers(); - SetThink( &StartupThink ); + SetThink( &CNihilanth::StartupThink ); pev->nextthink = gpGlobals->time + 0.1; m_vecDesired = Vector( 1, 0, 0 ); @@ -378,9 +378,9 @@ void CNihilanth::NullThink( void ) void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - SetThink( &HuntThink ); + SetThink( &CNihilanth::HuntThink ); pev->nextthink = gpGlobals->time + 0.1; - SetUse( &CommandUse ); + SetUse( &CNihilanth::CommandUse ); } @@ -410,8 +410,8 @@ void CNihilanth::StartupThink( void ) } m_hRecharger = NULL; - SetThink( &HuntThink); - SetUse( &CommandUse ); + SetThink( &CNihilanth::HuntThink); + SetUse( &CNihilanth::CommandUse ); pev->nextthink = gpGlobals->time + 0.1; } @@ -846,7 +846,7 @@ void CNihilanth :: HuntThink( void ) // if dead, force cancelation of current animation if (pev->health <= 0) { - SetThink( &DyingThink ); + SetThink( &CNihilanth::DyingThink ); m_fSequenceFinished = TRUE; return; } @@ -1018,8 +1018,9 @@ BOOL CNihilanth :: EmitSphere( void ) void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) { + int i; CBaseMonster *pSphere; - for (int i = 0; i < N_SPHERES; i++) + for (i = 0; i < N_SPHERES; i++) { if (m_hSphere[i] != NULL) { @@ -1330,8 +1331,8 @@ void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); UTIL_SetOrigin( pev, pev->origin ); - SetThink( &HoverThink ); - SetTouch( &BounceTouch ); + SetThink( &CNihilanthHVR::HoverThink ); + SetTouch( &CNihilanthHVR::BounceTouch ); pev->nextthink = gpGlobals->time + 0.1; m_hTargetEnt = pTarget; @@ -1433,8 +1434,8 @@ void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) pev->velocity = (pEnemy->pev->origin - pev->origin).Normalize() * 200; m_hEnemy = pEnemy; - SetThink( &ZapThink ); - SetTouch( &ZapTouch ); + 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 ); @@ -1559,8 +1560,8 @@ void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBa m_hTargetEnt = pTarget; m_hTouch = pTouch; - SetThink( &TeleportThink ); - SetTouch( &TeleportTouch ); + 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 ); @@ -1579,7 +1580,7 @@ void CNihilanthHVR :: GreenBallInit( ) SET_MODEL(edict(), "sprites/exit1.spr"); - SetTouch( &RemoveTouch ); + SetTouch( &CNihilanthHVR::RemoveTouch ); } @@ -1631,7 +1632,7 @@ void CNihilanthHVR :: TeleportThink( void ) void CNihilanthHVR :: AbsorbInit( void ) { - SetThink( &DissipateThink ); + SetThink( &CNihilanthHVR::DissipateThink ); pev->renderamt = 255; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -1833,4 +1834,4 @@ void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) -#endif \ No newline at end of file +#endif diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 1a55cd43..c69dc709 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -40,7 +40,7 @@ CGraph WorldGraph; LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); -#ifdef __linux__ +#ifdef _LINUX #include #include #define CreateDirectory(p, n) mkdir(p, 0777) @@ -636,6 +636,7 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, } else { + int i; CQueuePriority queue; switch( iHull ) @@ -656,7 +657,7 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, // Mark all the nodes as unvisited. // - for ( int i = 0; i < m_cNodes; i++) + for ( i = 0; i < m_cNodes; i++) { m_pNodes[ i ].m_flClosestSoFar = -1.0; } @@ -888,7 +889,7 @@ int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) m_CheckedCounter++; if (m_CheckedCounter == 0) { - for (int i = 0; i < m_cNodes; i++) + for ( i = 0; i < m_cNodes; i++ ) { m_di[i].m_CheckedEvent = 0; } @@ -1274,7 +1275,8 @@ int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ) 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", j ); + //fprintf ( file, "\n", j ); + fprintf ( file, "\n" ); } pLinkPool [ cTotalLinks ].m_iDestNode = j; @@ -1459,12 +1461,12 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode ) if ( WorldGraph.m_fGraphPresent ) {// graph loaded from disk, so we don't need the test hull - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } else { - SetThink( &DropDelay ); + SetThink( &CTestHull::DropDelay ); pev->nextthink = gpGlobals->time + 1; } @@ -1484,7 +1486,7 @@ void CTestHull::DropDelay ( void ) UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); - SetThink( &CallBuildNodeGraph ); + SetThink( &CTestHull::CallBuildNodeGraph ); pev->nextthink = gpGlobals->time + 1; } @@ -1593,7 +1595,7 @@ void CTestHull::CallBuildNodeGraph( void ) //========================================================= void CTestHull :: BuildNodeGraph( void ) { - TraceResult tr; + //TraceResult tr; FILE *file; char szNrpFilename [MAX_PATH];// text node report filename @@ -1632,7 +1634,7 @@ void CTestHull :: BuildNodeGraph( void ) float flDist; int step; - SetThink( &SUB_Remove );// no matter what happens, the hull gets rid of itself. + SetThink( &CBaseEntity::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. @@ -1744,7 +1746,7 @@ void CTestHull :: BuildNodeGraph( void ) { ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - SetThink( &ShowBadNode );// send the hull off to show the offending node. + SetThink( &CTestHull::ShowBadNode );// send the hull off to show the offending node. //pev->solid = SOLID_NOT; pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; @@ -1883,17 +1885,17 @@ void CTestHull :: BuildNodeGraph( void ) switch ( hull ) { case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection - fprintf ( file, "NODE_SMALL_HULL step %f\n", step ); + 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 %f\n", step ); + 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 %f\n", step ); + fprintf ( file, "NODE_LARGE_HULL step %d\n", step ); pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL; break; } @@ -2722,6 +2724,7 @@ int Primes[NUMBER_OF_PRIMES] = void CGraph::HashChoosePrimes(int TableSize) { + int iPrime, iZone; int LargestPrime = TableSize/2; if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) { @@ -2733,7 +2736,7 @@ void CGraph::HashChoosePrimes(int TableSize) // We divide this interval into 16 equal sized zones. We want to find // one prime number that best represents that zone. // - for (int iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) + 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. @@ -2789,9 +2792,9 @@ void CGraph::SortNodes(void) // After assigning new node numbers to everything, we move // things and patchup the links. // - int iNodeCnt = 0; + int i, iNodeCnt = 0; m_pNodes[0].m_iPreviousNode = iNodeCnt++; - for (int i = 1; i < m_cNodes; i++) + for (i = 1; i < m_cNodes; i++) { m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; } @@ -2847,6 +2850,7 @@ void CGraph::SortNodes(void) void CGraph::BuildLinkLookups(void) { + int i; m_nHashLinks = 3*m_cLinks/2 + 3; HashChoosePrimes(m_nHashLinks); @@ -2856,7 +2860,7 @@ void CGraph::BuildLinkLookups(void) ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); return; } - for (int i = 0; i < m_nHashLinks; i++) + for ( i = 0; i < m_nHashLinks; i++ ) { m_pHashLinks[i] = ENTRY_STATE_EMPTY; } @@ -2882,6 +2886,7 @@ void CGraph::BuildLinkLookups(void) void CGraph::BuildRegionTables(void) { + int i, j; if (m_di) free(m_di); // Go ahead and setup for range searching the nodes for FindNearestNodes @@ -2896,7 +2901,7 @@ void CGraph::BuildRegionTables(void) // Calculate regions for all the nodes. // // - for (int i = 0; i < 3; 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; @@ -2926,7 +2931,7 @@ void CGraph::BuildRegionTables(void) for (i = 0; i < 3; i++) { - for (int j = 0; j < NUM_RANGES; j++) + for (j = 0; j < NUM_RANGES; j++) { m_RangeStart[i][j] = 255; m_RangeEnd[i][j] = 0; @@ -3029,6 +3034,7 @@ void CGraph::BuildRegionTables(void) void CGraph :: ComputeStaticRoutingTables( void ) { + int iFrom; int nRoutes = m_cNodes*m_cNodes; #define FROM_TO(x,y) ((x)*m_cNodes+(y)) short *Routes = new short[nRoutes]; @@ -3060,7 +3066,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) // Initialize Routing table to uncalculated. // - for (int iFrom = 0; iFrom < m_cNodes; iFrom++) + for (iFrom = 0; iFrom < m_cNodes; iFrom++) { for (int iTo = 0; iTo < m_cNodes; iTo++) { @@ -3276,7 +3282,8 @@ void CGraph :: ComputeStaticRoutingTables( void ) int nRoute = p - pRoute; if (m_pRouteInfo) { - for (int i = 0; i < m_nRouteInfo - nRoute; i++) + int i; + for (i = 0; i < m_nRouteInfo - nRoute; i++) { if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) { @@ -3312,10 +3319,10 @@ void CGraph :: ComputeStaticRoutingTables( void ) } 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; + if ( Routes ) delete[] Routes; + if ( BestNextNodes ) delete[] BestNextNodes; + if ( pRoute ) delete[] pRoute; + if ( pMyPath ) delete[] pMyPath; Routes = 0; BestNextNodes = 0; pRoute = 0; @@ -3331,6 +3338,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) // void CGraph :: TestRoutingTables( void ) { + int i; int *pMyPath = new int[m_cNodes]; int *pMyPath2 = new int[m_cNodes]; if (pMyPath && pMyPath2) @@ -3368,7 +3376,7 @@ void CGraph :: TestRoutingTables( void ) // #if 1 float flDistance1 = 0.0; - for (int i = 0; i < cPathSize1-1; i++) + for ( i = 0; i < cPathSize1-1; i++ ) { // Find the link from pMyPath[i] to pMyPath[i+1] // @@ -3422,7 +3430,7 @@ void CGraph :: TestRoutingTables( void ) #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++) + for ( i = 0; i < cPathSize1; i++ ) { ALERT(at_aiconsole, "%d ", pMyPath[i]); } @@ -3446,8 +3454,8 @@ void CGraph :: TestRoutingTables( void ) EnoughSaid: - if (pMyPath) delete pMyPath; - if (pMyPath2) delete pMyPath2; + if (pMyPath) delete[] pMyPath; + if (pMyPath2) delete[] pMyPath2; pMyPath = 0; pMyPath2 = 0; } @@ -3559,7 +3567,7 @@ void CNodeViewer::Spawn( ) ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); m_iDraw = 0; - SetThink( &DrawThink ); + SetThink( &CNodeViewer::DrawThink ); pev->nextthink = gpGlobals->time; } diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index b85fadda..309d4354 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -167,8 +167,8 @@ void COsprey :: Spawn( void ) InitBoneControllers(); - SetThink( &FindAllThink ); - SetUse( &CommandUse ); + SetThink( &COsprey::FindAllThink ); + SetUse( &COsprey::CommandUse ); if (!(pev->spawnflags & SF_WAITFORTRIGGER)) { @@ -225,7 +225,7 @@ void COsprey :: FindAllThink( void ) UTIL_Remove( this ); return; } - SetThink( &FlyThink ); + SetThink( &COsprey::FlyThink ); pev->nextthink = gpGlobals->time + 0.1; m_startTime = gpGlobals->time; } @@ -257,7 +257,7 @@ void COsprey :: DeployThink( void ) vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; m_hRepel[3] = MakeGrunt( vecSrc ); - SetThink( &HoverThink ); + SetThink( &COsprey::HoverThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -308,7 +308,7 @@ CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &SUB_Remove ); + pBeam->SetThink( &CBaseEntity::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 ); @@ -336,7 +336,7 @@ void COsprey :: HoverThink( void ) if (i == 4) { m_startTime = gpGlobals->time; - SetThink( &FlyThink ); + SetThink( &COsprey::FlyThink ); } pev->nextthink = gpGlobals->time + 0.1; @@ -396,7 +396,7 @@ void COsprey::FlyThink( void ) { if (m_pGoalEnt->pev->speed == 0) { - SetThink( &DeployThink ); + SetThink( &COsprey::DeployThink ); } do { m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( m_pGoalEnt->pev->target ) ) ); @@ -518,8 +518,8 @@ void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( &DyingThink ); - SetTouch( &CrashTouch ); + SetThink( &COsprey::DyingThink ); + SetTouch( &COsprey::CrashTouch ); pev->nextthink = gpGlobals->time + 0.1; pev->health = 0; pev->takedamage = DAMAGE_NO; diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 5b62d79b..64151f47 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -328,7 +328,7 @@ void CFuncPlat :: Spawn( ) { UTIL_SetOrigin (pev, m_vecPosition1); m_toggle_state = TS_AT_TOP; - SetUse( &PlatUse ); + SetUse( &CFuncPlat::PlatUse ); } else { @@ -435,7 +435,7 @@ void CFuncPlat :: GoDown( void ) ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); m_toggle_state = TS_GOING_DOWN; - SetMoveDone( &CallHitBottom); + SetMoveDone( &CFuncPlat::CallHitBottom); LinearMove(m_vecPosition2, pev->speed); } @@ -466,7 +466,7 @@ void CFuncPlat :: GoUp( void ) ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); m_toggle_state = TS_GOING_UP; - SetMoveDone( &CallHitTop); + SetMoveDone( &CFuncPlat::CallHitTop); LinearMove(m_vecPosition1, pev->speed); } @@ -488,7 +488,7 @@ void CFuncPlat :: HitTop( void ) if ( !IsTogglePlat() ) { // After a delay, the platform will automatically start going down again. - SetThink( &CallGoDown ); + SetThink( &CFuncPlat::CallGoDown ); pev->nextthink = pev->ltime + 3; } } @@ -738,7 +738,7 @@ void CFuncTrain :: Wait( void ) 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( &Next ); + SetThink( &CFuncTrain::Next ); } else { @@ -802,7 +802,7 @@ void CFuncTrain :: Next( void ) if ( pev->noiseMovement ) EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); ClearBits(pev->effects, EF_NOINTERP); - SetMoveDone( &Wait ); + SetMoveDone( &CFuncTrain::Wait ); LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); } } @@ -824,7 +824,7 @@ void CFuncTrain :: Activate( void ) if ( FStringNull(pev->targetname) ) { // not triggered, so start immediately pev->nextthink = pev->ltime + 0.1; - SetThink( &Next ); + SetThink( &CFuncTrain::Next ); } else pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; @@ -920,7 +920,7 @@ void CFuncTrain::OverrideReset( void ) } else // Keep moving for 0.1 secs, then find path_corner again and restart { - SetThink( &Next ); + SetThink( &CFuncTrain::Next ); pev->nextthink = pev->ltime + 0.1; } } @@ -1126,7 +1126,7 @@ void CFuncTrackTrain :: UpdateSound( void ) if (!pev->noise) return; - flpitch = TRAIN_STARTPITCH + (abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); + flpitch = TRAIN_STARTPITCH + (fabs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); if (!m_soundPlaying) { @@ -1262,7 +1262,7 @@ void CFuncTrackTrain :: Next( void ) } } - SetThink( &Next ); + SetThink( &CFuncTrackTrain::Next ); NextThink( pev->ltime + time, TRUE ); } else // end of path, stop @@ -1284,7 +1284,7 @@ void CFuncTrackTrain :: Next( void ) // no, how long to get there? time = distance / m_oldSpeed; pev->velocity = pev->velocity * (m_oldSpeed / distance); - SetThink( &DeadEnd ); + SetThink( &CFuncTrackTrain::DeadEnd ); NextThink( pev->ltime + time, FALSE ); } else @@ -1402,7 +1402,7 @@ void CFuncTrackTrain :: Find( void ) pev->angles.x = 0; UTIL_SetOrigin( pev, nextPos ); NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &Next ); + SetThink( &CFuncTrackTrain::Next ); pev->speed = m_startSpeed; UpdateSound(); @@ -1452,7 +1452,7 @@ void CFuncTrackTrain :: NearestPath( void ) if ( pev->speed != 0 ) { NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &Next ); + SetThink( &CFuncTrackTrain::Next ); } } @@ -1460,7 +1460,7 @@ void CFuncTrackTrain :: NearestPath( void ) void CFuncTrackTrain::OverrideReset( void ) { NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &NearestPath ); + SetThink( &CFuncTrackTrain::NearestPath ); } @@ -1519,7 +1519,7 @@ void CFuncTrackTrain :: Spawn( void ) // 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( &Find ); + SetThink( &CFuncTrackTrain::Find ); Precache(); } @@ -1589,7 +1589,7 @@ void CFuncTrainControls :: Spawn( void ) UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); - SetThink( &Find ); + SetThink( &CFuncTrainControls::Find ); pev->nextthink = gpGlobals->time; } @@ -1701,7 +1701,7 @@ void CFuncTrackChange :: Spawn( void ) EnableUse(); pev->nextthink = pev->ltime + 2.0; - SetThink( &Find ); + SetThink( &CFuncTrackChange::Find ); Precache(); } @@ -1752,7 +1752,7 @@ void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) void CFuncTrackChange::OverrideReset( void ) { pev->nextthink = pev->ltime + 1.0; - SetThink( &Find ); + SetThink( &CFuncTrackChange::Find ); } void CFuncTrackChange :: Find( void ) @@ -1862,14 +1862,14 @@ void CFuncTrackChange :: GoDown( void ) // If ROTMOVE, move & rotate if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { - SetMoveDone( &CallHitBottom ); + SetMoveDone( &CFuncPlat::CallHitBottom ); m_toggle_state = TS_GOING_DOWN; AngularMove( m_start, pev->speed ); } else { CFuncPlat :: GoDown(); - SetMoveDone( &CallHitBottom ); + SetMoveDone( &CFuncPlat::CallHitBottom ); RotMove( m_start, pev->nextthink - pev->ltime ); } // Otherwise, rotate first, move second @@ -1898,14 +1898,14 @@ void CFuncTrackChange :: GoUp( void ) if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { m_toggle_state = TS_GOING_UP; - SetMoveDone( &CallHitTop ); + SetMoveDone( &CFuncPlat::CallHitTop ); AngularMove( m_end, pev->speed ); } else { // If ROTMOVE, move & rotate CFuncPlat :: GoUp(); - SetMoveDone( &CallHitTop ); + SetMoveDone( &CFuncPlat::CallHitTop ); RotMove( m_end, pev->nextthink - pev->ltime ); } @@ -2160,7 +2160,7 @@ void CGunTarget::Spawn( void ) if ( pev->spawnflags & FGUNTARGET_START_ON ) { - SetThink( &Start ); + SetThink( &CGunTarget::Start ); pev->nextthink = pev->ltime + 0.3; } } @@ -2198,7 +2198,7 @@ void CGunTarget::Next( void ) Stop(); return; } - SetMoveDone( &Wait ); + SetMoveDone( &CGunTarget::Wait ); LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); } @@ -2224,7 +2224,7 @@ void CGunTarget::Wait( void ) m_flWait = pTarget->GetDelay(); pev->target = pTarget->pev->target; - SetThink( &Next ); + SetThink( &CGunTarget::Next ); if (m_flWait != 0) {// -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; diff --git a/dlls/player.cpp b/dlls/player.cpp index 8ff7a395..7dee887d 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -933,7 +933,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) pev->angles.x = 0; pev->angles.z = 0; - SetThink( &PlayerDeathThink); + SetThink( &CBasePlayer::PlayerDeathThink); pev->nextthink = gpGlobals->time + 0.1; } @@ -1979,7 +1979,7 @@ void CBasePlayer::CheckTimeBasedDamage() return; // only check for time based damage approx. every 2 seconds - if (abs(gpGlobals->time - m_tbdPrev) < 2.0) + if ( fabs( gpGlobals->time - m_tbdPrev ) < 2.0 ) return; m_tbdPrev = gpGlobals->time; @@ -2200,7 +2200,7 @@ void CBasePlayer::CheckSuitUpdate() // play a sentence off of the end of the queue for (i = 0; i < CSUITPLAYLIST; i++) { - if (isentence = m_rgSuitPlayList[isearch]) + if ( ( isentence = m_rgSuitPlayList[isearch] ) ) break; if (++isearch == CSUITPLAYLIST) @@ -3209,7 +3209,7 @@ void CBloodSplat::Spawn ( entvars_t *pevOwner ) pev->angles = pevOwner->v_angle; pev->owner = ENT(pevOwner); - SetThink( &Spray ); + SetThink( &CBloodSplat::Spray ); pev->nextthink = gpGlobals->time + 0.1; } @@ -3224,7 +3224,7 @@ void CBloodSplat::Spray ( void ) UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); } - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -3537,7 +3537,7 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) case 107: { - TraceResult tr; + //TraceResult tr; edict_t *pWorld = g_engfuncs.pfnPEntityOfEntIndex( 0 ); @@ -3587,7 +3587,7 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) if ( pEntity ) { if ( pEntity->pev->takedamage ) - pEntity->SetThink( &SUB_Remove); + pEntity->SetThink( &CBaseEntity::SUB_Remove); } break; } @@ -4726,7 +4726,7 @@ void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP { UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); pev->nextthink = gpGlobals->time + MessageTime(); - SetThink( &MessageThink ); + SetThink( &CRevertSaved::MessageThink ); } @@ -4737,7 +4737,7 @@ void CRevertSaved :: MessageThink( void ) if ( nextThink > 0 ) { pev->nextthink = gpGlobals->time + nextThink; - SetThink( &LoadThink ); + SetThink( &CRevertSaved::LoadThink ); } else LoadThink(); diff --git a/dlls/player.h b/dlls/player.h index cbf95809..56e535fb 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -292,7 +292,7 @@ public: void SetCustomDecalFrames( int nFrames ); int GetCustomDecalFrames( void ); - void CBasePlayer::TabulateAmmo( void ); + void TabulateAmmo( void ); float m_flStartCharge; float m_flAmmoStartCharge; diff --git a/dlls/roach.cpp b/dlls/roach.cpp index 3c13bf1c..32ec66ae 100644 --- a/dlls/roach.cpp +++ b/dlls/roach.cpp @@ -262,7 +262,7 @@ void CRoach :: MonsterThink( void ) 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 ) + if ( pSound && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) { PickNewDest( ROACH_SMELL_FOOD ); SetActivity ( ACT_WALK ); diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index e13af4ab..b435b5cb 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -80,7 +80,7 @@ void CLaserSpot::Suspend( float flSuspendTime ) { pev->effects |= EF_NODRAW; - SetThink( &Revive ); + SetThink( &CLaserSpot::Revive ); pev->nextthink = gpGlobals->time + flSuspendTime; } @@ -133,8 +133,8 @@ void CRpgRocket :: Spawn( void ) pev->classname = MAKE_STRING("rpg_rocket"); - SetThink( &IgniteThink ); - SetTouch( &ExplodeTouch ); + SetThink( &CRpgRocket::IgniteThink ); + SetTouch( &CGrenade::ExplodeTouch ); pev->angles.x -= 30; UTIL_MakeVectors( pev->angles ); @@ -200,7 +200,7 @@ void CRpgRocket :: IgniteThink( void ) m_flIgniteTime = gpGlobals->time; // set to follow laser spot - SetThink( &FollowThink ); + SetThink( &CRpgRocket::FollowThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -284,7 +284,7 @@ void CRpgRocket :: FollowThink( void ) void CRpg::Reload( void ) { - int iResult; + int iResult = 0; if ( m_iClip == 1 ) { @@ -615,4 +615,4 @@ class CRpgAmmo : public CBasePlayerAmmo }; LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); -#endif \ No newline at end of file +#endif diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 0bd6513d..9eeb1abb 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -77,9 +77,9 @@ void CSatchelCharge :: Spawn( void ) 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( &SatchelSlide ); - SetUse( &DetonateUse ); - SetThink( &SatchelThink ); + SetTouch( &CSatchelCharge::SatchelSlide ); + SetUse( &CGrenade::DetonateUse ); + SetThink( &CSatchelCharge::SatchelThink ); pev->nextthink = gpGlobals->time + 0.1; pev->gravity = 0.5; @@ -322,7 +322,7 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) { m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } } @@ -491,4 +491,4 @@ void DeactivateSatchels( CBasePlayer *pOwner ) } } -#endif \ No newline at end of file +#endif diff --git a/dlls/saverestore.h b/dlls/saverestore.h index 3814aaaf..c774b62d 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -60,7 +60,7 @@ public: 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 + void WriteFunction( const char *pname, const int *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 ); diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 5b1742b3..f7e991ad 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -686,7 +686,7 @@ void CScientist :: Spawn( void ) pev->skin = 1; MonsterInit(); - SetUse( &FollowerUse ); + SetUse( &CTalkMonster::FollowerUse ); } //========================================================= @@ -1012,7 +1012,7 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) if ( IsFollowing() ) { int relationship = IRelationship( m_hEnemy ); - if ( relationship != R_FR || relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + 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; @@ -1240,7 +1240,7 @@ void CSittingScientist :: Spawn( ) pev->sequence = m_baseSequence + RANDOM_LONG(0,4); ResetSequenceInfo( ); - SetThink( &SittingThink); + SetThink( &CSittingScientist::SittingThink); pev->nextthink = gpGlobals->time + 0.1; DROP_TO_FLOOR ( ENT(pev) ); diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index 817e1f79..fbe56fd9 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -142,7 +142,7 @@ void CCineMonster :: Spawn( void ) // if no targetname, start now if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) { - SetThink( &CineThink ); + SetThink( &CCineMonster::CineThink ); pev->nextthink = gpGlobals->time + 1.0; // Wait to be used? if ( pev->targetname ) @@ -198,7 +198,7 @@ void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP else { // if not, try finding them - SetThink( &CineThink ); + SetThink( &CCineMonster::CineThink ); pev->nextthink = gpGlobals->time; } } @@ -253,7 +253,7 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) // void CCineMonster :: Die( void ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); } // @@ -564,7 +564,7 @@ void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -1026,7 +1026,7 @@ void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, US if ( !m_active ) return; // ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); - SetThink( &FindThink ); + SetThink( &CScriptedSentence::FindThink ); pev->nextthink = gpGlobals->time; } @@ -1039,7 +1039,7 @@ void CScriptedSentence :: Spawn( void ) // if no targetname, start now if ( !pev->targetname ) { - SetThink( &FindThink ); + SetThink( &CScriptedSentence::FindThink ); pev->nextthink = gpGlobals->time + 1.0; } @@ -1078,7 +1078,7 @@ void CScriptedSentence :: FindThink( void ) StartSentence( pMonster ); if ( pev->spawnflags & SF_SENTENCE_ONCE ) UTIL_Remove( this ); - SetThink( &DelayThink ); + 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) ); @@ -1096,7 +1096,7 @@ void CScriptedSentence :: DelayThink( void ) m_active = TRUE; if ( !pev->targetname ) pev->nextthink = gpGlobals->time + 0.1; - SetThink( &FindThink ); + SetThink( &CScriptedSentence::FindThink ); } @@ -1219,7 +1219,7 @@ LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); //========================================================= void CFurniture :: Die ( void ) { - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 01038247..f61086a5 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -193,7 +193,7 @@ void CAmbientGeneric :: Spawn( void ) { 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( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; @@ -203,12 +203,12 @@ void CAmbientGeneric :: Spawn( void ) // of ambient sound's pitch or volume. Don't // start thinking yet. - SetThink( &RampThink); + SetThink( &CAmbientGeneric::RampThink); pev->nextthink = 0; // allow on/off switching via 'use' function. - SetUse( &ToggleUse ); + SetUse( &CAmbientGeneric::ToggleUse ); m_fActive = FALSE; @@ -1824,19 +1824,19 @@ void CSpeaker :: Spawn( void ) { 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( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; - SetThink( &SpeakerThink); + SetThink( &CSpeaker::SpeakerThink); pev->nextthink = 0.0; // allow on/off switching via 'use' function. - SetUse( &ToggleUse ); + SetUse( &CSpeaker::ToggleUse ); Precache( ); } @@ -1975,4 +1975,4 @@ void CSpeaker :: KeyValue( KeyValueData *pkvd ) } else CBaseEntity::KeyValue( pkvd ); -} \ No newline at end of file +} diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index 93c70a7e..c3d169f1 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -274,7 +274,7 @@ void CSoundEnt :: Initialize ( void ) int CSoundEnt :: ISoundsInList ( int iListType ) { int i; - int iThisSound; + int iThisSound = 0; if ( iListType == SOUNDLISTTYPE_FREE ) { @@ -376,4 +376,4 @@ int CSoundEnt :: ClientSoundIndex ( edict_t *pClient ) #endif // _DEBUG return iReturn; -} \ No newline at end of file +} diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 0eacb2d8..5dd718a4 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -120,8 +120,8 @@ void CSqueakGrenade :: Spawn( void ) UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( &SuperBounceTouch ); - SetThink( &HuntThink ); + SetTouch( &CSqueakGrenade::SuperBounceTouch ); + SetThink( &CSqueakGrenade::HuntThink ); pev->nextthink = gpGlobals->time + 0.1; m_flNextHunt = gpGlobals->time + 1E6; @@ -162,7 +162,7 @@ void CSqueakGrenade::Precache( void ) void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; @@ -230,7 +230,7 @@ void CSqueakGrenade::HuntThink( void ) pev->velocity = pev->velocity * 0.9; pev->velocity.z += 8.0; } - else if (pev->movetype = MOVETYPE_FLY) + else if ( ( pev->movetype = MOVETYPE_FLY ) ) { pev->movetype = MOVETYPE_BOUNCE; } @@ -483,7 +483,7 @@ void CSqueak::Holster( int skiplocal /* = 0 */ ) if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) { m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; return; } @@ -598,4 +598,4 @@ void CSqueak::WeaponIdle( void ) SendWeaponAnim( iAnim ); } -#endif \ No newline at end of file +#endif diff --git a/dlls/subs.cpp b/dlls/subs.cpp index b48fc0f4..3de64d9a 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -231,7 +231,7 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl pTemp->pev->nextthink = gpGlobals->time + m_flDelay; - pTemp->SetThink( &DelayThink ); + pTemp->SetThink( &CBaseDelay::DelayThink ); // Save the useType pTemp->pev->button = (int)useType; @@ -413,7 +413,7 @@ void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) // set nextthink to trigger a call to LinearMoveDone when dest is reached pev->nextthink = pev->ltime + flTravelTime; - SetThink( &LinearMoveDone ); + SetThink( &CBaseToggle::LinearMoveDone ); // scale the destdelta vector by the time spent traveling to get velocity pev->velocity = vecDestDelta / flTravelTime; @@ -473,7 +473,7 @@ void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) // set nextthink to trigger a call to AngularMoveDone when dest is reached pev->nextthink = pev->ltime + flTravelTime; - SetThink( &AngularMoveDone ); + SetThink( &CBaseToggle::AngularMoveDone ); // scale the destdelta vector by the time spent traveling to get velocity pev->avelocity = vecDestDelta / flTravelTime; diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index 76ac05b7..ee0b0407 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -654,7 +654,7 @@ CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, Vector vecCheck; pszFriend = m_szFriends[ FriendNumber(listNumber) ]; - while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) + while ( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) { if (pFriend == this || !pFriend->IsAlive()) // don't talk to self or dead people @@ -687,7 +687,7 @@ void CTalkMonster::AlertFriends( void ) // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { - while (pFriend = EnumFriends( pFriend, i, TRUE )) + while ( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); if ( pMonster->IsAlive() ) @@ -709,7 +709,7 @@ void CTalkMonster::ShutUpFriends( void ) // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { - while (pFriend = EnumFriends( pFriend, i, TRUE )) + while ( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); if ( pMonster ) @@ -732,7 +732,7 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { - while (pFriend = EnumFriends( pFriend, i, FALSE )) + while ( ( pFriend = EnumFriends( pFriend, i, FALSE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); if ( pMonster ) @@ -831,7 +831,7 @@ CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) continue; // for each friend in this bsp... - while (pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend )) + while ( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) { if (pFriend == this || !pFriend->IsAlive()) // don't talk to self or dead people @@ -1119,7 +1119,7 @@ int CTalkMonster :: FIdleSpeak ( void ) if ( RANDOM_LONG(0,1) ) { //SENTENCEG_PlayRndSz( ENT(pev), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); - CBaseEntity *pFriend = FindNearestFriend(TRUE); + pFriend = FindNearestFriend(TRUE); if ( pFriend ) { diff --git a/dlls/tempmonster.cpp b/dlls/tempmonster.cpp index 2ad893f1..1f2cd7ed 100644 --- a/dlls/tempmonster.cpp +++ b/dlls/tempmonster.cpp @@ -114,4 +114,4 @@ void CMyMonster :: Precache() //========================================================= // AI Schedules Specific to this monster //========================================================= -#endif 0 +#endif //0 diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index 921a7b7d..016e850f 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -265,9 +265,9 @@ void CTentacle :: Spawn( ) m_bloodColor = BLOOD_COLOR_GREEN; - SetThink( &Start ); - SetTouch( &HitTouch ); - SetUse( &CommandUse ); + SetThink( &CTentacle::Start ); + SetTouch( &CTentacle::HitTouch ); + SetUse( &CTentacle::CommandUse ); pev->nextthink = gpGlobals->time + 0.2; @@ -714,7 +714,7 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T { case USE_OFF: pev->takedamage = DAMAGE_NO; - SetThink( &DieThink ); + SetThink( &CTentacle::DieThink ); m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; break; case USE_ON: @@ -728,7 +728,7 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T break; case USE_TOGGLE: pev->takedamage = DAMAGE_NO; - SetThink( &DieThink ); + SetThink( &CTentacle::DieThink ); m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; break; } @@ -926,7 +926,7 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) // void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) void CTentacle :: Start( void ) { - SetThink( &Cycle ); + SetThink( &CTentacle::Cycle ); if ( !g_fFlySound ) { @@ -1041,4 +1041,4 @@ void CTentacleMaw :: Precache( ) PRECACHE_MODEL("models/maw.mdl"); } -#endif \ No newline at end of file +#endif diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index d7c82806..871a1ecc 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -73,7 +73,7 @@ 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( &ChangeFriction ); + SetTouch( &CFrictionModifier::ChangeFriction ); } @@ -344,8 +344,8 @@ void CMultiManager :: KeyValue( KeyValueData *pkvd ) void CMultiManager :: Spawn( void ) { pev->solid = SOLID_NOT; - SetUse( &ManagerUse ); - SetThink( &ManagerThink); + SetUse( &CMultiManager::ManagerUse ); + SetThink( &CMultiManager::ManagerThink ); // Sort targets // Quick and dirty bubble sort @@ -403,7 +403,7 @@ void CMultiManager :: ManagerThink ( void ) UTIL_Remove( this ); return; } - SetUse( &ManagerUse );// allow manager re-use + SetUse( &CMultiManager::ManagerUse );// allow manager re-use } else pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; @@ -444,7 +444,7 @@ void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller SetUse( NULL );// disable use until all targets have fired - SetThink( &ManagerThink ); + SetThink( &CMultiManager::ManagerThink ); pev->nextthink = gpGlobals->time; } @@ -618,7 +618,7 @@ void CTriggerMonsterJump :: Spawn ( void ) {// if targetted, spawn turned off pev->solid = SOLID_NOT; UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetUse( &ToggleUse ); + SetUse( &CBaseTrigger::ToggleUse ); } } @@ -808,11 +808,11 @@ void CTargetCDAudio::Play( void ) void CTriggerHurt :: Spawn( void ) { InitTrigger(); - SetTouch( &HurtTouch ); + SetTouch( &CBaseTrigger::HurtTouch ); if ( !FStringNull ( pev->targetname ) ) { - SetUse( &ToggleUse ); + SetUse( &CBaseTrigger::ToggleUse ); } else { @@ -821,7 +821,7 @@ void CTriggerHurt :: Spawn( void ) if (m_bitsDamageInflict & DMG_RADIATION) { - SetThink( &RadiationThink ); + SetThink( &CTriggerHurt::RadiationThink ); pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); } @@ -1080,7 +1080,7 @@ void CTriggerMultiple :: Spawn( void ) // } // else { - SetTouch( &MultiTouch ); + SetTouch( &CBaseTrigger::MultiTouch ); } } @@ -1122,7 +1122,7 @@ void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) // 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") ) + ( ( pev->spawnflags & SF_TRIGGER_PUSHABLES ) && FClassnameIs( pevToucher,"func_pushable" ) ) ) { #if 0 @@ -1177,7 +1177,7 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) if (m_flWait > 0) { - SetThink( &MultiWaitOver ); + SetThink( &CBaseTrigger::MultiWaitOver ); pev->nextthink = gpGlobals->time + m_flWait; } else @@ -1186,7 +1186,7 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) // called while C code is looping through area links... SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); } } @@ -1266,7 +1266,7 @@ void CTriggerCounter :: Spawn( void ) if (m_cTriggersLeft == 0) m_cTriggersLeft = 2; - SetUse( &CounterUse ); + SetUse( &CBaseTrigger::CounterUse ); } // ====================== TRIGGER_CHANGELEVEL ================================ @@ -1411,11 +1411,11 @@ void CChangeLevel :: Spawn( void ) if (!FStringNull ( pev->targetname ) ) { - SetUse( &UseChangeLevel ); + SetUse( &CChangeLevel::UseChangeLevel ); } InitTrigger(); if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) - SetTouch( &TouchChangeLevel ); + SetTouch( &CChangeLevel::TouchChangeLevel ); // ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); } @@ -1820,7 +1820,7 @@ void CTriggerPush :: Spawn( ) if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. pev->solid = SOLID_NOT; - SetUse( &ToggleUse ); + SetUse( &CBaseTrigger::ToggleUse ); UTIL_SetOrigin( pev, pev->origin ); // Link into the list } @@ -1938,7 +1938,7 @@ void CTriggerTeleport :: Spawn( void ) { InitTrigger(); - SetTouch( &TeleportTouch ); + SetTouch( &CBaseTrigger::TeleportTouch ); } @@ -1963,7 +1963,7 @@ void CTriggerSave::Spawn( void ) } InitTrigger(); - SetTouch( &SaveTouch ); + SetTouch( &CTriggerSave::SaveTouch ); } void CTriggerSave::SaveTouch( CBaseEntity *pOther ) @@ -2018,10 +2018,10 @@ void CTriggerEndSection::Spawn( void ) InitTrigger(); - SetUse( &EndSectionUse ); + SetUse( &CTriggerEndSection::EndSectionUse ); // If it is a "use only" trigger, then don't set the touch function. if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) - SetTouch( &EndSectionTouch ); + SetTouch( &CTriggerEndSection::EndSectionTouch ); } void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) @@ -2064,7 +2064,7 @@ LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); void CTriggerGravity::Spawn( void ) { InitTrigger(); - SetTouch( &GravityTouch ); + SetTouch( &CTriggerGravity::GravityTouch ); } void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) @@ -2321,7 +2321,7 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); // follow the player down - SetThink( &FollowTarget ); + SetThink( &CTriggerCamera::FollowTarget ); pev->nextthink = gpGlobals->time; m_moveDistance = 0; diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index ce140f6c..11a6d959 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -120,7 +120,7 @@ void CTripmineGrenade :: Spawn( void ) m_flPowerUp = gpGlobals->time + 2.5; } - SetThink( &PowerupThink ); + SetThink( &CTripmineGrenade::PowerupThink ); pev->nextthink = gpGlobals->time + 0.2; pev->takedamage = DAMAGE_YES; @@ -158,7 +158,7 @@ void CTripmineGrenade :: WarningThink( void ) // EMIT_SOUND( ENT(pev), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); // set to power up - SetThink( &PowerupThink ); + SetThink( &CTripmineGrenade::PowerupThink ); pev->nextthink = gpGlobals->time + 1.0; } @@ -191,7 +191,7 @@ void CTripmineGrenade :: PowerupThink( void ) { STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::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(); @@ -206,7 +206,7 @@ void CTripmineGrenade :: PowerupThink( void ) CBaseEntity *pMine = Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); pMine->pev->spawnflags |= SF_NORESPAWN; - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); KillBeam(); pev->nextthink = gpGlobals->time + 0.1; return; @@ -249,7 +249,7 @@ void CTripmineGrenade :: MakeBeam( void ) m_flBeamLength = tr.flFraction; // set to follow laser spot - SetThink( &BeamBreakThink ); + SetThink( &CTripmineGrenade::BeamBreakThink ); pev->nextthink = gpGlobals->time + 0.1; Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; @@ -317,7 +317,7 @@ int CTripmineGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttac { // disable // Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; KillBeam(); return FALSE; @@ -335,7 +335,7 @@ void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) pev->owner = ENT( pevAttacker ); } - SetThink( &DelayDeathThink ); + 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 @@ -420,7 +420,7 @@ void CTripmine::Holster( int skiplocal /* = 0 */ ) { // out of mines m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; } diff --git a/dlls/turret.cpp b/dlls/turret.cpp index cc28f0bb..2077e87d 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -257,7 +257,7 @@ void CBaseTurret::Spawn() pev->takedamage = DAMAGE_AIM; SetBits (pev->flags, FL_MONSTER); - SetUse( &TurretUse ); + SetUse( &CBaseTurret::TurretUse ); if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) @@ -307,7 +307,7 @@ void CTurret::Spawn() m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - SetThink( &Initialize); + SetThink( &CBaseTurret::Initialize); m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); @@ -339,7 +339,7 @@ void CMiniTurret::Spawn() m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - SetThink( &Initialize); + SetThink( &CBaseTurret::Initialize); pev->nextthink = gpGlobals->time + 0.3; } @@ -381,11 +381,11 @@ void CBaseTurret::Initialize(void) if (m_iAutoStart) { m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &AutoSearchThink); + SetThink( &CBaseTurret::AutoSearchThink); pev->nextthink = gpGlobals->time + .1; } else - SetThink( &SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing); } void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) @@ -399,7 +399,7 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ pev->nextthink = gpGlobals->time + 0.1; m_iAutoStart = FALSE;// switching off a turret disables autostart //!!!! this should spin down first!!BUGBUG - SetThink( &Retire); + SetThink( &CBaseTurret::Retire); } else { @@ -411,7 +411,7 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ m_iAutoStart = TRUE; } - SetThink( &Deploy); + SetThink( &CBaseTurret::Deploy); } } @@ -472,7 +472,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &SearchThink); + SetThink( &CBaseTurret::SearchThink); return; } @@ -489,7 +489,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &SearchThink); + SetThink( &CBaseTurret::SearchThink); return; } } @@ -518,7 +518,7 @@ void CBaseTurret::ActiveThink(void) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &SearchThink); + SetThink( &CBaseTurret::SearchThink); return; } } @@ -670,7 +670,7 @@ void CBaseTurret::Deploy(void) SetTurretAnim(TURRET_ANIM_SPIN); pev->framerate = 0; - SetThink( &SearchThink); + SetThink( &CBaseTurret::SearchThink); } m_flLastSight = gpGlobals->time + m_flMaxWait; @@ -710,11 +710,11 @@ void CBaseTurret::Retire(void) UTIL_SetSize(pev, pev->mins, pev->maxs); if (m_iAutoStart) { - SetThink( &AutoSearchThink); + SetThink( &CBaseTurret::AutoSearchThink); pev->nextthink = gpGlobals->time + .1; } else - SetThink( &SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing); } } else @@ -746,7 +746,7 @@ void CTurret::SpinUpCall(void) { pev->nextthink = gpGlobals->time + 0.1; // retarget delay EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink( &ActiveThink); + SetThink( &CBaseTurret::ActiveThink); m_iStartSpin = 0; m_iSpin = 1; } @@ -758,7 +758,7 @@ void CTurret::SpinUpCall(void) if (m_iSpin) { - SetThink( &ActiveThink); + SetThink( &CBaseTurret::ActiveThink); } } @@ -856,7 +856,7 @@ void CBaseTurret::SearchThink(void) { m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink( &ActiveThink); + SetThink( &CBaseTurret::ActiveThink); } else { @@ -866,7 +866,7 @@ void CBaseTurret::SearchThink(void) //Before we retrace, make sure that we are spun down. m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink( &Retire); + SetThink( &CBaseTurret::Retire); } // should we stop the spin? else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) @@ -911,7 +911,7 @@ void CBaseTurret::AutoSearchThink(void) if (m_hEnemy != NULL) { - SetThink( &Deploy); + SetThink( &CBaseTurret::Deploy); EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); } } @@ -1025,7 +1025,7 @@ int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, flo ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? SetUse( NULL ); - SetThink( &TurretDeath); + SetThink( &CBaseTurret::TurretDeath); SUB_UseTargets( this, USE_ON, 0 ); // wake up others pev->nextthink = gpGlobals->time + 0.1; @@ -1037,7 +1037,7 @@ int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, flo if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) { m_fBeserk = 1; - SetThink( &SearchThink); + SetThink( &CBaseTurret::SearchThink); } } @@ -1179,8 +1179,8 @@ void CSentry::Spawn() m_iMinPitch = -60; UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - SetTouch( &SentryTouch); - SetThink( &Initialize); + SetTouch( &CSentry::SentryTouch); + SetThink( &CBaseTurret::Initialize); pev->nextthink = gpGlobals->time + 0.3; } @@ -1204,7 +1204,7 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f if (!m_iOn) { - SetThink( &Deploy ); + SetThink( &CBaseTurret::Deploy ); SetUse( NULL ); pev->nextthink = gpGlobals->time + 0.1; } @@ -1219,7 +1219,7 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? SetUse( NULL ); - SetThink( &SentryDeath); + SetThink( &CSentry::SentryDeath); SUB_UseTargets( this, USE_ON, 0 ); // wake up others pev->nextthink = gpGlobals->time + 0.1; diff --git a/dlls/util.cpp b/dlls/util.cpp index 867bb3e1..3533a778 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1973,7 +1973,7 @@ void CSave :: WritePositionVector( const char *pname, const float *value, int co } -void CSave :: WriteFunction( const char *pname, void **data, int count ) +void CSave :: WriteFunction( const char *pname, const int *data, int count ) { const char *functionName; @@ -2141,7 +2141,7 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p break; case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (void **)pOutputData, pTest->fieldSize ); + WriteFunction( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); break; default: ALERT( at_error, "Bad field type\n" ); diff --git a/dlls/util.h b/dlls/util.h index 1edc0411..cbf3a9ca 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -36,7 +36,7 @@ extern globalvars_t *gpGlobals; // Use this instead of ALLOC_STRING on constant strings #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) -#define MAKE_STRING(str) ((int)str - (int)STRING(0)) +#define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) { @@ -248,7 +248,7 @@ typedef enum { ignore_monsters=1, dont_ignore_monsters=0, missile=2 } IGNORE_MON 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 }; +enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; 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); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 264edb88..6a65f298 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -477,8 +477,8 @@ void CBasePlayerItem :: FallInit( void ) UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. - SetTouch( &DefaultTouch ); - SetThink( &FallThink ); + SetTouch( &CBasePlayerItem::DefaultTouch ); + SetThink( &CBasePlayerItem::FallThink ); pev->nextthink = gpGlobals->time + 0.1; } @@ -528,7 +528,7 @@ void CBasePlayerItem::Materialize( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch( &DefaultTouch); + SetTouch( &CBasePlayerItem::DefaultTouch); SetThink( NULL ); } @@ -581,7 +581,7 @@ CBaseEntity* CBasePlayerItem::Respawn( void ) { pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now pNewWeapon->SetTouch( NULL );// no touch - pNewWeapon->SetThink( &AttemptToMaterialize ); + pNewWeapon->SetThink( &CBasePlayerItem::AttemptToMaterialize ); DROP_TO_FLOOR ( ENT(pev) ); @@ -739,14 +739,14 @@ int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) void CBasePlayerItem::Drop( void ) { SetTouch( NULL ); - SetThink( &SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + .1; } void CBasePlayerItem::Kill( void ) { SetTouch( NULL ); - SetThink( &SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + .1; } @@ -1066,7 +1066,7 @@ void CBasePlayerAmmo::Spawn( void ) UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( &DefaultTouch ); + SetTouch( &CBaseEntity::DefaultTouch ); } CBaseEntity* CBasePlayerAmmo::Respawn( void ) @@ -1076,7 +1076,7 @@ CBaseEntity* CBasePlayerAmmo::Respawn( void ) UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. - SetThink( &Materialize ); + SetThink( &CBasePlayerAmmo::Materialize ); pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); return this; @@ -1092,7 +1092,7 @@ void CBasePlayerAmmo::Materialize( void ) pev->effects |= EF_MUZZLEFLASH; } - SetTouch( &DefaultTouch ); + SetTouch( &CBasePlayerAmmo::DefaultTouch ); } void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) @@ -1111,7 +1111,7 @@ void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) else { SetTouch( NULL ); - SetThink( &SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + .1; } } @@ -1119,7 +1119,7 @@ void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { // evil impulse 101 hack, kill always SetTouch( NULL ); - SetThink( &SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + .1; } } @@ -1256,7 +1256,7 @@ void CWeaponBox::Kill( void ) while ( pWeapon ) { - pWeapon->SetThink( &SUB_Remove); + pWeapon->SetThink( &CBaseEntity::SUB_Remove); pWeapon->pev->nextthink = gpGlobals->time + 0.1; pWeapon = pWeapon->m_pNext; } diff --git a/dlls/weapons.h b/dlls/weapons.h index aaa98247..38ba9794 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -445,7 +445,7 @@ public: int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; - HasWeapon( CBasePlayerItem *pCheckItem ); + BOOL HasWeapon( CBasePlayerItem *pCheckItem ); BOOL PackWeapon( CBasePlayerItem *pWeapon ); BOOL PackAmmo( int iszName, int iCount ); diff --git a/dlls/world.cpp b/dlls/world.cpp index cb20add3..1206824b 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -125,15 +125,15 @@ void CDecal :: Spawn( void ) if ( FStringNull ( pev->targetname ) ) { - SetThink( &StaticDecal ); + 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( &SUB_DoNothing ); - SetUse( &TriggerDecal); + SetThink( &CBaseEntity::SUB_DoNothing ); + SetUse( &CDecal::TriggerDecal); } } @@ -158,7 +158,7 @@ void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); MESSAGE_END(); - SetThink( &SUB_Remove ); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } @@ -642,7 +642,7 @@ void CWorld :: Precache( void ) CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); if ( pEntity ) { - pEntity->SetThink( &SUB_CallUseToggle ); + pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); pEntity->pev->message = pev->netname; pev->netname = 0; pEntity->pev->nextthink = gpGlobals->time + 0.3; @@ -857,4 +857,4 @@ int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEn memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) ); return TRUE; -} \ No newline at end of file +} diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h index 0271a117..58871a4a 100644 --- a/game_shared/bitvec.h +++ b/game_shared/bitvec.h @@ -13,7 +13,7 @@ #include - +#include class CBitVecAccessor { diff --git a/game_shared/voice_gamemgr.cpp b/game_shared/voice_gamemgr.cpp index 5ba2edfe..b3f16714 100644 --- a/game_shared/voice_gamemgr.cpp +++ b/game_shared/voice_gamemgr.cpp @@ -179,7 +179,7 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) for(int i=1; i < CMD_ARGC(); i++) { unsigned long mask = 0; - sscanf(CMD_ARGV(i), "%x", &mask); + sscanf(CMD_ARGV(i), "%lx", &mask); if(i <= VOICE_MAX_PLAYERS_DW) { @@ -238,7 +238,7 @@ void CVoiceGameMgr::UpdateMasks() // Build a mask of who they can hear based on the game rules. for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) { - CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1); + pEnt = UTIL_PlayerByIndex(iOtherClient+1); if(pEnt && pEnt->IsPlayer() && (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) { From bdc4e3f8d39f5d9e02a93b1d643d3ab738300c4a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 18 Apr 2016 01:44:31 +0500 Subject: [PATCH 022/227] Fix build. --- dlls/weapons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 6a65f298..e82d1006 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1066,7 +1066,7 @@ void CBasePlayerAmmo::Spawn( void ) UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); UTIL_SetOrigin( pev, pev->origin ); - SetTouch( &CBaseEntity::DefaultTouch ); + SetTouch( &CBasePlayerAmmo::DefaultTouch ); } CBaseEntity* CBasePlayerAmmo::Respawn( void ) From d287ed446332e615ab5fb25ca81b99fa14d18a73 Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 22 Apr 2016 14:27:54 +0000 Subject: [PATCH 023/227] 64 bit support --- cl_dll/StudioModelRenderer.cpp | 2 +- dlls/nodes.cpp | 8 ++++---- dlls/util.cpp | 6 +++--- dlls/util.h | 5 ++++- engine/studio.h | 4 +++- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index e0845c29..cbda63cd 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -377,7 +377,7 @@ mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudi if (pseqdesc->seqgroup == 0) { - return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); + return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqdesc->animindex); } paSequences = (cache_user_t *)m_pSubModel->submodels; diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 1a55cd43..80bcc33e 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -3312,10 +3312,10 @@ void CGraph :: ComputeStaticRoutingTables( void ) } 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; + if (Routes) delete[] Routes; + if (BestNextNodes) delete[] BestNextNodes; + if (pRoute) delete[] pRoute; + if (pMyPath) delete[] pMyPath; Routes = 0; BestNextNodes = 0; pRoute = 0; diff --git a/dlls/util.cpp b/dlls/util.cpp index 867bb3e1..f4408e06 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2372,13 +2372,13 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou break; case FIELD_POINTER: - *((int *)pOutputData) = *( int *)pInputData; + *((void**)pOutputData) = *( void **)pInputData; break; case FIELD_FUNCTION: if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; + *((void**)pOutputData) = 0; else - *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); + *((void**)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); break; default: diff --git a/dlls/util.h b/dlls/util.h index 1edc0411..2de039fc 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -36,8 +36,11 @@ extern globalvars_t *gpGlobals; // Use this instead of ALLOC_STRING on constant strings #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) +#if !defined __amd64__ || defined(CLIENT_DLL) #define MAKE_STRING(str) ((int)str - (int)STRING(0)) - +#else +#define MAKE_STRING ALLOC_STRING +#endif inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) { return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); diff --git a/engine/studio.h b/engine/studio.h index 8cffc27a..3d4f3d87 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -215,7 +215,9 @@ typedef struct char label[32]; // textual name char name[64]; // file name cache_user_t cache; // cache index pointer +#ifndef __amd64 int data; // hack for group 0 +#endif } mstudioseqgroup_t; // sequence descriptions @@ -366,4 +368,4 @@ typedef struct short s,t; // s,t position on skin } mstudiotrivert_t; -#endif//STUDIO_H \ No newline at end of file +#endif//STUDIO_H From 0549ead5aba67be2feca2957dca49220ba1e61fd Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 23 Apr 2016 20:18:48 +0500 Subject: [PATCH 024/227] Rework initialization. --- cl_dll/hud_spectator.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 33a95d35..54d723c5 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -867,16 +867,13 @@ bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) bool CHudSpectator::ParseOverviewFile( ) { - char filename[255]; - char levelname[255]; - char token[1024]; + char filename[255] = { 0 }; + char levelname[255] = { 0 }; + char token[1024] = { 0 }; float height; char *pfile = NULL; - memset( filename, 0, 255 ); - memset( levelname, 0, 255 ); - memset( token, 0, 1024 ); memset( &m_OverviewData, 0, sizeof(m_OverviewData)); // fill in standrd values From 015b5425ff290eb99120c1312dbbc19290a57c54 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 17:05:10 +0500 Subject: [PATCH 025/227] Add missing cast. --- dlls/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index d1507229..5f25f79f 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2378,7 +2378,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou if ( strlen( (char *)pInputData ) == 0 ) *((void**)pOutputData) = 0; else - *((void**)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); + *((void**)pOutputData) = (void**)FUNCTION_FROM_NAME( (char *)pInputData ); break; default: From 57b52d0a1ce58a63068c74092a68dbe3bb72acbe Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 17:09:45 +0500 Subject: [PATCH 026/227] Remove unneeded definition. --- engine/eiface.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/engine/eiface.h b/engine/eiface.h index 64984b10..5f830ac9 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -34,12 +34,6 @@ // This is conveniently done for them in extdll.h // -#ifdef _WIN32 -#define DLLEXPORT __stdcall -#else -#define DLLEXPORT /* */ -#endif - typedef enum { at_notice, @@ -494,4 +488,4 @@ extern NEW_DLL_FUNCTIONS gNewDLLFunctions; typedef int (*APIFUNCTION)( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); typedef int (*APIFUNCTION2)( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); -#endif//EIFACE_H \ No newline at end of file +#endif//EIFACE_H From a569c16c2f72984f59d8cc0289fd5985c627a342 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 17:17:44 +0500 Subject: [PATCH 027/227] Fix strange definition. --- dlls/h_export.cpp | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index bdbad2c6..a2e533c5 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -46,27 +46,10 @@ BOOL WINAPI DllMain( } return TRUE; } +#endif^M -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) __attribute__((__stdcall__)) ; - - -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; } - - -#else - -extern "C" { - -void GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -{ - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; -} - -} - -#endif From e0136428bb70a34bdeb7195ed00bc2a581760698 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 17:20:18 +0500 Subject: [PATCH 028/227] Remov flag -fpermissive from Android Makefiles. --- cl_dll/Android.mk | 2 +- dlls/Android.mk | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index b5f3f311..94489844 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -91,7 +91,7 @@ SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -fpermissive -w +DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ $(LOCAL_PATH)/../common \ diff --git a/dlls/Android.mk b/dlls/Android.mk index 38e6a019..e0266879 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -14,9 +14,9 @@ LOCAL_MODULE_FILENAME = libserver_hardfp endif LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \ - -fno-exceptions -w -fpermissive + -fno-exceptions -w -LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti -fpermissive +LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti LOCAL_C_INCLUDES := $(SDL_PATH)/include \ $(LOCAL_PATH)/. \ From 4304846337b7a68fd003d483a7420ee679a3be3a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 18:24:23 +0500 Subject: [PATCH 029/227] CRLF to LF all. --- cl_dll/GameStudioModelRenderer.cpp | 236 +- cl_dll/GameStudioModelRenderer.h | 50 +- cl_dll/GameStudioModelRenderer_Sample.cpp | 1984 ++--- cl_dll/GameStudioModelRenderer_Sample.h | 108 +- cl_dll/StudioModelRenderer.cpp | 3406 ++++---- cl_dll/StudioModelRenderer.h | 376 +- cl_dll/ammo.cpp | 2406 +++--- cl_dll/ammo.h | 122 +- cl_dll/ammo_secondary.cpp | 318 +- cl_dll/ammohistory.cpp | 378 +- cl_dll/ammohistory.h | 286 +- cl_dll/battery.cpp | 274 +- cl_dll/camera.h | 48 +- cl_dll/cdll_int.cpp | 556 +- cl_dll/cl_dll.h | 92 +- cl_dll/cl_util.h | 352 +- cl_dll/com_weapons.cpp | 554 +- cl_dll/com_weapons.h | 94 +- cl_dll/death.cpp | 606 +- cl_dll/demo.cpp | 202 +- cl_dll/demo.h | 52 +- cl_dll/entity.cpp | 1948 ++--- cl_dll/ev_common.cpp | 408 +- cl_dll/ev_hldm.cpp | 3398 ++++---- cl_dll/ev_hldm.h | 188 +- cl_dll/events.cpp | 44 +- cl_dll/eventscripts.h | 146 +- cl_dll/flashlight.cpp | 294 +- cl_dll/geiger.cpp | 368 +- cl_dll/health.cpp | 966 +-- cl_dll/health.h | 254 +- cl_dll/hl/hl_baseentity.cpp | 692 +- cl_dll/hl/hl_events.cpp | 160 +- cl_dll/hl/hl_objects.cpp | 180 +- cl_dll/hl/hl_weapons.cpp | 2202 ++--- cl_dll/hud.cpp | 1176 +-- cl_dll/hud.h | 1404 +-- cl_dll/hud_iface.h | 38 +- cl_dll/hud_msg.cpp | 240 +- cl_dll/hud_redraw.cpp | 730 +- cl_dll/hud_servers.cpp | 2458 +++--- cl_dll/hud_servers.h | 80 +- cl_dll/hud_servers_priv.h | 194 +- cl_dll/hud_spectator.cpp | 3190 +++---- cl_dll/hud_spectator.h | 264 +- cl_dll/hud_update.cpp | 108 +- cl_dll/in_camera.cpp | 1240 +-- cl_dll/in_defs.h | 60 +- cl_dll/input.cpp | 2008 ++--- cl_dll/inputw32.cpp | 1892 ++-- cl_dll/kbutton.h | 34 +- cl_dll/menu.cpp | 368 +- cl_dll/message.cpp | 1072 +-- cl_dll/overview.cpp | 318 +- cl_dll/overview.h | 62 +- cl_dll/parsemsg.cpp | 332 +- cl_dll/parsemsg.h | 80 +- cl_dll/saytext.cpp | 624 +- cl_dll/soundsystem.cpp | 324 +- cl_dll/status_icons.cpp | 324 +- cl_dll/statusbar.cpp | 530 +- cl_dll/studio_util.cpp | 500 +- cl_dll/studio_util.h | 78 +- cl_dll/text_message.cpp | 418 +- cl_dll/tf_defs.h | 2778 +++--- cl_dll/train.cpp | 170 +- cl_dll/tri.cpp | 244 +- cl_dll/util.cpp | 266 +- cl_dll/util_vector.h | 242 +- cl_dll/view.cpp | 3384 ++++---- cl_dll/view.h | 28 +- common/beamdef.h | 118 +- common/bspfile.h | 490 +- common/cl_entity.h | 208 +- common/com_model.h | 824 +- common/con_nprint.h | 48 +- common/const.h | 1558 ++-- common/cvardef.h | 72 +- common/demo_api.h | 52 +- common/dlight.h | 60 +- common/entity_state.h | 370 +- common/entity_types.h | 48 +- common/event_api.h | 106 +- common/event_args.h | 92 +- common/event_flags.h | 88 +- common/gameinfo.h | 96 +- common/hltv.h | 116 +- common/ivoicetweak.h | 78 +- common/lightstyle.h | 56 +- common/mathlib.h | 190 +- common/net_api.h | 192 +- common/netadr.h | 72 +- common/particledef.h | 106 +- common/pmtrace.h | 80 +- common/qfont.h | 74 +- common/r_efx.h | 388 +- common/r_studioint.h | 306 +- common/ref_params.h | 178 +- common/render_api.h | 520 +- common/screenfade.h | 56 +- common/studio_event.h | 52 +- common/triangleapi.h | 122 +- common/usercmd.h | 76 +- common/wadfile.h | 156 +- common/weaponinfo.h | 98 +- common/wrect.h | 46 +- dlls/AI_BaseNPC_Schedule.cpp | 3028 +++---- dlls/Wxdebug.cpp | 790 +- dlls/activity.h | 218 +- dlls/activitymap.h | 194 +- dlls/aflock.cpp | 1820 ++-- dlls/agrunt.cpp | 2372 ++--- dlls/airtank.cpp | 236 +- dlls/animating.cpp | 636 +- dlls/animation.cpp | 1048 +-- dlls/animation.h | 94 +- dlls/apache.cpp | 2098 ++--- dlls/barnacle.cpp | 898 +- dlls/barney.cpp | 1682 ++-- dlls/basemonster.h | 678 +- dlls/bigmomma.cpp | 2502 +++--- dlls/bloater.cpp | 438 +- dlls/bmodels.cpp | 1916 ++-- dlls/bullsquid.cpp | 2550 +++--- dlls/buttons.cpp | 2552 +++--- dlls/cbase.cpp | 1548 ++-- dlls/cbase.h | 1600 ++-- dlls/cdll_dll.h | 90 +- dlls/client.cpp | 3608 ++++---- dlls/client.h | 130 +- dlls/combat.cpp | 3412 ++++---- dlls/controller.cpp | 2854 +++--- dlls/crossbow.cpp | 1126 +-- dlls/crowbar.cpp | 636 +- dlls/decals.h | 150 +- dlls/defaultai.cpp | 2464 +++--- dlls/defaultai.h | 196 +- dlls/doors.cpp | 2156 ++--- dlls/doors.h | 66 +- dlls/effects.cpp | 4534 +++++----- dlls/effects.h | 418 +- dlls/egon.cpp | 1134 +-- dlls/enginecallback.h | 314 +- dlls/explode.cpp | 546 +- dlls/explode.h | 64 +- dlls/exportdef.h | 36 +- dlls/extdll.h | 176 +- dlls/flyingmonster.cpp | 562 +- dlls/flyingmonster.h | 106 +- dlls/func_break.cpp | 2010 ++--- dlls/func_break.h | 148 +- dlls/func_tank.cpp | 2078 ++--- dlls/game.cpp | 1774 ++-- dlls/game.h | 90 +- dlls/gamerules.cpp | 694 +- dlls/gamerules.h | 720 +- dlls/gargantua.cpp | 2734 +++--- dlls/gauss.cpp | 1242 +-- dlls/genericmonster.cpp | 280 +- dlls/ggrenade.cpp | 976 +-- dlls/globals.cpp | 78 +- dlls/glock.cpp | 548 +- dlls/gman.cpp | 474 +- dlls/h_ai.cpp | 398 +- dlls/h_battery.cpp | 398 +- dlls/h_cine.cpp | 482 +- dlls/h_cycler.cpp | 942 +- dlls/h_export.cpp | 110 +- dlls/handgrenade.cpp | 466 +- dlls/hassassin.cpp | 2028 ++--- dlls/headcrab.cpp | 1110 +-- dlls/healthkit.cpp | 526 +- dlls/hgrunt.cpp | 5034 +++++------ dlls/hornet.cpp | 838 +- dlls/hornet.h | 116 +- dlls/hornetgun.cpp | 608 +- dlls/houndeye.cpp | 2608 +++--- dlls/ichthyosaur.cpp | 2214 ++--- dlls/islave.cpp | 1732 ++-- dlls/items.cpp | 684 +- dlls/items.h | 58 +- dlls/leech.cpp | 1446 ++-- dlls/lights.cpp | 398 +- dlls/maprules.cpp | 1836 ++-- dlls/maprules.h | 44 +- dlls/monsterevent.h | 68 +- dlls/monstermaker.cpp | 584 +- dlls/monsters.cpp | 6896 +++++++-------- dlls/monsters.h | 366 +- dlls/monsterstate.cpp | 468 +- dlls/mortar.cpp | 644 +- dlls/mp5.cpp | 770 +- dlls/mpstubb.cpp | 528 +- dlls/multiplay_gamerules.cpp | 3396 ++++---- dlls/nihilanth.cpp | 3670 ++++---- dlls/nodes.cpp | 7298 ++++++++-------- dlls/nodes.h | 748 +- dlls/osprey.cpp | 1610 ++-- dlls/pathcorner.cpp | 856 +- dlls/physcallback.h | 64 +- dlls/plane.cpp | 120 +- dlls/plane.h | 86 +- dlls/plats.cpp | 4570 +++++----- dlls/player.cpp | 9582 ++++++++++----------- dlls/player.h | 648 +- dlls/playermonster.cpp | 244 +- dlls/python.cpp | 638 +- dlls/rat.cpp | 196 +- dlls/roach.cpp | 920 +- dlls/rpg.cpp | 1234 +-- dlls/satchel.cpp | 986 +-- dlls/saverestore.h | 338 +- dlls/schedule.cpp | 3028 +++---- dlls/schedule.h | 580 +- dlls/scientist.cpp | 2856 +++--- dlls/scripted.cpp | 2520 +++--- dlls/scripted.h | 214 +- dlls/scriptevent.h | 58 +- dlls/shotgun.cpp | 802 +- dlls/singleplay_gamerules.cpp | 656 +- dlls/skill.cpp | 94 +- dlls/skill.h | 294 +- dlls/sound.cpp | 3954 ++++----- dlls/soundent.cpp | 756 +- dlls/soundent.h | 190 +- dlls/spectator.cpp | 298 +- dlls/spectator.h | 52 +- dlls/squad.h | 38 +- dlls/squadmonster.cpp | 1246 +-- dlls/squadmonster.h | 240 +- dlls/squeakgrenade.cpp | 1200 +-- dlls/stats.cpp | 312 +- dlls/subs.cpp | 1118 +-- dlls/talkmonster.cpp | 2944 +++---- dlls/talkmonster.h | 366 +- dlls/teamplay_gamerules.cpp | 1260 +-- dlls/teamplay_gamerules.h | 114 +- dlls/tempmonster.cpp | 234 +- dlls/tentacle.cpp | 2086 ++--- dlls/trains.h | 254 +- dlls/triggers.cpp | 4868 +++++------ dlls/tripmine.cpp | 1052 +-- dlls/turret.cpp | 2610 +++--- dlls/util.h | 1096 +-- dlls/vector.h | 222 +- dlls/weapons.cpp | 3160 +++---- dlls/weapons.h | 2030 ++--- dlls/world.cpp | 1718 ++-- dlls/wxdebug.h | 274 +- dlls/xen.cpp | 1168 +-- dlls/zombie.cpp | 690 +- engine/anorms.h | 354 +- engine/cdll_exp.h | 136 +- engine/cdll_int.h | 614 +- engine/custom.h | 184 +- engine/customentity.h | 76 +- engine/edict.h | 82 +- engine/eiface.h | 980 +-- engine/keydefs.h | 264 +- engine/menu_int.h | 374 +- engine/physint.h | 226 +- engine/progdefs.h | 434 +- engine/shake.h | 98 +- engine/sprite.h | 202 +- engine/studio.h | 742 +- engine/warpsin.h | 106 +- game_shared/bitvec.h | 358 +- game_shared/vgui_checkbutton2.cpp | 394 +- game_shared/vgui_checkbutton2.h | 202 +- game_shared/vgui_defaultinputsignal.h | 78 +- game_shared/vgui_grid.cpp | 796 +- game_shared/vgui_grid.h | 244 +- game_shared/vgui_helpers.cpp | 90 +- game_shared/vgui_helpers.h | 62 +- game_shared/vgui_listbox.cpp | 414 +- game_shared/vgui_listbox.h | 230 +- game_shared/vgui_loadtga.cpp | 186 +- game_shared/vgui_loadtga.h | 44 +- game_shared/vgui_scrollbar2.cpp | 620 +- game_shared/vgui_scrollbar2.h | 124 +- game_shared/vgui_slider2.cpp | 870 +- game_shared/vgui_slider2.h | 134 +- game_shared/voice_banmgr.cpp | 394 +- game_shared/voice_banmgr.h | 114 +- game_shared/voice_common.h | 48 +- game_shared/voice_gamemgr.cpp | 548 +- game_shared/voice_gamemgr.h | 158 +- game_shared/voice_status.cpp | 1748 ++-- game_shared/voice_status.h | 456 +- game_shared/voice_vgui_tweakdlg.cpp | 578 +- game_shared/voice_vgui_tweakdlg.h | 50 +- pm_shared/pm_debug.c | 640 +- pm_shared/pm_debug.h | 44 +- pm_shared/pm_defs.h | 440 +- pm_shared/pm_info.h | 38 +- pm_shared/pm_materials.h | 62 +- pm_shared/pm_math.c | 844 +- pm_shared/pm_movevars.h | 106 +- pm_shared/pm_shared.c | 6662 +++++++------- pm_shared/pm_shared.h | 62 +- 300 files changed, 133343 insertions(+), 133343 deletions(-) diff --git a/cl_dll/GameStudioModelRenderer.cpp b/cl_dll/GameStudioModelRenderer.cpp index 9cfca965..c7211752 100644 --- a/cl_dll/GameStudioModelRenderer.cpp +++ b/cl_dll/GameStudioModelRenderer.cpp @@ -1,118 +1,118 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "com_model.h" -#include "studio.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "dlight.h" -#include "triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -// -// Override the StudioModelRender virtual member functions here to implement custom bone -// setup, blending, etc. -// - -// Global engine <-> studio model rendering code interface -extern engine_studio_api_t IEngineStudio; - -// The renderer object, created on the stack. -CGameStudioModelRenderer g_StudioRenderer; -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -CGameStudioModelRenderer::CGameStudioModelRenderer( void ) -{ -} - -//////////////////////////////////// -// Hooks to class implementation -//////////////////////////////////// - -/* -==================== -R_StudioDrawPlayer - -==================== -*/ -int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); -} - -/* -==================== -R_StudioDrawModel - -==================== -*/ -int R_StudioDrawModel( int flags ) -{ - return g_StudioRenderer.StudioDrawModel( flags ); -} - -/* -==================== -R_StudioInit - -==================== -*/ -void R_StudioInit( void ) -{ - g_StudioRenderer.Init(); -} - -// The simple drawing interface we'll pass back to the engine -r_studio_interface_t studio = -{ - STUDIO_INTERFACE_VERSION, - R_StudioDrawModel, - R_StudioDrawPlayer, -}; - -/* -==================== -HUD_GetStudioModelInterface - -Export this function for the engine to use the studio renderer class to render objects. -==================== -*/ -extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) -{ - if ( version != STUDIO_INTERFACE_VERSION ) - return 0; - - // Point the engine to our callbacks - *ppinterface = &studio; - - // Copy in engine helper functions - memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); - - // Initialize local variables, etc. - R_StudioInit(); - - // Success - return 1; -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// +// Override the StudioModelRender virtual member functions here to implement custom bone +// setup, blending, etc. +// + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer.h b/cl_dll/GameStudioModelRenderer.h index a9d2efff..7d06f70f 100644 --- a/cl_dll/GameStudioModelRenderer.h +++ b/cl_dll/GameStudioModelRenderer.h @@ -1,26 +1,26 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( GAMESTUDIOMODELRENDERER_H ) -#define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -class CGameStudioModelRenderer : public CStudioModelRenderer -{ -public: - CGameStudioModelRenderer( void ); -}; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); +}; + #endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/GameStudioModelRenderer_Sample.cpp b/cl_dll/GameStudioModelRenderer_Sample.cpp index ec31e479..d697d927 100644 --- a/cl_dll/GameStudioModelRenderer_Sample.cpp +++ b/cl_dll/GameStudioModelRenderer_Sample.cpp @@ -1,992 +1,992 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "com_model.h" -#include "studio.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "dlight.h" -#include "triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -// Predicted values saved off in hl_weapons.cpp -void Game_GetSequence( int *seq, int *gaitseq ); -void Game_GetOrientation( float *o, float *a ); - -float g_flStartScaleTime; -int iPrevRenderState; -int iRenderStateChanged; - -// Global engine <-> studio model rendering code interface -extern engine_studio_api_t IEngineStudio; - -typedef struct -{ - vec3_t origin; - vec3_t angles; - - vec3_t realangles; - - float animtime; - float frame; - int sequence; - int gaitsequence; - float framerate; - - int m_fSequenceLoops; - int m_fSequenceFinished; - - byte controller[ 4 ]; - byte blending[ 2 ]; - - latchedvars_t lv; -} client_anim_state_t; - -static client_anim_state_t g_state; -static client_anim_state_t g_clientstate; - -// The renderer object, created on the stack. -CGameStudioModelRenderer g_StudioRenderer; -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -CGameStudioModelRenderer::CGameStudioModelRenderer( void ) -{ - // If you want to predict animations locally, set this to TRUE - // NOTE: The animation code is somewhat broken, but gives you a sense for how - // to do client side animation of the predicted player in a third person game. - m_bLocal = false; -} - -/* -==================== -StudioSetupBones - -==================== -*/ -void CGameStudioModelRenderer::StudioSetupBones ( void ) -{ - int i; - double f; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - static vec4_t q[MAXSTUDIOBONES]; - float bonematrix[3][4]; - - static float pos2[MAXSTUDIOBONES][3]; - static vec4_t q2[MAXSTUDIOBONES]; - static float pos3[MAXSTUDIOBONES][3]; - static vec4_t q3[MAXSTUDIOBONES]; - static float pos4[MAXSTUDIOBONES][3]; - static vec4_t q4[MAXSTUDIOBONES]; - - // Use default bone setup for nonplayers - if ( !m_pCurrentEntity->player ) - { - CStudioModelRenderer::StudioSetupBones(); - return; - } - - // Bound sequence number. - if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) - { - f = m_pPlayerInfo->gaitframe; - } - else - { - f = StudioEstimateFrame( pseqdesc ); - } - - // This game knows how to do three way blending - if ( pseqdesc->numblends == 3 ) - { - float s; - - // Get left anim - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - - // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right - if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) - { - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - // Scale 0-127 blending up to 0-255 - s = m_pCurrentEntity->curstate.blending[0]; - s = ( s * 2.0 ); - } - else - { - - // Skip ahead to middle - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - // Scale 127-255 blending up to 0-255 - s = m_pCurrentEntity->curstate.blending[0]; - s = 2.0 * ( s - 127.0 ); - } - - // Normalize interpolant - s /= 255.0; - - // Go to middle or right - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); - - // Spherically interpolate the bones - StudioSlerpBones( q, pos, q2, pos2, s ); - } - else - { - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - } - - // Are we in the process of transitioning from one sequence to another. - if ( m_fDoInterp && - m_pCurrentEntity->latched.sequencetime && - ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && - ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) - { - // blend from last sequence - static float pos1b[MAXSTUDIOBONES][3]; - static vec4_t q1b[MAXSTUDIOBONES]; - float s; - - // Blending value into last sequence - unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; - - // Point at previous sequenece - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; - - // Know how to do three way blends - if ( pseqdesc->numblends == 3 ) - { - float s; - - // Get left animation - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - - if ( prevseqblending <= 127 ) - { - // Set up bones based on final frame of previous sequence - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = prevseqblending; - s = ( s * 2.0 ); - } - else - { - // Skip to middle blend - panim += m_pStudioHeader->numbones; - - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = prevseqblending; - s = 2.0 * ( s - 127.0 ); - } - - // Normalize - s /= 255.0; - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - // Interpolate bones - StudioSlerpBones( q1b, pos1b, q2, pos2, s ); - } - else - { - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - // clip prevframe - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - } - - // Now blend last frame of previous sequence with current sequence. - s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; - StudioSlerpBones( q, pos, q1b, pos1b, s ); - } - else - { - m_pCurrentEntity->latched.prevframe = f; - } - - // Now convert quaternions and bone positions into matrices - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } -} - -/* -==================== -StudioEstimateGait - -==================== -*/ -void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) -{ - float dt; - vec3_t est_velocity; - - dt = (m_clTime - m_clOldTime); - dt = max( 0.0, dt ); - dt = min( 1.0, dt ); - - if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) - { - m_flGaitMovement = 0; - return; - } - - // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); - if ( m_fGaitEstimation ) - { - VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); - VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); - m_flGaitMovement = Length( est_velocity ); - if (dt <= 0 || m_flGaitMovement / dt < 5) - { - m_flGaitMovement = 0; - est_velocity[0] = 0; - est_velocity[1] = 0; - } - } - else - { - VectorCopy( pplayer->velocity, est_velocity ); - m_flGaitMovement = Length( est_velocity ) * dt; - } - - if (est_velocity[1] == 0 && est_velocity[0] == 0) - { - float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) - flYawDiff -= 360; - if (flYawDiff < -180) - flYawDiff += 360; - - if (dt < 0.25) - flYawDiff *= dt * 4; - else - flYawDiff *= dt; - - m_pPlayerInfo->gaityaw += flYawDiff; - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; - - m_flGaitMovement = 0; - } - else - { - m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - if (m_pPlayerInfo->gaityaw > 180) - m_pPlayerInfo->gaityaw = 180; - if (m_pPlayerInfo->gaityaw < -180) - m_pPlayerInfo->gaityaw = -180; - } - -} - -/* -==================== -StudioProcessGait - -==================== -*/ -void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) -{ - mstudioseqdesc_t *pseqdesc; - float dt; - float flYaw; // view direction relative to movement - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - m_pCurrentEntity->angles[PITCH] = 0; - m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; - - dt = (m_clTime - m_clOldTime); - dt = max( 0.0, dt ); - dt = min( 1.0, dt ); - - StudioEstimateGait( pplayer ); - - // calc side to side turning - flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - - flYaw = fmod( flYaw, 360.0 ); - - if (flYaw < -180) - { - flYaw = flYaw + 360; - } - else if (flYaw > 180) - { - flYaw = flYaw - 360; - } - - float maxyaw = 120.0; - - if (flYaw > maxyaw) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw - 180; - } - else if (flYaw < -maxyaw) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw + 180; - } - - float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; - blend_yaw = min( 255.0, blend_yaw ); - blend_yaw = max( 0.0, blend_yaw ); - - blend_yaw = 255.0 - blend_yaw; - - m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); - m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; - m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; - - m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; - if (m_pCurrentEntity->angles[YAW] < -0) - { - m_pCurrentEntity->angles[YAW] += 360; - } - m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; - - // Calc gait frame - if (pseqdesc->linearmovement[0] > 0) - { - m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; - } - else - { - m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; - } - - // Do modulo - m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; - if (m_pPlayerInfo->gaitframe < 0) - { - m_pPlayerInfo->gaitframe += pseqdesc->numframes; - } -} - -/* -============================== -SavePlayerState - -For local player, in third person, we need to store real render data and then - setup for with fake/client side animation data -============================== -*/ -void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) -{ - client_anim_state_t *st; - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - st = &g_state; - - st->angles = ent->curstate.angles; - st->origin = ent->curstate.origin; - - st->realangles = ent->angles; - - st->sequence = ent->curstate.sequence; - st->gaitsequence = pplayer->gaitsequence; - st->animtime = ent->curstate.animtime; - st->frame = ent->curstate.frame; - st->framerate = ent->curstate.framerate; - memcpy( st->blending, ent->curstate.blending, 2 ); - memcpy( st->controller, ent->curstate.controller, 4 ); - - st->lv = ent->latched; -} - -void GetSequenceInfo( void *pmodel, client_anim_state_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, client_anim_state_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; -} - -float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) -{ - if (flInterval == 0.0) - { - flInterval = (gEngfuncs.GetClientTime() - st->animtime); - if (flInterval <= 0.001) - { - st->animtime = gEngfuncs.GetClientTime(); - return 0.0; - } - } - if (!st->animtime) - flInterval = 0.0; - - st->frame += flInterval * framerate * st->framerate; - st->animtime = gEngfuncs.GetClientTime(); - - if (st->frame < 0.0 || st->frame >= 256.0) - { - if ( st->m_fSequenceLoops ) - st->frame -= (int)(st->frame / 256.0) * 256.0; - else - st->frame = (st->frame < 0.0) ? 0 : 255; - st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents - } - - return flInterval; -} - -/* -============================== -SetupClientAnimation - -Called to set up local player's animation values -============================== -*/ -void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) -{ - static double oldtime; - double curtime, dt; - - client_anim_state_t *st; - float fr, gs; - - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - curtime = gEngfuncs.GetClientTime(); - dt = curtime - oldtime; - dt = min( 1.0, max( 0.0, dt ) ); - - oldtime = curtime; - st = &g_clientstate; - - st->framerate = 1.0; - - int oldseq = st->sequence; - Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); - Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); - st->realangles = st->angles; - - if ( st->sequence != oldseq ) - { - st->frame = 0.0; - st->lv.prevsequence = oldseq; - st->lv.sequencetime = st->animtime; - - memcpy( st->lv.prevseqblending, st->blending, 2 ); - memcpy( st->lv.prevcontroller, st->controller, 4 ); - } - - void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); - - GetSequenceInfo( pmodel, st, &fr, &gs ); - st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); - StudioFrameAdvance( st, fr, dt ); - -// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); - - ent->angles = st->realangles; - ent->curstate.angles = st->angles; - ent->curstate.origin = st->origin; - - ent->curstate.sequence = st->sequence; - pplayer->gaitsequence = st->gaitsequence; - ent->curstate.animtime = st->animtime; - ent->curstate.frame = st->frame; - ent->curstate.framerate = st->framerate; - memcpy( ent->curstate.blending, st->blending, 2 ); - memcpy( ent->curstate.controller, st->controller, 4 ); - - ent->latched = st->lv; -} - -/* -============================== -RestorePlayerState - -Called to restore original player state information -============================== -*/ -void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) -{ - client_anim_state_t *st; - cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); - assert( ent ); - if ( !ent ) - return; - - st = &g_clientstate; - - st->angles = ent->curstate.angles; - st->origin = ent->curstate.origin; - st->realangles = ent->angles; - - st->sequence = ent->curstate.sequence; - st->gaitsequence = pplayer->gaitsequence; - st->animtime = ent->curstate.animtime; - st->frame = ent->curstate.frame; - st->framerate = ent->curstate.framerate; - memcpy( st->blending, ent->curstate.blending, 2 ); - memcpy( st->controller, ent->curstate.controller, 4 ); - - st->lv = ent->latched; - - st = &g_state; - - ent->curstate.angles = st->angles; - ent->curstate.origin = st->origin; - ent->angles = st->realangles; - - ent->curstate.sequence = st->sequence; - pplayer->gaitsequence = st->gaitsequence; - ent->curstate.animtime = st->animtime; - ent->curstate.frame = st->frame; - ent->curstate.framerate = st->framerate; - memcpy( ent->curstate.blending, st->blending, 2 ); - memcpy( ent->curstate.controller, st->controller, 4 ); - - ent->latched = st->lv; -} - -/* -============================== -StudioDrawPlayer - -============================== -*/ -int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - int iret = 0; - - bool isLocalPlayer = false; - - // Set up for client? - if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) - { - isLocalPlayer = true; - } - - if ( isLocalPlayer ) - { - // Store original data - SavePlayerState( pplayer ); - - // Copy in client side animation data - SetupClientAnimation( pplayer ); - } - - // Call real draw function - iret = _StudioDrawPlayer( flags, pplayer ); - - // Restore for client? - if ( isLocalPlayer ) - { - // Restore the original data for the player - RestorePlayerState( pplayer ); - } - - return iret; -} - -/* -==================== -_StudioDrawPlayer - -==================== -*/ -int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - m_nPlayerIndex = pplayer->number - 1; - - if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) - return 0; - - m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); - if (m_pRenderModel == NULL) - return 0; - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - if (pplayer->gaitsequence) - { - vec3_t orig_angles; - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - VectorCopy( m_pCurrentEntity->angles, orig_angles ); - - StudioProcessGait( pplayer ); - - m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; - m_pPlayerInfo = NULL; - - StudioSetUpTransform( 0 ); - VectorCopy( orig_angles, m_pCurrentEntity->angles ); - } - else - { - m_pCurrentEntity->curstate.controller[0] = 127; - m_pCurrentEntity->curstate.controller[1] = 127; - m_pCurrentEntity->curstate.controller[2] = 127; - m_pCurrentEntity->curstate.controller[3] = 127; - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - m_pPlayerInfo->gaitsequence = 0; - - StudioSetUpTransform( 0 ); - } - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - StudioSetupBones( ); - StudioSaveBones( ); - m_pPlayerInfo->renderframe = m_nFrameCount; - - m_pPlayerInfo = NULL; - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - /* - if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) - { - // show highest resolution multiplayer model - m_pCurrentEntity->curstate.body = 255; - } - - if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) - { - m_pCurrentEntity->curstate.body = 1; // force helmet - } - */ - - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - // get remap colors - m_nTopColor = m_pPlayerInfo->topcolor; - if (m_nTopColor < 0) - m_nTopColor = 0; - if (m_nTopColor > 360) - m_nTopColor = 360; - m_nBottomColor = m_pPlayerInfo->bottomcolor; - if (m_nBottomColor < 0) - m_nBottomColor = 0; - if (m_nBottomColor > 360) - m_nBottomColor = 360; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel( ); - m_pPlayerInfo = NULL; - - if (pplayer->weaponmodel) - { - cl_entity_t saveent = *m_pCurrentEntity; - - model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - - StudioMergeBones( pweaponmodel); - - IEngineStudio.StudioSetupLighting (&lighting); - - StudioRenderModel( ); - - StudioCalcAttachments( ); - - *m_pCurrentEntity = saveent; - } - } - - return 1; -} - -/* -==================== -Studio_FxTransform - -==================== -*/ -void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) -{ - switch( ent->curstate.renderfx ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); - } - else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - float offset; - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - offset = gEngfuncs.pfnRandomFloat(-10,10); - transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; - } - break; - case kRenderFxExplode: - { - if ( iRenderStateChanged ) - { - g_flStartScaleTime = m_clTime; - iRenderStateChanged = FALSE; - } - - // Make the Model continue to shrink - float flTimeDelta = m_clTime - g_flStartScaleTime; - if ( flTimeDelta > 0 ) - { - float flScale = 0.001; - // Goes almost all away - if ( flTimeDelta <= 2.0 ) - flScale = 1.0 - (flTimeDelta / 2.0); - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - transform[i][j] *= flScale; - } - } - } - break; - } -} - -//////////////////////////////////// -// Hooks to class implementation -//////////////////////////////////// - -/* -==================== -R_StudioDrawPlayer - -==================== -*/ -int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); -} - -/* -==================== -R_StudioDrawModel - -==================== -*/ -int R_StudioDrawModel( int flags ) -{ - return g_StudioRenderer.StudioDrawModel( flags ); -} - -/* -==================== -R_StudioInit - -==================== -*/ -void R_StudioInit( void ) -{ - g_StudioRenderer.Init(); -} - -// The simple drawing interface we'll pass back to the engine -r_studio_interface_t studio = -{ - STUDIO_INTERFACE_VERSION, - R_StudioDrawModel, - R_StudioDrawPlayer, -}; - -/* -==================== -HUD_GetStudioModelInterface - -Export this function for the engine to use the studio renderer class to render objects. -==================== -*/ - -extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) -{ - if ( version != STUDIO_INTERFACE_VERSION ) - return 0; - - // Point the engine to our callbacks - *ppinterface = &studio; - - // Copy in engine helper functions - memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); - - // Initialize local variables, etc. - R_StudioInit(); - - // Success - return 1; -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Predicted values saved off in hl_weapons.cpp +void Game_GetSequence( int *seq, int *gaitseq ); +void Game_GetOrientation( float *o, float *a ); + +float g_flStartScaleTime; +int iPrevRenderState; +int iRenderStateChanged; + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +typedef struct +{ + vec3_t origin; + vec3_t angles; + + vec3_t realangles; + + float animtime; + float frame; + int sequence; + int gaitsequence; + float framerate; + + int m_fSequenceLoops; + int m_fSequenceFinished; + + byte controller[ 4 ]; + byte blending[ 2 ]; + + latchedvars_t lv; +} client_anim_state_t; + +static client_anim_state_t g_state; +static client_anim_state_t g_clientstate; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ + // If you want to predict animations locally, set this to TRUE + // NOTE: The animation code is somewhat broken, but gives you a sense for how + // to do client side animation of the predicted player in a third person game. + m_bLocal = false; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CGameStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + // Use default bone setup for nonplayers + if ( !m_pCurrentEntity->player ) + { + CStudioModelRenderer::StudioSetupBones(); + return; + } + + // Bound sequence number. + if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) + { + f = m_pPlayerInfo->gaitframe; + } + else + { + f = StudioEstimateFrame( pseqdesc ); + } + + // This game knows how to do three way blending + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left anim + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right + if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) + { + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 0-127 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = ( s * 2.0 ); + } + else + { + + // Skip ahead to middle + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 127-255 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize interpolant + s /= 255.0; + + // Go to middle or right + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + // Spherically interpolate the bones + StudioSlerpBones( q, pos, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + } + + // Are we in the process of transitioning from one sequence to another. + if ( m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + // Blending value into last sequence + unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; + + // Point at previous sequenece + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + + // Know how to do three way blends + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left animation + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + if ( prevseqblending <= 127 ) + { + // Set up bones based on final frame of previous sequence + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = ( s * 2.0 ); + } + else + { + // Skip to middle blend + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize + s /= 255.0; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + // Interpolate bones + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + } + + // Now blend last frame of previous sequence with current sequence. + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + m_pCurrentEntity->latched.prevframe = f; + } + + // Now convert quaternions and bone positions into matrices + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + float flYaw; // view direction relative to movement + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + m_pCurrentEntity->angles[PITCH] = 0; + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + StudioEstimateGait( pplayer ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + + flYaw = fmod( flYaw, 360.0 ); + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + float maxyaw = 120.0; + + if (flYaw > maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; + blend_yaw = min( 255.0, blend_yaw ); + blend_yaw = max( 0.0, blend_yaw ); + + blend_yaw = 255.0 - blend_yaw; + + m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + { + m_pCurrentEntity->angles[YAW] += 360; + } + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // Calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; + } + + // Do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + { + m_pPlayerInfo->gaitframe += pseqdesc->numframes; + } +} + +/* +============================== +SavePlayerState + +For local player, in third person, we need to store real render data and then + setup for with fake/client side animation data +============================== +*/ +void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_state; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; +} + +void GetSequenceInfo( void *pmodel, client_anim_state_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, client_anim_state_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; +} + +float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) +{ + if (flInterval == 0.0) + { + flInterval = (gEngfuncs.GetClientTime() - st->animtime); + if (flInterval <= 0.001) + { + st->animtime = gEngfuncs.GetClientTime(); + return 0.0; + } + } + if (!st->animtime) + flInterval = 0.0; + + st->frame += flInterval * framerate * st->framerate; + st->animtime = gEngfuncs.GetClientTime(); + + if (st->frame < 0.0 || st->frame >= 256.0) + { + if ( st->m_fSequenceLoops ) + st->frame -= (int)(st->frame / 256.0) * 256.0; + else + st->frame = (st->frame < 0.0) ? 0 : 255; + st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents + } + + return flInterval; +} + +/* +============================== +SetupClientAnimation + +Called to set up local player's animation values +============================== +*/ +void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) +{ + static double oldtime; + double curtime, dt; + + client_anim_state_t *st; + float fr, gs; + + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + curtime = gEngfuncs.GetClientTime(); + dt = curtime - oldtime; + dt = min( 1.0, max( 0.0, dt ) ); + + oldtime = curtime; + st = &g_clientstate; + + st->framerate = 1.0; + + int oldseq = st->sequence; + Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); + Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); + st->realangles = st->angles; + + if ( st->sequence != oldseq ) + { + st->frame = 0.0; + st->lv.prevsequence = oldseq; + st->lv.sequencetime = st->animtime; + + memcpy( st->lv.prevseqblending, st->blending, 2 ); + memcpy( st->lv.prevcontroller, st->controller, 4 ); + } + + void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); + + GetSequenceInfo( pmodel, st, &fr, &gs ); + st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); + StudioFrameAdvance( st, fr, dt ); + +// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); + + ent->angles = st->realangles; + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +RestorePlayerState + +Called to restore original player state information +============================== +*/ +void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_clientstate; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; + + st = &g_state; + + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + ent->angles = st->realangles; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +StudioDrawPlayer + +============================== +*/ +int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + int iret = 0; + + bool isLocalPlayer = false; + + // Set up for client? + if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) + { + isLocalPlayer = true; + } + + if ( isLocalPlayer ) + { + // Store original data + SavePlayerState( pplayer ); + + // Copy in client side animation data + SetupClientAnimation( pplayer ); + } + + // Call real draw function + iret = _StudioDrawPlayer( flags, pplayer ); + + // Restore for client? + if ( isLocalPlayer ) + { + // Restore the original data for the player + RestorePlayerState( pplayer ); + } + + return iret; +} + +/* +==================== +_StudioDrawPlayer + +==================== +*/ +int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + /* + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + */ + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + if ( iRenderStateChanged ) + { + g_flStartScaleTime = m_clTime; + iRenderStateChanged = FALSE; + } + + // Make the Model continue to shrink + float flTimeDelta = m_clTime - g_flStartScaleTime; + if ( flTimeDelta > 0 ) + { + float flScale = 0.001; + // Goes almost all away + if ( flTimeDelta <= 2.0 ) + flScale = 1.0 - (flTimeDelta / 2.0); + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + transform[i][j] *= flScale; + } + } + } + break; + } +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ + +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer_Sample.h b/cl_dll/GameStudioModelRenderer_Sample.h index bf5cc73f..c924ba3e 100644 --- a/cl_dll/GameStudioModelRenderer_Sample.h +++ b/cl_dll/GameStudioModelRenderer_Sample.h @@ -1,55 +1,55 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( GAMESTUDIOMODELRENDERER_H ) -#define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CGameStudioModelRenderer - -==================== -*/ -class CGameStudioModelRenderer : public CStudioModelRenderer -{ -public: - CGameStudioModelRenderer( void ); - - // Set up model bone positions - virtual void StudioSetupBones ( void ); - - // Estimate gait frame for player - virtual void StudioEstimateGait ( entity_state_t *pplayer ); - - // Process movement of player - virtual void StudioProcessGait ( entity_state_t *pplayer ); - - // Player drawing code - virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); - virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); - - // Apply special effects to transform matrix - virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); - -private: - // For local player, in third person, we need to store real render data and then - // setup for with fake/client side animation data - void SavePlayerState( entity_state_t *pplayer ); - // Called to set up local player's animation values - void SetupClientAnimation( entity_state_t *pplayer ); - // Called to restore original player state information - void RestorePlayerState( entity_state_t *pplayer ); - -private: - // Private data - bool m_bLocal; -}; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + + // Player drawing code + virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); + virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + +private: + // For local player, in third person, we need to store real render data and then + // setup for with fake/client side animation data + void SavePlayerState( entity_state_t *pplayer ); + // Called to set up local player's animation values + void SetupClientAnimation( entity_state_t *pplayer ); + // Called to restore original player state information + void RestorePlayerState( entity_state_t *pplayer ); + +private: + // Private data + bool m_bLocal; +}; + #endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index 4f99f46e..d4644408 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -1,1703 +1,1703 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// studio_model.cpp -// routines for setting up to draw 3DStudio models - -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "com_model.h" -#include "studio.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "dlight.h" -#include "triangleapi.h" - -#include -#include -#include -#include - -#include "studio_util.h" -#include "r_studioint.h" - -#include "StudioModelRenderer.h" -#include "GameStudioModelRenderer.h" - -// Global engine <-> studio model rendering code interface -engine_studio_api_t IEngineStudio; - -///////////////////// -// Implementation of CStudioModelRenderer.h -#define LEGS_BONES_COUNT 8 - -// enumerate all the bones that used for gait animation -const char *legs_bones[] = -{ - "Bip01" , - "Bip01 Pelvis" , - "Bip01 L Leg" , - "Bip01 L Leg1" , - "Bip01 L Foot" , - "Bip01 R Leg" , - "Bip01 R Leg1" , - "Bip01 R Foot" -}; - -/* -==================== -Init - -==================== -*/ -void CStudioModelRenderer::Init( void ) -{ - // Set up some variables shared with engine - m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); - m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); - m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); - - m_pChromeSprite = IEngineStudio.GetChromeSprite(); - - IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); - - // Get pointers to engine data structures - m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); - m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); - m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); - m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); -} - -/* -==================== -CStudioModelRenderer - -==================== -*/ -CStudioModelRenderer::CStudioModelRenderer( void ) -{ - m_fDoInterp = 1; - m_fGaitEstimation = 1; - m_pCurrentEntity = NULL; - m_pCvarHiModels = NULL; - m_pCvarDeveloper = NULL; - m_pCvarDrawEntities = NULL; - m_pChromeSprite = NULL; - m_pStudioModelCount = NULL; - m_pModelsDrawn = NULL; - m_protationmatrix = NULL; - m_paliastransform = NULL; - m_pbonetransform = NULL; - m_plighttransform = NULL; - m_pStudioHeader = NULL; - m_pBodyPart = NULL; - m_pSubModel = NULL; - m_pPlayerInfo = NULL; - m_pRenderModel = NULL; -} - -/* -==================== -~CStudioModelRenderer - -==================== -*/ -CStudioModelRenderer::~CStudioModelRenderer( void ) -{ -} - -/* -==================== -StudioCalcBoneAdj - -==================== -*/ -void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) -{ - int i, j; - float value; - mstudiobonecontroller_t *pbonecontroller; - - pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); - - for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) - { - i = pbonecontroller[j].index; - if (i <= 3) - { - // check for 360% wrapping - if (pbonecontroller[j].type & STUDIO_RLOOP) - { - if (abs(pcontroller1[i] - pcontroller2[i]) > 128) - { - int a, b; - a = (pcontroller1[j] + 128) % 256; - b = (pcontroller2[j] + 128) % 256; - value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; - } - else - { - value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; - } - } - else - { - value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; - if (value < 0) value = 0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; - } - // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); - } - else - { - value = mouthopen / 64.0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; - // Con_DPrintf("%d %f\n", mouthopen, value ); - } - switch(pbonecontroller[j].type & STUDIO_TYPES) - { - case STUDIO_XR: - case STUDIO_YR: - case STUDIO_ZR: - adj[j] = value * (M_PI / 180.0); - break; - case STUDIO_X: - case STUDIO_Y: - case STUDIO_Z: - adj[j] = value; - break; - } - } -} - - -/* -==================== -StudioCalcBoneQuaterion - -==================== -*/ -void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) -{ - int j, k; - vec4_t q1, q2; - vec3_t angle1, angle2; - mstudioanimvalue_t *panimvalue; - - for (j = 0; j < 3; j++) - { - if (panim->offset[j+3] == 0) - { - angle2[j] = angle1[j] = pbone->value[j+3]; // default; - } - else - { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); - k = frame; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - while (panimvalue->num.total <= k) - { - k -= panimvalue->num.total; - panimvalue += panimvalue->num.valid + 1; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - } - // Bah, missing blend! - if (panimvalue->num.valid > k) - { - angle1[j] = panimvalue[k+1].value; - - if (panimvalue->num.valid > k + 1) - { - angle2[j] = panimvalue[k+2].value; - } - else - { - if (panimvalue->num.total > k + 1) - angle2[j] = angle1[j]; - else - angle2[j] = panimvalue[panimvalue->num.valid+2].value; - } - } - else - { - angle1[j] = panimvalue[panimvalue->num.valid].value; - if (panimvalue->num.total > k + 1) - { - angle2[j] = angle1[j]; - } - else - { - angle2[j] = panimvalue[panimvalue->num.valid + 2].value; - } - } - angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; - angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; - } - - if (pbone->bonecontroller[j+3] != -1) - { - angle1[j] += adj[pbone->bonecontroller[j+3]]; - angle2[j] += adj[pbone->bonecontroller[j+3]]; - } - } - - if (!VectorCompare( angle1, angle2 )) - { - AngleQuaternion( angle1, q1 ); - AngleQuaternion( angle2, q2 ); - QuaternionSlerp( q1, q2, s, q ); - } - else - { - AngleQuaternion( angle1, q ); - } -} - -/* -==================== -StudioCalcBonePosition - -==================== -*/ -void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) -{ - int j, k; - mstudioanimvalue_t *panimvalue; - - for (j = 0; j < 3; j++) - { - pos[j] = pbone->value[j]; // default; - if (panim->offset[j] != 0) - { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); - /* - if (i == 0 && j == 0) - Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); - */ - - k = frame; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - // find span of values that includes the frame we want - while (panimvalue->num.total <= k) - { - k -= panimvalue->num.total; - panimvalue += panimvalue->num.valid + 1; - // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) - k = 0; - } - // if we're inside the span - if (panimvalue->num.valid > k) - { - // and there's more data in the span - if (panimvalue->num.valid > k + 1) - { - pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; - } - else - { - pos[j] += panimvalue[k+1].value * pbone->scale[j]; - } - } - else - { - // are we at the end of the repeating values section and there's another section with data? - if (panimvalue->num.total <= k + 1) - { - pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; - } - else - { - pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; - } - } - } - if ( pbone->bonecontroller[j] != -1 && adj ) - { - pos[j] += adj[pbone->bonecontroller[j]]; - } - } -} - -/* -==================== -StudioSlerpBones - -==================== -*/ -void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) -{ - int i; - vec4_t q3; - float s1; - - if (s < 0) s = 0; - else if (s > 1.0) s = 1.0; - - s1 = 1.0 - s; - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionSlerp( q1[i], q2[i], s, q3 ); - q1[i][0] = q3[0]; - q1[i][1] = q3[1]; - q1[i][2] = q3[2]; - q1[i][3] = q3[3]; - pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; - pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; - pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; - } -} - -/* -==================== -StudioGetAnim - -==================== -*/ -mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) -{ - mstudioseqgroup_t *pseqgroup; - cache_user_t *paSequences; - - pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; - - if (pseqdesc->seqgroup == 0) - { - return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqdesc->animindex); - } - - paSequences = (cache_user_t *)m_pSubModel->submodels; - - if (paSequences == NULL) - { - paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! - m_pSubModel->submodels = (dmodel_t *)paSequences; - } - - if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) - { - gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); - IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); - } - return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); -} - -/* -==================== -StudioPlayerBlend - -==================== -*/ -void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) -{ - // calc up/down pointing - *pBlend = (*pPitch * 3); - if (*pBlend < pseqdesc->blendstart[0]) - { - *pPitch -= pseqdesc->blendstart[0] / 3.0; - *pBlend = 0; - } - else if (*pBlend > pseqdesc->blendend[0]) - { - *pPitch -= pseqdesc->blendend[0] / 3.0; - *pBlend = 255; - } - else - { - if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error - *pBlend = 127; - else - *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); - *pPitch = 0; - } -} - -/* -==================== -StudioSetUpTransform - -==================== -*/ -void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) -{ - int i; - vec3_t angles; - vec3_t modelpos; - -// tweek model origin - //for (i = 0; i < 3; i++) - // modelpos[i] = m_pCurrentEntity->origin[i]; - - VectorCopy( m_pCurrentEntity->origin, modelpos ); - -// TODO: should really be stored with the entity instead of being reconstructed -// TODO: should use a look-up table -// TODO: could cache lazily, stored in the entity - angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; - angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; - angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; - - //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); - //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) - { - float f = 0; - float d; - - // don't do it if the goalstarttime hasn't updated in a while. - - // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit - // was increased to 1.0 s., which is 2x the max lag we are accounting for. - - if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && - ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) - { - f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); - //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); - } - - if (m_fDoInterp) - { - // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set - f = f - 1.0; - } - else - { - f = 0; - } - - for (i = 0; i < 3; i++) - { - modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; - } - - // NOTE: Because multiplayer lag can be relatively large, we don't want to cap - // f at 1.5 anymore. - //if (f > -1.0 && f < 1.5) {} - -// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); - for (i = 0; i < 3; i++) - { - float ang1, ang2; - - ang1 = m_pCurrentEntity->angles[i]; - ang2 = m_pCurrentEntity->latched.prevangles[i]; - - d = ang1 - ang2; - if (d > 180) - { - d -= 360; - } - else if (d < -180) - { - d += 360; - } - - angles[i] += d * f; - } - //Con_DPrintf("%.3f \n", f ); - } - else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) - { - VectorCopy( m_pCurrentEntity->angles, angles ); - } - - //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); - //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); - - angles[PITCH] = -angles[PITCH]; - AngleMatrix (angles, (*m_protationmatrix)); - - if ( !IEngineStudio.IsHardware() ) - { - static float viewmatrix[3][4]; - - VectorCopy (m_vRight, viewmatrix[0]); - VectorCopy (m_vUp, viewmatrix[1]); - VectorInverse (viewmatrix[1]); - VectorCopy (m_vNormal, viewmatrix[2]); - - (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; - (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; - (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; - - ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); - - // do the scaling up of x and y to screen coordinates as part of the transform - // for the unclipped case (it would mess up clipping in the clipped case). - // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y - // correspondingly so the projected x and y come out right - // FIXME: make this work for clipped case too? - if (trivial_accept) - { - for (i=0 ; i<4 ; i++) - { - (*m_paliastransform)[0][i] *= m_fSoftwareXScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[1][i] *= m_fSoftwareYScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); - - } - } - } - - (*m_protationmatrix)[0][3] = modelpos[0]; - (*m_protationmatrix)[1][3] = modelpos[1]; - (*m_protationmatrix)[2][3] = modelpos[2]; -} - - -/* -==================== -StudioEstimateInterpolant - -==================== -*/ -float CStudioModelRenderer::StudioEstimateInterpolant( void ) -{ - float dadt = 1.0; - - if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) - { - dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; - if (dadt > 2.0) - { - dadt = 2.0; - } - } - return dadt; -} - -/* -==================== -StudioCalcRotations - -==================== -*/ -void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) -{ - int i; - int frame; - mstudiobone_t *pbone; - - float s; - float adj[MAXSTUDIOCONTROLLERS]; - float dadt; - - if (f > pseqdesc->numframes - 1) - { - f = 0; // bah, fix this bug with changing sequences too fast - } - // BUG ( somewhere else ) but this code should validate this data. - // This could cause a crash if the frame # is negative, so we'll go ahead - // and clamp it here - else if ( f < -0.01 ) - { - f = -0.01; - } - - frame = (int)f; - - // Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); - - // Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); - - // Con_DPrintf("frame %d %d\n", frame1, frame2 ); - - - dadt = StudioEstimateInterpolant( ); - s = (f - frame); - - // add in programtic controllers - pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); - - for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) - { - StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); - - StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); - // if (0 && i == 0) - // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); - } - - if (pseqdesc->motiontype & STUDIO_X) - { - pos[pseqdesc->motionbone][0] = 0.0; - } - if (pseqdesc->motiontype & STUDIO_Y) - { - pos[pseqdesc->motionbone][1] = 0.0; - } - if (pseqdesc->motiontype & STUDIO_Z) - { - pos[pseqdesc->motionbone][2] = 0.0; - } - - s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; - - if (pseqdesc->motiontype & STUDIO_LX) - { - pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; - } - if (pseqdesc->motiontype & STUDIO_LY) - { - pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; - } - if (pseqdesc->motiontype & STUDIO_LZ) - { - pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; - } -} - -/* -==================== -Studio_FxTransform - -==================== -*/ -void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) -{ - switch( ent->curstate.renderfx ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); - } - else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) - { - float offset; - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - offset = gEngfuncs.pfnRandomFloat(-10,10); - transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; - } - break; - case kRenderFxExplode: - { - float scale; - - scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; - if ( scale > 2 ) // Don't blow up more than 200% - scale = 2; - transform[0][1] *= scale; - transform[1][1] *= scale; - transform[2][1] *= scale; - } - break; - - } -} - -/* -==================== -StudioEstimateFrame - -==================== -*/ -float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) -{ - double dfdt, f; - - if ( m_fDoInterp ) - { - if ( m_clTime < m_pCurrentEntity->curstate.animtime ) - { - dfdt = 0; - } - else - { - dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; - - } - } - else - { - dfdt = 0; - } - - if (pseqdesc->numframes <= 1) - { - f = 0; - } - else - { - f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; - } - - f += dfdt; - - if (pseqdesc->flags & STUDIO_LOOPING) - { - if (pseqdesc->numframes > 1) - { - f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); - } - if (f < 0) - { - f += (pseqdesc->numframes - 1); - } - } - else - { - if (f >= pseqdesc->numframes - 1.001) - { - f = pseqdesc->numframes - 1.001; - } - if (f < 0.0) - { - f = 0.0; - } - } - return f; -} - -/* -==================== -StudioSetupBones - -==================== -*/ -void CStudioModelRenderer::StudioSetupBones ( void ) -{ - int i, j; - double f; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - static vec4_t q[MAXSTUDIOBONES]; - float bonematrix[3][4]; - - static float pos2[MAXSTUDIOBONES][3]; - static vec4_t q2[MAXSTUDIOBONES]; - static float pos3[MAXSTUDIOBONES][3]; - static vec4_t q3[MAXSTUDIOBONES]; - static float pos4[MAXSTUDIOBONES][3]; - static vec4_t q4[MAXSTUDIOBONES]; - - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - f = StudioEstimateFrame( pseqdesc ); - - if (m_pCurrentEntity->latched.prevframe > f) - { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); - } - - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - if (pseqdesc->numblends > 1) - { - float s; - float dadt; - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); - - dadt = StudioEstimateInterpolant(); - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; - - StudioSlerpBones( q, pos, q2, pos2, s ); - - if (pseqdesc->numblends == 4) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); - - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; - StudioSlerpBones( q3, pos3, q4, pos4, s ); - - s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; - StudioSlerpBones( q, pos, q3, pos3, s ); - } - } - - if (m_fDoInterp && - m_pCurrentEntity->latched.sequencetime && - ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && - ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) - { - // blend from last sequence - static float pos1b[MAXSTUDIOBONES][3]; - static vec4_t q1b[MAXSTUDIOBONES]; - float s; - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - // clip prevframe - StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - if (pseqdesc->numblends > 1) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; - StudioSlerpBones( q1b, pos1b, q2, pos2, s ); - - if (pseqdesc->numblends == 4) - { - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - panim += m_pStudioHeader->numbones; - StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - - s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; - StudioSlerpBones( q3, pos3, q4, pos4, s ); - - s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; - StudioSlerpBones( q1b, pos1b, q3, pos3, s ); - } - } - - s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; - StudioSlerpBones( q, pos, q1b, pos1b, s ); - } - else - { - //Con_DPrintf("prevframe = %4.2f\n", f); - m_pCurrentEntity->latched.prevframe = f; - } - - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - // calc gait animation - if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) - { - if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) - { - m_pPlayerInfo->gaitsequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; - - panim = StudioGetAnim( m_pRenderModel, pseqdesc ); - StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - for( j = 0; j < LEGS_BONES_COUNT; j++ ) - { - if( !strcmp( pbones[i].name, legs_bones[j] )) - break; - } - - if( j == LEGS_BONES_COUNT ) - continue; // not used for legs - - memcpy( pos[i], pos2[i], sizeof( pos[i] )); - memcpy( q[i], q2[i], sizeof( q[i] )); - } - } - - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - - // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } -} - - -/* -==================== -StudioSaveBones - -==================== -*/ -void CStudioModelRenderer::StudioSaveBones( void ) -{ - int i; - - mstudiobone_t *pbones; - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - m_nCachedBones = m_pStudioHeader->numbones; - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - strcpy( m_nCachedBoneNames[i], pbones[i].name ); - MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); - MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); - } -} - - -/* -==================== -StudioMergeBones - -==================== -*/ -void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) -{ - int i, j; - double f; - int do_hunt = true; - - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; - - static float pos[MAXSTUDIOBONES][3]; - float bonematrix[3][4]; - static vec4_t q[MAXSTUDIOBONES]; - - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - f = StudioEstimateFrame( pseqdesc ); - - if (m_pCurrentEntity->latched.prevframe > f) - { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); - } - - panim = StudioGetAnim( m_pSubModel, pseqdesc ); - StudioCalcRotations( pos, q, pseqdesc, panim, f ); - - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); - - - for (i = 0; i < m_pStudioHeader->numbones; i++) - { - for (j = 0; j < m_nCachedBones; j++) - { - if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) - { - MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); - MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); - break; - } - } - if (j >= m_nCachedBones) - { - QuaternionMatrix( q[i], bonematrix ); - - bonematrix[0][3] = pos[i][0]; - bonematrix[1][3] = pos[i][1]; - bonematrix[2][3] = pos[i][2]; - - if (pbones[i].parent == -1) - { - if ( IEngineStudio.IsHardware() ) - { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); - - // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); - } - else - { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); - } - - // Apply client-side effects to the transformation matrix - StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); - } - else - { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); - } - } - } -} - -/* -==================== -StudioDrawModel - -==================== -*/ -int CStudioModelRenderer::StudioDrawModel( int flags ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) - { - entity_state_t deadplayer; - - int result; - int save_interp; - - if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) - return 0; - - // get copy of player - deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; - - // clear weapon, movement state - deadplayer.number = m_pCurrentEntity->curstate.renderamt; - deadplayer.weaponmodel = 0; - deadplayer.gaitsequence = 0; - - deadplayer.movetype = MOVETYPE_NONE; - VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); - VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); - - save_interp = m_fDoInterp; - m_fDoInterp = 0; - - // draw as though it were a player - result = StudioDrawPlayer( flags, &deadplayer ); - - m_fDoInterp = save_interp; - return result; - } - - m_pRenderModel = m_pCurrentEntity->model; - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - StudioSetUpTransform( 0 ); - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) - { - StudioMergeBones( m_pRenderModel ); - } - else - { - StudioSetupBones( ); - } - StudioSaveBones( ); - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - // get remap colors - m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; - m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel( ); - } - - return 1; -} - -/* -==================== -StudioEstimateGait - -==================== -*/ -void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) -{ - float dt; - vec3_t est_velocity; - - dt = (m_clTime - m_clOldTime); - if (dt < 0) - dt = 0; - else if (dt > 1.0) - dt = 1; - - if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) - { - m_flGaitMovement = 0; - return; - } - - // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); - if ( m_fGaitEstimation ) - { - VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); - VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); - m_flGaitMovement = Length( est_velocity ); - if (dt <= 0 || m_flGaitMovement / dt < 5) - { - m_flGaitMovement = 0; - est_velocity[0] = 0; - est_velocity[1] = 0; - } - } - else - { - VectorCopy( pplayer->velocity, est_velocity ); - m_flGaitMovement = Length( est_velocity ) * dt; - } - - if (est_velocity[1] == 0 && est_velocity[0] == 0) - { - float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) - flYawDiff -= 360; - if (flYawDiff < -180) - flYawDiff += 360; - - if (dt < 0.25) - flYawDiff *= dt * 4; - else - flYawDiff *= dt; - - m_pPlayerInfo->gaityaw += flYawDiff; - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; - - m_flGaitMovement = 0; - } - else - { - m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - if (m_pPlayerInfo->gaityaw > 180) - m_pPlayerInfo->gaityaw = 180; - if (m_pPlayerInfo->gaityaw < -180) - m_pPlayerInfo->gaityaw = -180; - } - -} - -/* -==================== -StudioProcessGait - -==================== -*/ -void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) -{ - mstudioseqdesc_t *pseqdesc; - float dt; - int iBlend; - float flYaw; // view direction relative to movement - - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) - { - m_pCurrentEntity->curstate.sequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; - - StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); - - m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; - m_pCurrentEntity->curstate.blending[0] = iBlend; - m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; - m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; - - // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); - - dt = (m_clTime - m_clOldTime); - if (dt < 0) - dt = 0; - else if (dt > 1.0) - dt = 1; - - StudioEstimateGait( pplayer ); - - // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); - - // calc side to side turning - flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYaw = flYaw - (int)(flYaw / 360) * 360; - if (flYaw < -180) - flYaw = flYaw + 360; - if (flYaw > 180) - flYaw = flYaw - 360; - - if (flYaw > 120) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw - 180; - } - else if (flYaw < -120) - { - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; - m_flGaitMovement = -m_flGaitMovement; - flYaw = flYaw + 180; - } - - // adjust torso - m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; - if (m_pCurrentEntity->angles[YAW] < -0) - m_pCurrentEntity->angles[YAW] += 360; - m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; - - if (pplayer->gaitsequence >= m_pStudioHeader->numseq) - { - pplayer->gaitsequence = 0; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; - - // calc gait frame - if (pseqdesc->linearmovement[0] > 0) - { - m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; - } - else - { - m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; - } - - // do modulo - m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; - if (m_pPlayerInfo->gaitframe < 0) - m_pPlayerInfo->gaitframe += pseqdesc->numframes; -} - -/* -==================== -StudioDrawPlayer - -==================== -*/ -int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) -{ - alight_t lighting; - vec3_t dir; - - m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); - IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); - IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); - IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - - // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); - - // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); - - // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); - - m_nPlayerIndex = pplayer->number - 1; - - if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) - return 0; - - m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); - if (m_pRenderModel == NULL) - return 0; - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - IEngineStudio.SetRenderModel( m_pRenderModel ); - - if (pplayer->gaitsequence) - { - vec3_t orig_angles; - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - VectorCopy( m_pCurrentEntity->angles, orig_angles ); - - StudioProcessGait( pplayer ); - - m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; - m_pPlayerInfo = NULL; - - StudioSetUpTransform( 0 ); - VectorCopy( orig_angles, m_pCurrentEntity->angles ); - } - else - { - m_pCurrentEntity->curstate.controller[0] = 127; - m_pCurrentEntity->curstate.controller[1] = 127; - m_pCurrentEntity->curstate.controller[2] = 127; - m_pCurrentEntity->curstate.controller[3] = 127; - m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; - m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; - m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; - m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - m_pPlayerInfo->gaitsequence = 0; - - StudioSetUpTransform( 0 ); - } - - if (flags & STUDIO_RENDER) - { - // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) - return 0; - - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie - - if (m_pStudioHeader->numbodyparts == 0) - return 1; - } - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - StudioSetupBones( ); - StudioSaveBones( ); - m_pPlayerInfo->renderframe = m_nFrameCount; - - m_pPlayerInfo = NULL; - - if (flags & STUDIO_EVENTS) - { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); - // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) - { - cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); - } - } - - if (flags & STUDIO_RENDER) - { - if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) - { - // show highest resolution multiplayer model - m_pCurrentEntity->curstate.body = 255; - } - - if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) - { - m_pCurrentEntity->curstate.body = 1; // force helmet - } - - lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); - - IEngineStudio.StudioEntityLight( &lighting ); - - // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); - - m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - - // get remap colors - m_nTopColor = m_pPlayerInfo->topcolor; - m_nBottomColor = m_pPlayerInfo->bottomcolor; - if (m_nTopColor < 0) - m_nTopColor = 0; - if (m_nTopColor > 360) - m_nTopColor = 360; - if (m_nBottomColor < 0) - m_nBottomColor = 0; - if (m_nBottomColor > 360) - m_nBottomColor = 360; - - IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - - StudioRenderModel( ); - m_pPlayerInfo = NULL; - - if (pplayer->weaponmodel) - { - cl_entity_t saveent = *m_pCurrentEntity; - - model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); - - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); - IEngineStudio.StudioSetHeader( m_pStudioHeader ); - - StudioMergeBones( pweaponmodel); - - IEngineStudio.StudioSetupLighting (&lighting); - - StudioRenderModel( ); - - StudioCalcAttachments( ); - - *m_pCurrentEntity = saveent; - } - } - - return 1; -} - -/* -==================== -StudioCalcAttachments - -==================== -*/ -void CStudioModelRenderer::StudioCalcAttachments( void ) -{ - int i; - mstudioattachment_t *pattachment; - - if ( m_pStudioHeader->numattachments > 4 ) - { - gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); - exit( -1 ); - } - - // calculate attachment points - pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); - for (i = 0; i < m_pStudioHeader->numattachments; i++) - { - VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); - } -} - -/* -==================== -StudioRenderModel - -==================== -*/ -void CStudioModelRenderer::StudioRenderModel( void ) -{ - IEngineStudio.SetChromeOrigin(); - IEngineStudio.SetForceFaceFlags( 0 ); - - if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) - { - m_pCurrentEntity->curstate.renderfx = kRenderFxNone; - StudioRenderFinal( ); - - if ( !IEngineStudio.IsHardware() ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - } - - IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); - - gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); - m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; - - StudioRenderFinal( ); - if ( !IEngineStudio.IsHardware() ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - } - else - { - StudioRenderFinal( ); - } -} - -/* -==================== -StudioRenderFinal_Software - -==================== -*/ -void CStudioModelRenderer::StudioRenderFinal_Software( void ) -{ - int i; - - // Note, rendermode set here has effect in SW - IEngineStudio.SetupRenderer( 0 ); - - if (m_pCvarDrawEntities->value == 2) - { - IEngineStudio.StudioDrawBones( ); - } - else if (m_pCvarDrawEntities->value == 3) - { - IEngineStudio.StudioDrawHulls( ); - } - else - { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) - { - IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - IEngineStudio.StudioDrawPoints( ); - } - } - - if (m_pCvarDrawEntities->value == 4) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - - if (m_pCvarDrawEntities->value == 5) - { - IEngineStudio.StudioDrawAbsBBox( ); - } - - IEngineStudio.RestoreRenderer(); -} - -/* -==================== -StudioRenderFinal_Hardware - -==================== -*/ -void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) -{ - int i; - int rendermode; - - rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; - IEngineStudio.SetupRenderer( rendermode ); - - if (m_pCvarDrawEntities->value == 2) - { - IEngineStudio.StudioDrawBones(); - } - else if (m_pCvarDrawEntities->value == 3) - { - IEngineStudio.StudioDrawHulls(); - } - else - { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) - { - IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - - if (m_fDoInterp) - { - // interpolation messes up bounding boxes. - m_pCurrentEntity->trivial_accept = 0; - } - - IEngineStudio.GL_SetRenderMode( rendermode ); - IEngineStudio.StudioDrawPoints(); - IEngineStudio.GL_StudioDrawShadow(); - } - } - - if ( m_pCvarDrawEntities->value == 4 ) - { - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - } - - if (m_pCvarDrawEntities->value == 5) - { - IEngineStudio.StudioDrawAbsBBox( ); - } - - IEngineStudio.RestoreRenderer(); -} - -/* -==================== -StudioRenderFinal - -==================== -*/ -void CStudioModelRenderer::StudioRenderFinal(void) -{ - if ( IEngineStudio.IsHardware() ) - { - StudioRenderFinal_Hardware(); - } - else - { - StudioRenderFinal_Software(); - } -} - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// studio_model.cpp +// routines for setting up to draw 3DStudio models + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Global engine <-> studio model rendering code interface +engine_studio_api_t IEngineStudio; + +///////////////////// +// Implementation of CStudioModelRenderer.h +#define LEGS_BONES_COUNT 8 + +// enumerate all the bones that used for gait animation +const char *legs_bones[] = +{ + "Bip01" , + "Bip01 Pelvis" , + "Bip01 L Leg" , + "Bip01 L Leg1" , + "Bip01 L Foot" , + "Bip01 R Leg" , + "Bip01 R Leg1" , + "Bip01 R Foot" +}; + +/* +==================== +Init + +==================== +*/ +void CStudioModelRenderer::Init( void ) +{ + // Set up some variables shared with engine + m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); + m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); + m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); + + m_pChromeSprite = IEngineStudio.GetChromeSprite(); + + IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); + + // Get pointers to engine data structures + m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); + m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); + m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); + m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); +} + +/* +==================== +CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::CStudioModelRenderer( void ) +{ + m_fDoInterp = 1; + m_fGaitEstimation = 1; + m_pCurrentEntity = NULL; + m_pCvarHiModels = NULL; + m_pCvarDeveloper = NULL; + m_pCvarDrawEntities = NULL; + m_pChromeSprite = NULL; + m_pStudioModelCount = NULL; + m_pModelsDrawn = NULL; + m_protationmatrix = NULL; + m_paliastransform = NULL; + m_pbonetransform = NULL; + m_plighttransform = NULL; + m_pStudioHeader = NULL; + m_pBodyPart = NULL; + m_pSubModel = NULL; + m_pPlayerInfo = NULL; + m_pRenderModel = NULL; +} + +/* +==================== +~CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::~CStudioModelRenderer( void ) +{ +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) +{ + int i, j; + float value; + mstudiobonecontroller_t *pbonecontroller; + + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + if (i <= 3) + { + // check for 360% wrapping + if (pbonecontroller[j].type & STUDIO_RLOOP) + { + if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + int a, b; + a = (pcontroller1[j] + 128) % 256; + b = (pcontroller2[j] + 128) % 256; + value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + else + { + value = mouthopen / 64.0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Con_DPrintf("%d %f\n", mouthopen, value ); + } + switch(pbonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = value * (M_PI / 180.0); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + + +/* +==================== +StudioCalcBoneQuaterion + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j+3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j+3]; // default; + } + else + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k+1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k+2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid+2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + } + + if (pbone->bonecontroller[j+3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j+3]]; + angle2[j] += adj[pbone->bonecontroller[j+3]]; + } + } + + if (!VectorCompare( angle1, angle2 )) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q ); + } + else + { + AngleQuaternion( angle1, q ); + } +} + +/* +==================== +StudioCalcBonePosition + +==================== +*/ +void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) +{ + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + /* + if (i == 0 && j == 0) + Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + */ + + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if ( pbone->bonecontroller[j] != -1 && adj ) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* +==================== +StudioSlerpBones + +==================== +*/ +void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) +{ + int i; + vec4_t q3; + float s1; + + if (s < 0) s = 0; + else if (s > 1.0) s = 1.0; + + s1 = 1.0 - s; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* +==================== +StudioGetAnim + +==================== +*/ +mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) +{ + mstudioseqgroup_t *pseqgroup; + cache_user_t *paSequences; + + pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) + { + return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqdesc->animindex); + } + + paSequences = (cache_user_t *)m_pSubModel->submodels; + + if (paSequences == NULL) + { + paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! + m_pSubModel->submodels = (dmodel_t *)paSequences; + } + + if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) + { + gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); + IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); + } + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3); + if (*pBlend < pseqdesc->blendstart[0]) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0; + *pBlend = 0; + } + else if (*pBlend > pseqdesc->blendend[0]) + { + *pPitch -= pseqdesc->blendend[0] / 3.0; + *pBlend = 255; + } + else + { + if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error + *pBlend = 127; + else + *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0; + } +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) +{ + int i; + vec3_t angles; + vec3_t modelpos; + +// tweek model origin + //for (i = 0; i < 3; i++) + // modelpos[i] = m_pCurrentEntity->origin[i]; + + VectorCopy( m_pCurrentEntity->origin, modelpos ); + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; + angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; + angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; + + //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); + //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) + { + float f = 0; + float d; + + // don't do it if the goalstarttime hasn't updated in a while. + + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + + if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && + ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) + { + f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); + //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); + } + + if (m_fDoInterp) + { + // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set + f = f - 1.0; + } + else + { + f = 0; + } + + for (i = 0; i < 3; i++) + { + modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; + } + + // NOTE: Because multiplayer lag can be relatively large, we don't want to cap + // f at 1.5 anymore. + //if (f > -1.0 && f < 1.5) {} + +// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); + for (i = 0; i < 3; i++) + { + float ang1, ang2; + + ang1 = m_pCurrentEntity->angles[i]; + ang2 = m_pCurrentEntity->latched.prevangles[i]; + + d = ang1 - ang2; + if (d > 180) + { + d -= 360; + } + else if (d < -180) + { + d += 360; + } + + angles[i] += d * f; + } + //Con_DPrintf("%.3f \n", f ); + } + else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) + { + VectorCopy( m_pCurrentEntity->angles, angles ); + } + + //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); + //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); + + angles[PITCH] = -angles[PITCH]; + AngleMatrix (angles, (*m_protationmatrix)); + + if ( !IEngineStudio.IsHardware() ) + { + static float viewmatrix[3][4]; + + VectorCopy (m_vRight, viewmatrix[0]); + VectorCopy (m_vUp, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (m_vNormal, viewmatrix[2]); + + (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; + (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; + (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; + + ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); + + // do the scaling up of x and y to screen coordinates as part of the transform + // for the unclipped case (it would mess up clipping in the clipped case). + // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y + // correspondingly so the projected x and y come out right + // FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + (*m_paliastransform)[0][i] *= m_fSoftwareXScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[1][i] *= m_fSoftwareYScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); + + } + } + } + + (*m_protationmatrix)[0][3] = modelpos[0]; + (*m_protationmatrix)[1][3] = modelpos[1]; + (*m_protationmatrix)[2][3] = modelpos[2]; +} + + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float CStudioModelRenderer::StudioEstimateInterpolant( void ) +{ + float dadt = 1.0; + + if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) + { + dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; + if (dadt > 2.0) + { + dadt = 2.0; + } + } + return dadt; +} + +/* +==================== +StudioCalcRotations + +==================== +*/ +void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +{ + int i; + int frame; + mstudiobone_t *pbone; + + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; + + if (f > pseqdesc->numframes - 1) + { + f = 0; // bah, fix this bug with changing sequences too fast + } + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + else if ( f < -0.01 ) + { + f = -0.01; + } + + frame = (int)f; + + // Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + + // Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); + + // Con_DPrintf("frame %d %d\n", frame1, frame2 ); + + + dadt = StudioEstimateInterpolant( ); + s = (f - frame); + + // add in programtic controllers + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); + + for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + { + StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); + + StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + // if (0 && i == 0) + // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); + } + + if (pseqdesc->motiontype & STUDIO_X) + { + pos[pseqdesc->motionbone][0] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Y) + { + pos[pseqdesc->motionbone][1] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Z) + { + pos[pseqdesc->motionbone][2] = 0.0; + } + + s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; + + if (pseqdesc->motiontype & STUDIO_LX) + { + pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; + } + if (pseqdesc->motiontype & STUDIO_LY) + { + pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; + } + if (pseqdesc->motiontype & STUDIO_LZ) + { + pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; + } +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; + if ( scale > 2 ) // Don't blow up more than 200% + scale = 2; + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; + } + break; + + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if ( m_fDoInterp ) + { + if ( m_clTime < m_pCurrentEntity->curstate.animtime ) + { + dfdt = 0; + } + else + { + dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; + + } + } + else + { + dfdt = 0; + } + + if (pseqdesc->numframes <= 1) + { + f = 0; + } + else + { + f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; + } + + f += dfdt; + + if (pseqdesc->flags & STUDIO_LOOPING) + { + if (pseqdesc->numframes > 1) + { + f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + } + if (f < 0) + { + f += (pseqdesc->numframes - 1); + } + } + else + { + if (f >= pseqdesc->numframes - 1.001) + { + f = pseqdesc->numframes - 1.001; + } + if (f < 0.0) + { + f = 0.0; + } + } + return f; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CStudioModelRenderer::StudioSetupBones ( void ) +{ + int i, j; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + if (pseqdesc->numblends > 1) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + dadt = StudioEstimateInterpolant(); + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + + StudioSlerpBones( q, pos, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); + + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q, pos, q3, pos3, s ); + } + } + + if (m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + if (pseqdesc->numblends > 1) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; + StudioSlerpBones( q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + //Con_DPrintf("prevframe = %4.2f\n", f); + m_pCurrentEntity->latched.prevframe = f; + } + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) + { + if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) + { + m_pPlayerInfo->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for( j = 0; j < LEGS_BONES_COUNT; j++ ) + { + if( !strcmp( pbones[i].name, legs_bones[j] )) + break; + } + + if( j == LEGS_BONES_COUNT ) + continue; // not used for legs + + memcpy( pos[i], pos2[i], sizeof( pos[i] )); + memcpy( q[i], q2[i], sizeof( q[i] )); + } + } + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + + +/* +==================== +StudioSaveBones + +==================== +*/ +void CStudioModelRenderer::StudioSaveBones( void ) +{ + int i; + + mstudiobone_t *pbones; + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + m_nCachedBones = m_pStudioHeader->numbones; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + strcpy( m_nCachedBoneNames[i], pbones[i].name ); + MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); + MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); + } +} + + +/* +==================== +StudioMergeBones + +==================== +*/ +void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) +{ + int i, j; + double f; + int do_hunt = true; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + float bonematrix[3][4]; + static vec4_t q[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pSubModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for (j = 0; j < m_nCachedBones; j++) + { + if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) + { + MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); + MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); + break; + } + } + if (j >= m_nCachedBones) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } + } +} + +/* +==================== +StudioDrawModel + +==================== +*/ +int CStudioModelRenderer::StudioDrawModel( int flags ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) + { + entity_state_t deadplayer; + + int result; + int save_interp; + + if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) + return 0; + + // get copy of player + deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; + + // clear weapon, movement state + deadplayer.number = m_pCurrentEntity->curstate.renderamt; + deadplayer.weaponmodel = 0; + deadplayer.gaitsequence = 0; + + deadplayer.movetype = MOVETYPE_NONE; + VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); + VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); + + save_interp = m_fDoInterp; + m_fDoInterp = 0; + + // draw as though it were a player + result = StudioDrawPlayer( flags, &deadplayer ); + + m_fDoInterp = save_interp; + return result; + } + + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + StudioSetUpTransform( 0 ); + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + { + StudioMergeBones( m_pRenderModel ); + } + else + { + StudioSetupBones( ); + } + StudioSaveBones( ); + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + // get remap colors + m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + } + + return 1; +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + int iBlend; + float flYaw; // view direction relative to movement + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); + + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + m_pCurrentEntity->curstate.blending[0] = iBlend; + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + StudioEstimateGait( pplayer ); + + // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if (flYaw < -180) + flYaw = flYaw + 360; + if (flYaw > 180) + flYaw = flYaw - 360; + + if (flYaw > 120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + // adjust torso + m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + m_pCurrentEntity->angles[YAW] += 360; + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + if (pplayer->gaitsequence >= m_pStudioHeader->numseq) + { + pplayer->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; + } + + // do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + m_pPlayerInfo->gaitframe += pseqdesc->numframes; +} + +/* +==================== +StudioDrawPlayer + +==================== +*/ +int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + + // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); + + // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +StudioCalcAttachments + +==================== +*/ +void CStudioModelRenderer::StudioCalcAttachments( void ) +{ + int i; + mstudioattachment_t *pattachment; + + if ( m_pStudioHeader->numattachments > 4 ) + { + gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); + exit( -1 ); + } + + // calculate attachment points + pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + for (i = 0; i < m_pStudioHeader->numattachments; i++) + { + VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); + } +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void CStudioModelRenderer::StudioRenderModel( void ) +{ + IEngineStudio.SetChromeOrigin(); + IEngineStudio.SetForceFaceFlags( 0 ); + + if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) + { + m_pCurrentEntity->curstate.renderfx = kRenderFxNone; + StudioRenderFinal( ); + + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + } + + IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); + + gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); + m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; + + StudioRenderFinal( ); + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + } + else + { + StudioRenderFinal( ); + } +} + +/* +==================== +StudioRenderFinal_Software + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Software( void ) +{ + int i; + + // Note, rendermode set here has effect in SW + IEngineStudio.SetupRenderer( 0 ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones( ); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls( ); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + IEngineStudio.StudioDrawPoints( ); + } + } + + if (m_pCvarDrawEntities->value == 4) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal_Hardware + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) +{ + int i; + int rendermode; + + rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; + IEngineStudio.SetupRenderer( rendermode ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones(); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls(); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + + if (m_fDoInterp) + { + // interpolation messes up bounding boxes. + m_pCurrentEntity->trivial_accept = 0; + } + + IEngineStudio.GL_SetRenderMode( rendermode ); + IEngineStudio.StudioDrawPoints(); + IEngineStudio.GL_StudioDrawShadow(); + } + } + + if ( m_pCvarDrawEntities->value == 4 ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal(void) +{ + if ( IEngineStudio.IsHardware() ) + { + StudioRenderFinal_Hardware(); + } + else + { + StudioRenderFinal_Software(); + } +} + diff --git a/cl_dll/StudioModelRenderer.h b/cl_dll/StudioModelRenderer.h index 51eaaa60..8f1427ff 100644 --- a/cl_dll/StudioModelRenderer.h +++ b/cl_dll/StudioModelRenderer.h @@ -1,189 +1,189 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined ( STUDIOMODELRENDERER_H ) -#define STUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif - -/* -==================== -CStudioModelRenderer - -==================== -*/ -class CStudioModelRenderer -{ -public: - // Construction/Destruction - CStudioModelRenderer( void ); - virtual ~CStudioModelRenderer( void ); - - // Initialization - virtual void Init( void ); - -public: - // Public Interfaces - virtual int StudioDrawModel ( int flags ); - virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); - -public: - // Local interfaces - // - - // Look up animation data for sequence - virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); - - // Interpolate model position and angles and set up matrices - virtual void StudioSetUpTransform (int trivial_accept); - - // Set up model bone positions - virtual void StudioSetupBones ( void ); - - // Find final attachment points - virtual void StudioCalcAttachments ( void ); - - // Save bone matrices and names - virtual void StudioSaveBones( void ); - - // Merge cached bones with current bones for model - virtual void StudioMergeBones ( model_t *m_pSubModel ); - - // Determine interpolation fraction - virtual float StudioEstimateInterpolant( void ); - - // Determine current frame for rendering - virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); - - // Apply special effects to transform matrix - virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); - - // Spherical interpolation of bones - virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); - - // Compute bone adjustments ( bone controllers ) - virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); - - // Get bone quaternions - virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); - - // Get bone positions - virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); - - // Compute rotations - virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); - - // Send bones and verts to renderer - virtual void StudioRenderModel ( void ); - - // Finalize rendering - virtual void StudioRenderFinal (void); - - // GL&D3D vs. Software renderer finishing functions - virtual void StudioRenderFinal_Software ( void ); - virtual void StudioRenderFinal_Hardware ( void ); - - // Player specific data - // Determine pitch and blending amounts for players - virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); - - // Estimate gait frame for player - virtual void StudioEstimateGait ( entity_state_t *pplayer ); - - // Process movement of player - virtual void StudioProcessGait ( entity_state_t *pplayer ); - -public: - - // Client clock - double m_clTime; - // Old Client clock - double m_clOldTime; - - // Do interpolation? - int m_fDoInterp; - // Do gait estimation? - int m_fGaitEstimation; - - // Current render frame # - int m_nFrameCount; - - // Cvars that studio model code needs to reference - // - // Use high quality models? - cvar_t *m_pCvarHiModels; - // Developer debug output desired? - cvar_t *m_pCvarDeveloper; - // Draw entities bone hit boxes, etc? - cvar_t *m_pCvarDrawEntities; - - // The entity which we are currently rendering. - cl_entity_t *m_pCurrentEntity; - - // The model for the entity being rendered - model_t *m_pRenderModel; - - // Player info for current player, if drawing a player - player_info_t *m_pPlayerInfo; - - // The index of the player being drawn - int m_nPlayerIndex; - - // The player's gait movement - float m_flGaitMovement; - - // Pointer to header block for studio model data - studiohdr_t *m_pStudioHeader; - - // Pointers to current body part and submodel - mstudiobodyparts_t *m_pBodyPart; - mstudiomodel_t *m_pSubModel; - - // Palette substition for top and bottom of model - int m_nTopColor; - int m_nBottomColor; - - // - // Sprite model used for drawing studio model chrome - model_t *m_pChromeSprite; - - // Caching - // Number of bones in bone cache - int m_nCachedBones; - // Names of cached bones - char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; - // Cached bone & light transformation matrices - float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; - - // Software renderer scale factors - float m_fSoftwareXScale, m_fSoftwareYScale; - - // Current view vectors and render origin - float m_vUp[ 3 ]; - float m_vRight[ 3 ]; - float m_vNormal[ 3 ]; - - float m_vRenderOrigin[ 3 ]; - - // Model render counters ( from engine ) - int *m_pStudioModelCount; - int *m_pModelsDrawn; - - // Matrices - // Model to world transformation - float (*m_protationmatrix)[ 3 ][ 4 ]; - // Model to view transformation - float (*m_paliastransform)[ 3 ][ 4 ]; - - // Concatenated bone and light transforms - float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; -}; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( STUDIOMODELRENDERER_H ) +#define STUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CStudioModelRenderer + +==================== +*/ +class CStudioModelRenderer +{ +public: + // Construction/Destruction + CStudioModelRenderer( void ); + virtual ~CStudioModelRenderer( void ); + + // Initialization + virtual void Init( void ); + +public: + // Public Interfaces + virtual int StudioDrawModel ( int flags ); + virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); + +public: + // Local interfaces + // + + // Look up animation data for sequence + virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); + + // Interpolate model position and angles and set up matrices + virtual void StudioSetUpTransform (int trivial_accept); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Find final attachment points + virtual void StudioCalcAttachments ( void ); + + // Save bone matrices and names + virtual void StudioSaveBones( void ); + + // Merge cached bones with current bones for model + virtual void StudioMergeBones ( model_t *m_pSubModel ); + + // Determine interpolation fraction + virtual float StudioEstimateInterpolant( void ); + + // Determine current frame for rendering + virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + + // Spherical interpolation of bones + virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); + + // Compute bone adjustments ( bone controllers ) + virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); + + // Get bone quaternions + virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); + + // Get bone positions + virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); + + // Compute rotations + virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); + + // Send bones and verts to renderer + virtual void StudioRenderModel ( void ); + + // Finalize rendering + virtual void StudioRenderFinal (void); + + // GL&D3D vs. Software renderer finishing functions + virtual void StudioRenderFinal_Software ( void ); + virtual void StudioRenderFinal_Hardware ( void ); + + // Player specific data + // Determine pitch and blending amounts for players + virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + +public: + + // Client clock + double m_clTime; + // Old Client clock + double m_clOldTime; + + // Do interpolation? + int m_fDoInterp; + // Do gait estimation? + int m_fGaitEstimation; + + // Current render frame # + int m_nFrameCount; + + // Cvars that studio model code needs to reference + // + // Use high quality models? + cvar_t *m_pCvarHiModels; + // Developer debug output desired? + cvar_t *m_pCvarDeveloper; + // Draw entities bone hit boxes, etc? + cvar_t *m_pCvarDrawEntities; + + // The entity which we are currently rendering. + cl_entity_t *m_pCurrentEntity; + + // The model for the entity being rendered + model_t *m_pRenderModel; + + // Player info for current player, if drawing a player + player_info_t *m_pPlayerInfo; + + // The index of the player being drawn + int m_nPlayerIndex; + + // The player's gait movement + float m_flGaitMovement; + + // Pointer to header block for studio model data + studiohdr_t *m_pStudioHeader; + + // Pointers to current body part and submodel + mstudiobodyparts_t *m_pBodyPart; + mstudiomodel_t *m_pSubModel; + + // Palette substition for top and bottom of model + int m_nTopColor; + int m_nBottomColor; + + // + // Sprite model used for drawing studio model chrome + model_t *m_pChromeSprite; + + // Caching + // Number of bones in bone cache + int m_nCachedBones; + // Names of cached bones + char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; + // Cached bone & light transformation matrices + float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + + // Software renderer scale factors + float m_fSoftwareXScale, m_fSoftwareYScale; + + // Current view vectors and render origin + float m_vUp[ 3 ]; + float m_vRight[ 3 ]; + float m_vNormal[ 3 ]; + + float m_vRenderOrigin[ 3 ]; + + // Model render counters ( from engine ) + int *m_pStudioModelCount; + int *m_pModelsDrawn; + + // Matrices + // Model to world transformation + float (*m_protationmatrix)[ 3 ][ 4 ]; + // Model to view transformation + float (*m_paliastransform)[ 3 ][ 4 ]; + + // Concatenated bone and light transforms + float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; +}; + #endif // STUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 147709bc..d748176e 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -1,1203 +1,1203 @@ -/*** -* -* 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. -* -****/ -// -// Ammo.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" -#include "pm_shared.h" - -#include -#include - -#include "ammohistory.h" - -WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise - // this points to the active weapon menu item -WEAPON *gpLastSel; // Last weapon menu selection - -client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); - -WeaponsResource gWR; - -int g_weaponselect = 0; - -void WeaponsResource :: LoadAllWeaponSprites( void ) -{ - for (int i = 0; i < MAX_WEAPONS; i++) - { - if ( rgWeapons[i].iId ) - LoadWeaponSprites( &rgWeapons[i] ); - } -} - -int WeaponsResource :: CountAmmo( int iId ) -{ - if ( iId < 0 ) - return 0; - - return riAmmo[iId]; -} - -int WeaponsResource :: HasAmmo( WEAPON *p ) -{ - if ( !p ) - return FALSE; - - // weapons with no max ammo can always be selected - if ( p->iMax1 == -1 ) - return TRUE; - - return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) - || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); -} - - -void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) -{ - int i, iRes; - - if (ScreenWidth < 640) - iRes = 320; - else - iRes = 640; - - char sz[128]; - - if ( !pWeapon ) - return; - - memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); - memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); - pWeapon->hInactive = 0; - pWeapon->hActive = 0; - pWeapon->hAmmo = 0; - pWeapon->hAmmo2 = 0; - - sprintf(sz, "sprites/%s.txt", pWeapon->szName); - client_sprite_t *pList = SPR_GetList(sz, &i); - - if (!pList) - return; - - client_sprite_t *p; - - p = GetSpriteList( pList, "crosshair", iRes, i ); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hCrosshair = SPR_Load(sz); - pWeapon->rcCrosshair = p->rc; - } - else - pWeapon->hCrosshair = 0; - - p = GetSpriteList(pList, "autoaim", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAutoaim = SPR_Load(sz); - pWeapon->rcAutoaim = p->rc; - } - else - pWeapon->hAutoaim = 0; - - p = GetSpriteList( pList, "zoom", iRes, i ); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedCrosshair = SPR_Load(sz); - pWeapon->rcZoomedCrosshair = p->rc; - } - else - { - pWeapon->hZoomedCrosshair = pWeapon->hCrosshair; //default to non-zoomed crosshair - pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; - } - - p = GetSpriteList(pList, "zoom_autoaim", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedAutoaim = SPR_Load(sz); - pWeapon->rcZoomedAutoaim = p->rc; - } - else - { - pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair; //default to zoomed crosshair - pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; - } - - p = GetSpriteList(pList, "weapon", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hInactive = SPR_Load(sz); - pWeapon->rcInactive = p->rc; - - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else - pWeapon->hInactive = 0; - - p = GetSpriteList(pList, "weapon_s", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hActive = SPR_Load(sz); - pWeapon->rcActive = p->rc; - } - else - pWeapon->hActive = 0; - - p = GetSpriteList(pList, "ammo", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo = SPR_Load(sz); - pWeapon->rcAmmo = p->rc; - - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else - pWeapon->hAmmo = 0; - - p = GetSpriteList(pList, "ammo2", iRes, i); - if (p) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo2 = SPR_Load(sz); - pWeapon->rcAmmo2 = p->rc; - - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else - pWeapon->hAmmo2 = 0; - -} - -// Returns the first weapon for a given slot. -WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) -{ - WEAPON *pret = NULL; - - for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) - { - if ( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] ) ) - { - pret = rgSlots[iSlot][i]; - break; - } - } - - return pret; -} - - -WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) -{ - if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) - return NULL; - - WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; - - if ( !p || !gWR.HasAmmo(p) ) - return GetNextActivePos( iSlot, iSlotPos + 1 ); - - return p; -} - - -int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height - -HSPRITE ghsprBuckets; // Sprite for top row of weapons menu - -DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip -DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type -DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count -DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record -DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record -DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily -DECLARE_MESSAGE(m_Ammo, ItemPickup); - -DECLARE_COMMAND(m_Ammo, Slot1); -DECLARE_COMMAND(m_Ammo, Slot2); -DECLARE_COMMAND(m_Ammo, Slot3); -DECLARE_COMMAND(m_Ammo, Slot4); -DECLARE_COMMAND(m_Ammo, Slot5); -DECLARE_COMMAND(m_Ammo, Slot6); -DECLARE_COMMAND(m_Ammo, Slot7); -DECLARE_COMMAND(m_Ammo, Slot8); -DECLARE_COMMAND(m_Ammo, Slot9); -DECLARE_COMMAND(m_Ammo, Slot10); -DECLARE_COMMAND(m_Ammo, Close); -DECLARE_COMMAND(m_Ammo, NextWeapon); -DECLARE_COMMAND(m_Ammo, PrevWeapon); - -// width of ammo fonts -#define AMMO_SMALL_WIDTH 10 -#define AMMO_LARGE_WIDTH 20 - -#define HISTORY_DRAW_TIME "5" - -int CHudAmmo::Init(void) -{ - gHUD.AddHudElem(this); - - HOOK_MESSAGE(CurWeapon); - HOOK_MESSAGE(WeaponList); - HOOK_MESSAGE(AmmoPickup); - HOOK_MESSAGE(WeapPickup); - HOOK_MESSAGE(ItemPickup); - HOOK_MESSAGE(HideWeapon); - HOOK_MESSAGE(AmmoX); - - HOOK_COMMAND("slot1", Slot1); - HOOK_COMMAND("slot2", Slot2); - HOOK_COMMAND("slot3", Slot3); - HOOK_COMMAND("slot4", Slot4); - HOOK_COMMAND("slot5", Slot5); - HOOK_COMMAND("slot6", Slot6); - HOOK_COMMAND("slot7", Slot7); - HOOK_COMMAND("slot8", Slot8); - HOOK_COMMAND("slot9", Slot9); - HOOK_COMMAND("slot10", Slot10); - HOOK_COMMAND("cancelselect", Close); - HOOK_COMMAND("invnext", NextWeapon); - HOOK_COMMAND("invprev", PrevWeapon); - - Reset(); - - CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); - CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress - - m_iFlags |= HUD_ACTIVE; //!!! - - gWR.Init(); - gHR.Init(); - - return 1; -}; - -void CHudAmmo::Reset(void) -{ - m_fFade = 0; - m_iFlags |= HUD_ACTIVE; //!!! - - gpActiveSel = NULL; - gHUD.m_iHideHUDDisplay = 0; - - gWR.Reset(); - gHR.Reset(); - - // VidInit(); - -} - -int CHudAmmo::VidInit(void) -{ - // Load sprites for buckets (top row of weapon menu) - m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); - m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); - - ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); - giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; - giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; - - gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); - - // If we've already loaded weapons, let's get new sprites - gWR.LoadAllWeaponSprites(); - - if (ScreenWidth >= 640) - { - giABWidth = 20; - giABHeight = 4; - } - else - { - giABWidth = 10; - giABHeight = 2; - } - - return 1; -} - -// -// Think: -// Used for selection of weapon menu item. -// -void CHudAmmo::Think(void) -{ - if ( gHUD.m_fPlayerDead ) - return; - - if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) - { - gWR.iOldWeaponBits = gHUD.m_iWeaponBits; - - for (int i = MAX_WEAPONS-1; i > 0; i-- ) - { - WEAPON *p = gWR.GetWeapon(i); - - if ( p ) - { - if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) - gWR.PickupWeapon( p ); - else - gWR.DropWeapon( p ); - } - } - } - - if (!gpActiveSel) - return; - - // has the player selected one? - if (gHUD.m_iKeyBits & IN_ATTACK) - { - if (gpActiveSel != (WEAPON *)1) - { - ServerCmd(gpActiveSel->szName); - g_weaponselect = gpActiveSel->iId; - } - - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - gHUD.m_iKeyBits &= ~IN_ATTACK; - - PlaySound("common/wpn_select.wav", 1); - } - -} - -// -// Helper function to return a Ammo pointer from id -// - -HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iAmmoType == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo; - return &rgWeapons[i].hAmmo; - } - else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo2; - return &rgWeapons[i].hAmmo2; - } - } - - return NULL; -} - - -// Menu Selection Code - -void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) -{ - if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) - { // menu is overriding slot use commands - gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers - return; - } - - if ( iSlot > MAX_WEAPON_SLOTS ) - return; - - if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) - return; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return; - - if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) - return; - - WEAPON *p = NULL; - bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; - - if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) - { - PlaySound( "common/wpn_hudon.wav", 1 ); - p = GetFirstPos( iSlot ); - - if ( p && fastSwitch ) // check for fast weapon switch mode - { - // if fast weapon switch is on, then weapons can be selected in a single keypress - // but only if there is only one item in the bucket - WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); - if ( !p2 ) - { // only one active item in bucket, so change directly to weapon - ServerCmd( p->szName ); - g_weaponselect = p->iId; - return; - } - } - } - else - { - PlaySound("common/wpn_moveselect.wav", 1); - if ( gpActiveSel ) - p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); - if ( !p ) - p = GetFirstPos( iSlot ); - } - - - if ( !p ) // no selection found - { - // just display the weapon list, unless fastswitch is on just ignore it - if ( !fastSwitch ) - gpActiveSel = (WEAPON *)1; - else - gpActiveSel = NULL; - } - else - gpActiveSel = p; -} - -//------------------------------------------------------------------------ -// Message Handlers -//------------------------------------------------------------------------ - -// -// AmmoX -- Update the count of a known type of ammo -// -int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - int iIndex = READ_BYTE(); - int iCount = READ_BYTE(); - - gWR.SetAmmo( iIndex, abs(iCount) ); - - return 1; -} - -int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - int iIndex = READ_BYTE(); - int iCount = READ_BYTE(); - - // Add ammo to the history - gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); - - return 1; -} - -int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - int iIndex = READ_BYTE(); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); - - return 1; -} - -int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - const char *szName = READ_STRING(); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_ITEM, szName ); - - return 1; -} - - -int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - gHUD.m_iHideHUDDisplay = READ_BYTE(); - - if (gEngfuncs.IsSpectateOnly()) - return 1; - - if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) - { - static wrect_t nullrc; - gpActiveSel = NULL; - SetCrosshair( 0, nullrc, 0, 0, 0 ); - } - else - { - if ( m_pWeapon ) - SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - - return 1; -} - -// -// CurWeapon: Update hud state with the current weapon and clip count. Ammo -// counts are updated with AmmoX. Server assures that the Weapon ammo type -// numbers match a real ammo type. -// -int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) -{ - static wrect_t nullrc; - int fOnTarget = FALSE; - - BEGIN_READ( pbuf, iSize ); - - int iState = READ_BYTE(); - int iId = READ_CHAR(); - int iClip = READ_CHAR(); - - // detect if we're also on target - if ( iState > 1 ) - { - fOnTarget = TRUE; - } - - if ( iId < 1 ) - { - SetCrosshair(0, nullrc, 0, 0, 0); - return 0; - } - - if ( g_iUser1 != OBS_IN_EYE ) - { - // Is player dead??? - if ((iId == -1) && (iClip == -1)) - { - gHUD.m_fPlayerDead = TRUE; - gpActiveSel = NULL; - return 1; - } - gHUD.m_fPlayerDead = FALSE; - } - - WEAPON *pWeapon = gWR.GetWeapon( iId ); - - if ( !pWeapon ) - return 0; - - if ( iClip < -1 ) - pWeapon->iClip = abs(iClip); - else - pWeapon->iClip = iClip; - - - if ( iState == 0 ) // we're not the current weapon, so update no more - return 1; - - m_pWeapon = pWeapon; - - if ( gHUD.m_iFOV >= 90 ) - { // normal crosshairs - if (fOnTarget && m_pWeapon->hAutoaim) - SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); - else - SetCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); - } - else - { // zoomed crosshairs - if (fOnTarget && m_pWeapon->hZoomedAutoaim) - SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); - else - SetCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); - - } - - m_fFade = 200.0f; //!!! - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -// -// WeaponList -- Tells the hud about a new weapon type. -// -int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - WEAPON Weapon; - - strcpy( Weapon.szName, READ_STRING() ); - Weapon.iAmmoType = (int)READ_CHAR(); - - Weapon.iMax1 = READ_BYTE(); - if (Weapon.iMax1 == 255) - Weapon.iMax1 = -1; - - Weapon.iAmmo2Type = READ_CHAR(); - Weapon.iMax2 = READ_BYTE(); - if (Weapon.iMax2 == 255) - Weapon.iMax2 = -1; - - Weapon.iSlot = READ_CHAR(); - Weapon.iSlotPos = READ_CHAR(); - Weapon.iId = READ_CHAR(); - Weapon.iFlags = READ_BYTE(); - Weapon.iClip = 0; - - gWR.AddWeapon( &Weapon ); - - return 1; - -} - -//------------------------------------------------------------------------ -// Command Handlers -//------------------------------------------------------------------------ -// Slot button pressed -void CHudAmmo::SlotInput( int iSlot ) -{ - // Let the Viewport use it first, for menus -// if ( gViewPort && gViewPort->SlotInput( iSlot ) ) -// return; - - gWR.SelectSlot(iSlot, FALSE, 1); -} - -void CHudAmmo::UserCmd_Slot1(void) -{ - SlotInput( 0 ); -} - -void CHudAmmo::UserCmd_Slot2(void) -{ - SlotInput( 1 ); -} - -void CHudAmmo::UserCmd_Slot3(void) -{ - SlotInput( 2 ); -} - -void CHudAmmo::UserCmd_Slot4(void) -{ - SlotInput( 3 ); -} - -void CHudAmmo::UserCmd_Slot5(void) -{ - SlotInput( 4 ); -} - -void CHudAmmo::UserCmd_Slot6(void) -{ - SlotInput( 5 ); -} - -void CHudAmmo::UserCmd_Slot7(void) -{ - SlotInput( 6 ); -} - -void CHudAmmo::UserCmd_Slot8(void) -{ - SlotInput( 7 ); -} - -void CHudAmmo::UserCmd_Slot9(void) -{ - SlotInput( 8 ); -} - -void CHudAmmo::UserCmd_Slot10(void) -{ - SlotInput( 9 ); -} - -void CHudAmmo::UserCmd_Close(void) -{ - if (gpActiveSel) - { - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - PlaySound("common/wpn_hudoff.wav", 1); - } - else - ClientCmd("escape"); -} - - -// Selects the next item in the weapon menu -void CHudAmmo::UserCmd_NextWeapon(void) -{ - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) - return; - - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = 0; - int slot = 0; - if ( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos + 1; - slot = gpActiveSel->iSlot; - } - - for ( int loop = 0; loop <= 1; loop++ ) - { - for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) - { - for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if ( wsp && gWR.HasAmmo(wsp) ) - { - gpActiveSel = wsp; - return; - } - } - - pos = 0; - } - - slot = 0; // start looking from the first slot again - } - - gpActiveSel = NULL; -} - -// Selects the previous item in the menu -void CHudAmmo::UserCmd_PrevWeapon(void) -{ - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) - return; - - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = MAX_WEAPON_POSITIONS-1; - int slot = MAX_WEAPON_SLOTS-1; - if ( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos - 1; - slot = gpActiveSel->iSlot; - } - - for ( int loop = 0; loop <= 1; loop++ ) - { - for ( ; slot >= 0; slot-- ) - { - for ( ; pos >= 0; pos-- ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if ( wsp && gWR.HasAmmo(wsp) ) - { - gpActiveSel = wsp; - return; - } - } - - pos = MAX_WEAPON_POSITIONS-1; - } - - slot = MAX_WEAPON_SLOTS-1; - } - - gpActiveSel = NULL; -} - - - -//------------------------------------------------------------------------- -// Drawing code -//------------------------------------------------------------------------- - -int CHudAmmo::Draw(float flTime) -{ - int a, x, y, r, g, b; - int AmmoWidth; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) - return 1; - - // Draw Weapon Menu - DrawWList(flTime); - - // Draw ammo pickup history - gHR.DrawAmmoHistory( flTime ); - - if (!(m_iFlags & HUD_ACTIVE)) - return 0; - - if (!m_pWeapon) - return 0; - - WEAPON *pw = m_pWeapon; // shorthand - - // SPR_Draw Ammo - if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) - return 0; - - - int iFlags = DHN_DRAWZERO; // draw 0 values - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - a = (int) max( MIN_ALPHA, m_fFade ); - - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - ScaleColors(r, g, b, a ); - - // Does this weapon have a clip? - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; - - // Does weapon have any ammo at all? - if (m_pWeapon->iAmmoType > 0) - { - int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; - - if (pw->iClip >= 0) - { - // room for the number and the '|' and the current ammo - - x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); - - wrect_t rc; - rc.top = 0; - rc.left = 0; - rc.right = AmmoWidth; - rc.bottom = 100; - - int iBarWidth = AmmoWidth/10; - - x += AmmoWidth/2; - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - // draw the | bar - FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); - - x += iBarWidth + AmmoWidth/2;; - - // GL Seems to need this - ScaleColors(r, g, b, a ); - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - - - } - else - { - // SPR_Draw a bullets only line - x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - } - - // Draw the ammo Icon - int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; - SPR_Set(m_pWeapon->hAmmo, r, g, b); - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); - } - - // Does weapon have seconday ammo? - if (pw->iAmmo2Type > 0) - { - int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; - - // Do we have secondary ammo? - if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) - { - y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; - x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); - - // Draw the ammo Icon - SPR_Set(m_pWeapon->hAmmo2, r, g, b); - int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); - } - } - return 1; -} - - -// -// Draws the ammo bar on the hud -// -int DrawBar(int x, int y, int width, int height, float f) -{ - int r, g, b; - - if (f < 0) - f = 0; - if (f > 1) - f = 1; - - if (f) - { - int w = f * width; - - // Always show at least one pixel if we have ammo. - if (w <= 0) - w = 1; - UnpackRGB(r, g, b, RGB_GREENISH); - FillRGBA(x, y, w, height, r, g, b, 255); - x += w; - width -= w; - } - - UnpackRGB(r, g, b, RGB_YELLOWISH); - - FillRGBA(x, y, width, height, r, g, b, 128); - - return (x + width); -} - - - -void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) -{ - if ( !p ) - return; - - if (p->iAmmoType != -1) - { - if (!gWR.CountAmmo(p->iAmmoType)) - return; - - float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; - - x = DrawBar(x, y, width, height, f); - - - // Do we have secondary ammo too? - - if (p->iAmmo2Type != -1) - { - f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; - - x += 5; //!!! - - DrawBar(x, y, width, height, f); - } - } -} - - - - -// -// Draw Weapon Menu -// -int CHudAmmo::DrawWList(float flTime) -{ - int r,g,b,x,y,a,i; - - if ( !gpActiveSel ) - return 0; - - int iActiveSlot; - - if ( gpActiveSel == (WEAPON *)1 ) - iActiveSlot = -1; // current slot has no weapons - else - iActiveSlot = gpActiveSel->iSlot; - - x = 10; //!!! - y = 10; //!!! - - - // Ensure that there are available choices in the active slot - if ( iActiveSlot > 0 ) - { - if ( !gWR.GetFirstPos( iActiveSlot ) ) - { - gpActiveSel = (WEAPON *)1; - iActiveSlot = -1; - } - } - - // Draw top line - for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) - { - int iWidth; - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - if ( iActiveSlot == i ) - a = 255; - else - a = 192; - - ScaleColors(r, g, b, 255); - SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); - - // make active slot wide enough to accomodate gun pictures - if ( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos(iActiveSlot); - if ( p ) - iWidth = p->rcActive.right - p->rcActive.left; - else - iWidth = giBucketWidth; - } - else - iWidth = giBucketWidth; - - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); - - x += iWidth + 5; - } - - - a = 128; //!!! - x = 10; - - // Draw all of the buckets - for (i = 0; i < MAX_WEAPON_SLOTS; i++) - { - y = giBucketHeight + 10; - - // If this is the active slot, draw the bigger pictures, - // otherwise just draw boxes - if ( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos( i ); - int iWidth = giBucketWidth; - if ( p ) - iWidth = p->rcActive.right - p->rcActive.left; - - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - p = gWR.GetWeaponSlot( i, iPos ); - - if ( !p || !p->iId ) - continue; - - UnpackRGB( r,g,b, RGB_YELLOWISH ); - - // if active, then we must have ammo. - - if ( gpActiveSel == p ) - { - SPR_Set(p->hActive, r, g, b ); - SPR_DrawAdditive(0, x, y, &p->rcActive); - - SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); - } - else - { - // Draw Weapon if Red if no ammo - - if ( gWR.HasAmmo(p) ) - ScaleColors(r, g, b, 192); - else - { - UnpackRGB(r,g,b, RGB_REDISH); - ScaleColors(r, g, b, 128); - } - - SPR_Set( p->hInactive, r, g, b ); - SPR_DrawAdditive( 0, x, y, &p->rcInactive ); - } - - // Draw Ammo Bar - - DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); - - y += p->rcActive.bottom - p->rcActive.top + 5; - } - - x += iWidth + 5; - - } - else - { - // Draw Row of weapons. - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - WEAPON *p = gWR.GetWeaponSlot( i, iPos ); - - if ( !p || !p->iId ) - continue; - - if ( gWR.HasAmmo(p) ) - { - UnpackRGB(r,g,b, RGB_YELLOWISH); - a = 128; - } - else - { - UnpackRGB(r,g,b, RGB_REDISH); - a = 96; - } - - FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); - - y += giBucketHeight + 5; - } - - x += giBucketWidth + 5; - } - } - - return 1; - -} - - -/* ================================= - GetSpriteList - -Finds and returns the matching -sprite name 'psz' and resolution 'iRes' -in the given sprite list 'pList' -iCount is the number of items in the pList -================================= */ -client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) -{ - if (!pList) - return NULL; - - int i = iCount; - client_sprite_t *p = pList; - - while(i--) - { - if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) - return p; - p++; - } - - return NULL; -} +/*** +* +* 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. +* +****/ +// +// Ammo.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "pm_shared.h" + +#include +#include + +#include "ammohistory.h" + +WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise + // this points to the active weapon menu item +WEAPON *gpLastSel; // Last weapon menu selection + +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +WeaponsResource gWR; + +int g_weaponselect = 0; + +void WeaponsResource :: LoadAllWeaponSprites( void ) +{ + for (int i = 0; i < MAX_WEAPONS; i++) + { + if ( rgWeapons[i].iId ) + LoadWeaponSprites( &rgWeapons[i] ); + } +} + +int WeaponsResource :: CountAmmo( int iId ) +{ + if ( iId < 0 ) + return 0; + + return riAmmo[iId]; +} + +int WeaponsResource :: HasAmmo( WEAPON *p ) +{ + if ( !p ) + return FALSE; + + // weapons with no max ammo can always be selected + if ( p->iMax1 == -1 ) + return TRUE; + + return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) + || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); +} + + +void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) +{ + int i, iRes; + + if (ScreenWidth < 640) + iRes = 320; + else + iRes = 640; + + char sz[128]; + + if ( !pWeapon ) + return; + + memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); + pWeapon->hInactive = 0; + pWeapon->hActive = 0; + pWeapon->hAmmo = 0; + pWeapon->hAmmo2 = 0; + + sprintf(sz, "sprites/%s.txt", pWeapon->szName); + client_sprite_t *pList = SPR_GetList(sz, &i); + + if (!pList) + return; + + client_sprite_t *p; + + p = GetSpriteList( pList, "crosshair", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hCrosshair = SPR_Load(sz); + pWeapon->rcCrosshair = p->rc; + } + else + pWeapon->hCrosshair = 0; + + p = GetSpriteList(pList, "autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAutoaim = SPR_Load(sz); + pWeapon->rcAutoaim = p->rc; + } + else + pWeapon->hAutoaim = 0; + + p = GetSpriteList( pList, "zoom", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedCrosshair = SPR_Load(sz); + pWeapon->rcZoomedCrosshair = p->rc; + } + else + { + pWeapon->hZoomedCrosshair = pWeapon->hCrosshair; //default to non-zoomed crosshair + pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; + } + + p = GetSpriteList(pList, "zoom_autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedAutoaim = SPR_Load(sz); + pWeapon->rcZoomedAutoaim = p->rc; + } + else + { + pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair; //default to zoomed crosshair + pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; + } + + p = GetSpriteList(pList, "weapon", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hInactive = SPR_Load(sz); + pWeapon->rcInactive = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hInactive = 0; + + p = GetSpriteList(pList, "weapon_s", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hActive = SPR_Load(sz); + pWeapon->rcActive = p->rc; + } + else + pWeapon->hActive = 0; + + p = GetSpriteList(pList, "ammo", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo = SPR_Load(sz); + pWeapon->rcAmmo = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo = 0; + + p = GetSpriteList(pList, "ammo2", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo2 = SPR_Load(sz); + pWeapon->rcAmmo2 = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo2 = 0; + +} + +// Returns the first weapon for a given slot. +WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) +{ + WEAPON *pret = NULL; + + for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) + { + if ( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] ) ) + { + pret = rgSlots[iSlot][i]; + break; + } + } + + return pret; +} + + +WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) +{ + if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) + return NULL; + + WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; + + if ( !p || !gWR.HasAmmo(p) ) + return GetNextActivePos( iSlot, iSlotPos + 1 ); + + return p; +} + + +int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height + +HSPRITE ghsprBuckets; // Sprite for top row of weapons menu + +DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip +DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type +DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count +DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record +DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record +DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE(m_Ammo, ItemPickup); + +DECLARE_COMMAND(m_Ammo, Slot1); +DECLARE_COMMAND(m_Ammo, Slot2); +DECLARE_COMMAND(m_Ammo, Slot3); +DECLARE_COMMAND(m_Ammo, Slot4); +DECLARE_COMMAND(m_Ammo, Slot5); +DECLARE_COMMAND(m_Ammo, Slot6); +DECLARE_COMMAND(m_Ammo, Slot7); +DECLARE_COMMAND(m_Ammo, Slot8); +DECLARE_COMMAND(m_Ammo, Slot9); +DECLARE_COMMAND(m_Ammo, Slot10); +DECLARE_COMMAND(m_Ammo, Close); +DECLARE_COMMAND(m_Ammo, NextWeapon); +DECLARE_COMMAND(m_Ammo, PrevWeapon); + +// width of ammo fonts +#define AMMO_SMALL_WIDTH 10 +#define AMMO_LARGE_WIDTH 20 + +#define HISTORY_DRAW_TIME "5" + +int CHudAmmo::Init(void) +{ + gHUD.AddHudElem(this); + + HOOK_MESSAGE(CurWeapon); + HOOK_MESSAGE(WeaponList); + HOOK_MESSAGE(AmmoPickup); + HOOK_MESSAGE(WeapPickup); + HOOK_MESSAGE(ItemPickup); + HOOK_MESSAGE(HideWeapon); + HOOK_MESSAGE(AmmoX); + + HOOK_COMMAND("slot1", Slot1); + HOOK_COMMAND("slot2", Slot2); + HOOK_COMMAND("slot3", Slot3); + HOOK_COMMAND("slot4", Slot4); + HOOK_COMMAND("slot5", Slot5); + HOOK_COMMAND("slot6", Slot6); + HOOK_COMMAND("slot7", Slot7); + HOOK_COMMAND("slot8", Slot8); + HOOK_COMMAND("slot9", Slot9); + HOOK_COMMAND("slot10", Slot10); + HOOK_COMMAND("cancelselect", Close); + HOOK_COMMAND("invnext", NextWeapon); + HOOK_COMMAND("invprev", PrevWeapon); + + Reset(); + + CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); + CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress + + m_iFlags |= HUD_ACTIVE; //!!! + + gWR.Init(); + gHR.Init(); + + return 1; +}; + +void CHudAmmo::Reset(void) +{ + m_fFade = 0; + m_iFlags |= HUD_ACTIVE; //!!! + + gpActiveSel = NULL; + gHUD.m_iHideHUDDisplay = 0; + + gWR.Reset(); + gHR.Reset(); + + // VidInit(); + +} + +int CHudAmmo::VidInit(void) +{ + // Load sprites for buckets (top row of weapon menu) + m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); + m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); + + ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); + giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; + giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; + + gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); + + // If we've already loaded weapons, let's get new sprites + gWR.LoadAllWeaponSprites(); + + if (ScreenWidth >= 640) + { + giABWidth = 20; + giABHeight = 4; + } + else + { + giABWidth = 10; + giABHeight = 2; + } + + return 1; +} + +// +// Think: +// Used for selection of weapon menu item. +// +void CHudAmmo::Think(void) +{ + if ( gHUD.m_fPlayerDead ) + return; + + if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) + { + gWR.iOldWeaponBits = gHUD.m_iWeaponBits; + + for (int i = MAX_WEAPONS-1; i > 0; i-- ) + { + WEAPON *p = gWR.GetWeapon(i); + + if ( p ) + { + if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) + gWR.PickupWeapon( p ); + else + gWR.DropWeapon( p ); + } + } + } + + if (!gpActiveSel) + return; + + // has the player selected one? + if (gHUD.m_iKeyBits & IN_ATTACK) + { + if (gpActiveSel != (WEAPON *)1) + { + ServerCmd(gpActiveSel->szName); + g_weaponselect = gpActiveSel->iId; + } + + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + gHUD.m_iKeyBits &= ~IN_ATTACK; + + PlaySound("common/wpn_select.wav", 1); + } + +} + +// +// Helper function to return a Ammo pointer from id +// + +HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iAmmoType == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo; + return &rgWeapons[i].hAmmo; + } + else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo2; + return &rgWeapons[i].hAmmo2; + } + } + + return NULL; +} + + +// Menu Selection Code + +void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) +{ + if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) + { // menu is overriding slot use commands + gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers + return; + } + + if ( iSlot > MAX_WEAPON_SLOTS ) + return; + + if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + return; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return; + + if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) + return; + + WEAPON *p = NULL; + bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; + + if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) + { + PlaySound( "common/wpn_hudon.wav", 1 ); + p = GetFirstPos( iSlot ); + + if ( p && fastSwitch ) // check for fast weapon switch mode + { + // if fast weapon switch is on, then weapons can be selected in a single keypress + // but only if there is only one item in the bucket + WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); + if ( !p2 ) + { // only one active item in bucket, so change directly to weapon + ServerCmd( p->szName ); + g_weaponselect = p->iId; + return; + } + } + } + else + { + PlaySound("common/wpn_moveselect.wav", 1); + if ( gpActiveSel ) + p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); + if ( !p ) + p = GetFirstPos( iSlot ); + } + + + if ( !p ) // no selection found + { + // just display the weapon list, unless fastswitch is on just ignore it + if ( !fastSwitch ) + gpActiveSel = (WEAPON *)1; + else + gpActiveSel = NULL; + } + else + gpActiveSel = p; +} + +//------------------------------------------------------------------------ +// Message Handlers +//------------------------------------------------------------------------ + +// +// AmmoX -- Update the count of a known type of ammo +// +int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + gWR.SetAmmo( iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + // Add ammo to the history + gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); + + return 1; +} + +int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + const char *szName = READ_STRING(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_ITEM, szName ); + + return 1; +} + + +int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + gHUD.m_iHideHUDDisplay = READ_BYTE(); + + if (gEngfuncs.IsSpectateOnly()) + return 1; + + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + { + static wrect_t nullrc; + gpActiveSel = NULL; + SetCrosshair( 0, nullrc, 0, 0, 0 ); + } + else + { + if ( m_pWeapon ) + SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); + } + + return 1; +} + +// +// CurWeapon: Update hud state with the current weapon and clip count. Ammo +// counts are updated with AmmoX. Server assures that the Weapon ammo type +// numbers match a real ammo type. +// +int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) +{ + static wrect_t nullrc; + int fOnTarget = FALSE; + + BEGIN_READ( pbuf, iSize ); + + int iState = READ_BYTE(); + int iId = READ_CHAR(); + int iClip = READ_CHAR(); + + // detect if we're also on target + if ( iState > 1 ) + { + fOnTarget = TRUE; + } + + if ( iId < 1 ) + { + SetCrosshair(0, nullrc, 0, 0, 0); + return 0; + } + + if ( g_iUser1 != OBS_IN_EYE ) + { + // Is player dead??? + if ((iId == -1) && (iClip == -1)) + { + gHUD.m_fPlayerDead = TRUE; + gpActiveSel = NULL; + return 1; + } + gHUD.m_fPlayerDead = FALSE; + } + + WEAPON *pWeapon = gWR.GetWeapon( iId ); + + if ( !pWeapon ) + return 0; + + if ( iClip < -1 ) + pWeapon->iClip = abs(iClip); + else + pWeapon->iClip = iClip; + + + if ( iState == 0 ) // we're not the current weapon, so update no more + return 1; + + m_pWeapon = pWeapon; + + if ( gHUD.m_iFOV >= 90 ) + { // normal crosshairs + if (fOnTarget && m_pWeapon->hAutoaim) + SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + } + else + { // zoomed crosshairs + if (fOnTarget && m_pWeapon->hZoomedAutoaim) + SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); + + } + + m_fFade = 200.0f; //!!! + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +// +// WeaponList -- Tells the hud about a new weapon type. +// +int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + WEAPON Weapon; + + strcpy( Weapon.szName, READ_STRING() ); + Weapon.iAmmoType = (int)READ_CHAR(); + + Weapon.iMax1 = READ_BYTE(); + if (Weapon.iMax1 == 255) + Weapon.iMax1 = -1; + + Weapon.iAmmo2Type = READ_CHAR(); + Weapon.iMax2 = READ_BYTE(); + if (Weapon.iMax2 == 255) + Weapon.iMax2 = -1; + + Weapon.iSlot = READ_CHAR(); + Weapon.iSlotPos = READ_CHAR(); + Weapon.iId = READ_CHAR(); + Weapon.iFlags = READ_BYTE(); + Weapon.iClip = 0; + + gWR.AddWeapon( &Weapon ); + + return 1; + +} + +//------------------------------------------------------------------------ +// Command Handlers +//------------------------------------------------------------------------ +// Slot button pressed +void CHudAmmo::SlotInput( int iSlot ) +{ + // Let the Viewport use it first, for menus +// if ( gViewPort && gViewPort->SlotInput( iSlot ) ) +// return; + + gWR.SelectSlot(iSlot, FALSE, 1); +} + +void CHudAmmo::UserCmd_Slot1(void) +{ + SlotInput( 0 ); +} + +void CHudAmmo::UserCmd_Slot2(void) +{ + SlotInput( 1 ); +} + +void CHudAmmo::UserCmd_Slot3(void) +{ + SlotInput( 2 ); +} + +void CHudAmmo::UserCmd_Slot4(void) +{ + SlotInput( 3 ); +} + +void CHudAmmo::UserCmd_Slot5(void) +{ + SlotInput( 4 ); +} + +void CHudAmmo::UserCmd_Slot6(void) +{ + SlotInput( 5 ); +} + +void CHudAmmo::UserCmd_Slot7(void) +{ + SlotInput( 6 ); +} + +void CHudAmmo::UserCmd_Slot8(void) +{ + SlotInput( 7 ); +} + +void CHudAmmo::UserCmd_Slot9(void) +{ + SlotInput( 8 ); +} + +void CHudAmmo::UserCmd_Slot10(void) +{ + SlotInput( 9 ); +} + +void CHudAmmo::UserCmd_Close(void) +{ + if (gpActiveSel) + { + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + PlaySound("common/wpn_hudoff.wav", 1); + } + else + ClientCmd("escape"); +} + + +// Selects the next item in the weapon menu +void CHudAmmo::UserCmd_NextWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = 0; + int slot = 0; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos + 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) + { + for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = 0; + } + + slot = 0; // start looking from the first slot again + } + + gpActiveSel = NULL; +} + +// Selects the previous item in the menu +void CHudAmmo::UserCmd_PrevWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = MAX_WEAPON_POSITIONS-1; + int slot = MAX_WEAPON_SLOTS-1; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos - 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot >= 0; slot-- ) + { + for ( ; pos >= 0; pos-- ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = MAX_WEAPON_POSITIONS-1; + } + + slot = MAX_WEAPON_SLOTS-1; + } + + gpActiveSel = NULL; +} + + + +//------------------------------------------------------------------------- +// Drawing code +//------------------------------------------------------------------------- + +int CHudAmmo::Draw(float flTime) +{ + int a, x, y, r, g, b; + int AmmoWidth; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // Draw Weapon Menu + DrawWList(flTime); + + // Draw ammo pickup history + gHR.DrawAmmoHistory( flTime ); + + if (!(m_iFlags & HUD_ACTIVE)) + return 0; + + if (!m_pWeapon) + return 0; + + WEAPON *pw = m_pWeapon; // shorthand + + // SPR_Draw Ammo + if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) + return 0; + + + int iFlags = DHN_DRAWZERO; // draw 0 values + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + a = (int) max( MIN_ALPHA, m_fFade ); + + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a ); + + // Does this weapon have a clip? + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; + + // Does weapon have any ammo at all? + if (m_pWeapon->iAmmoType > 0) + { + int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; + + if (pw->iClip >= 0) + { + // room for the number and the '|' and the current ammo + + x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); + + wrect_t rc; + rc.top = 0; + rc.left = 0; + rc.right = AmmoWidth; + rc.bottom = 100; + + int iBarWidth = AmmoWidth/10; + + x += AmmoWidth/2; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + // draw the | bar + FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); + + x += iBarWidth + AmmoWidth/2;; + + // GL Seems to need this + ScaleColors(r, g, b, a ); + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + + + } + else + { + // SPR_Draw a bullets only line + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + } + + // Draw the ammo Icon + int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; + SPR_Set(m_pWeapon->hAmmo, r, g, b); + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); + } + + // Does weapon have seconday ammo? + if (pw->iAmmo2Type > 0) + { + int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; + + // Do we have secondary ammo? + if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) + { + y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); + + // Draw the ammo Icon + SPR_Set(m_pWeapon->hAmmo2, r, g, b); + int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); + } + } + return 1; +} + + +// +// Draws the ammo bar on the hud +// +int DrawBar(int x, int y, int width, int height, float f) +{ + int r, g, b; + + if (f < 0) + f = 0; + if (f > 1) + f = 1; + + if (f) + { + int w = f * width; + + // Always show at least one pixel if we have ammo. + if (w <= 0) + w = 1; + UnpackRGB(r, g, b, RGB_GREENISH); + FillRGBA(x, y, w, height, r, g, b, 255); + x += w; + width -= w; + } + + UnpackRGB(r, g, b, RGB_YELLOWISH); + + FillRGBA(x, y, width, height, r, g, b, 128); + + return (x + width); +} + + + +void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) +{ + if ( !p ) + return; + + if (p->iAmmoType != -1) + { + if (!gWR.CountAmmo(p->iAmmoType)) + return; + + float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; + + x = DrawBar(x, y, width, height, f); + + + // Do we have secondary ammo too? + + if (p->iAmmo2Type != -1) + { + f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; + + x += 5; //!!! + + DrawBar(x, y, width, height, f); + } + } +} + + + + +// +// Draw Weapon Menu +// +int CHudAmmo::DrawWList(float flTime) +{ + int r,g,b,x,y,a,i; + + if ( !gpActiveSel ) + return 0; + + int iActiveSlot; + + if ( gpActiveSel == (WEAPON *)1 ) + iActiveSlot = -1; // current slot has no weapons + else + iActiveSlot = gpActiveSel->iSlot; + + x = 10; //!!! + y = 10; //!!! + + + // Ensure that there are available choices in the active slot + if ( iActiveSlot > 0 ) + { + if ( !gWR.GetFirstPos( iActiveSlot ) ) + { + gpActiveSel = (WEAPON *)1; + iActiveSlot = -1; + } + } + + // Draw top line + for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + int iWidth; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if ( iActiveSlot == i ) + a = 255; + else + a = 192; + + ScaleColors(r, g, b, 255); + SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); + + // make active slot wide enough to accomodate gun pictures + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos(iActiveSlot); + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + else + iWidth = giBucketWidth; + } + else + iWidth = giBucketWidth; + + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); + + x += iWidth + 5; + } + + + a = 128; //!!! + x = 10; + + // Draw all of the buckets + for (i = 0; i < MAX_WEAPON_SLOTS; i++) + { + y = giBucketHeight + 10; + + // If this is the active slot, draw the bigger pictures, + // otherwise just draw boxes + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos( i ); + int iWidth = giBucketWidth; + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + UnpackRGB( r,g,b, RGB_YELLOWISH ); + + // if active, then we must have ammo. + + if ( gpActiveSel == p ) + { + SPR_Set(p->hActive, r, g, b ); + SPR_DrawAdditive(0, x, y, &p->rcActive); + + SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); + } + else + { + // Draw Weapon if Red if no ammo + + if ( gWR.HasAmmo(p) ) + ScaleColors(r, g, b, 192); + else + { + UnpackRGB(r,g,b, RGB_REDISH); + ScaleColors(r, g, b, 128); + } + + SPR_Set( p->hInactive, r, g, b ); + SPR_DrawAdditive( 0, x, y, &p->rcInactive ); + } + + // Draw Ammo Bar + + DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); + + y += p->rcActive.bottom - p->rcActive.top + 5; + } + + x += iWidth + 5; + + } + else + { + // Draw Row of weapons. + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + WEAPON *p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + if ( gWR.HasAmmo(p) ) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + a = 128; + } + else + { + UnpackRGB(r,g,b, RGB_REDISH); + a = 96; + } + + FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); + + y += giBucketHeight + 5; + } + + x += giBucketWidth + 5; + } + } + + return 1; + +} + + +/* ================================= + GetSpriteList + +Finds and returns the matching +sprite name 'psz' and resolution 'iRes' +in the given sprite list 'pList' +iCount is the number of items in the pList +================================= */ +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) +{ + if (!pList) + return NULL; + + int i = iCount; + client_sprite_t *p = pList; + + while(i--) + { + if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) + return p; + p++; + } + + return NULL; +} diff --git a/cl_dll/ammo.h b/cl_dll/ammo.h index ad730cc8..5e44065a 100644 --- a/cl_dll/ammo.h +++ b/cl_dll/ammo.h @@ -1,62 +1,62 @@ -/*** -* -* 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 __AMMO_H__ -#define __AMMO_H__ - -#define MAX_WEAPON_NAME 128 - - -#define WEAPON_FLAGS_SELECTONEMPTY 1 - -#define WEAPON_IS_ONTARGET 0x40 - -struct WEAPON -{ - char szName[MAX_WEAPON_NAME]; - int iAmmoType; - int iAmmo2Type; - int iMax1; - int iMax2; - int iSlot; - int iSlotPos; - int iFlags; - int iId; - int iClip; - - int iCount; // # of itesm in plist - - HSPRITE hActive; - wrect_t rcActive; - HSPRITE hInactive; - wrect_t rcInactive; - HSPRITE hAmmo; - wrect_t rcAmmo; - HSPRITE hAmmo2; - wrect_t rcAmmo2; - HSPRITE hCrosshair; - wrect_t rcCrosshair; - HSPRITE hAutoaim; - wrect_t rcAutoaim; - HSPRITE hZoomedCrosshair; - wrect_t rcZoomedCrosshair; - HSPRITE hZoomedAutoaim; - wrect_t rcZoomedAutoaim; -}; - -typedef int AMMO; - - +/*** +* +* 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 __AMMO_H__ +#define __AMMO_H__ + +#define MAX_WEAPON_NAME 128 + + +#define WEAPON_FLAGS_SELECTONEMPTY 1 + +#define WEAPON_IS_ONTARGET 0x40 + +struct WEAPON +{ + char szName[MAX_WEAPON_NAME]; + int iAmmoType; + int iAmmo2Type; + int iMax1; + int iMax2; + int iSlot; + int iSlotPos; + int iFlags; + int iId; + int iClip; + + int iCount; // # of itesm in plist + + HSPRITE hActive; + wrect_t rcActive; + HSPRITE hInactive; + wrect_t rcInactive; + HSPRITE hAmmo; + wrect_t rcAmmo; + HSPRITE hAmmo2; + wrect_t rcAmmo2; + HSPRITE hCrosshair; + wrect_t rcCrosshair; + HSPRITE hAutoaim; + wrect_t rcAutoaim; + HSPRITE hZoomedCrosshair; + wrect_t rcZoomedCrosshair; + HSPRITE hZoomedAutoaim; + wrect_t rcZoomedAutoaim; +}; + +typedef int AMMO; + + #endif \ No newline at end of file diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index 2ca07d2d..e2a2f591 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -1,159 +1,159 @@ -/*** -* -* 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. -* -****/ -// -// ammo_secondary.cpp -// -// implementation of CHudAmmoSecondary class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "parsemsg.h" - -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); - -int CHudAmmoSecondary :: Init( void ) -{ - HOOK_MESSAGE( SecAmmoVal ); - HOOK_MESSAGE( SecAmmoIcon ); - - gHUD.AddHudElem(this); - m_HUD_ammoicon = 0; - - for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) - m_iAmmoAmounts[i] = -1; // -1 means don't draw this value - - Reset(); - - return 1; -} - -void CHudAmmoSecondary :: Reset( void ) -{ - m_fFade = 0; -} - -int CHudAmmoSecondary :: VidInit( void ) -{ - return 1; -} - -int CHudAmmoSecondary :: Draw(float flTime) -{ - if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) - return 1; - - // draw secondary ammo icons above normal ammo readout - int a, x, y, r, g, b, AmmoWidth; - UnpackRGB( r, g, b, RGB_YELLOWISH ); - a = (int) max( MIN_ALPHA, m_fFade ); - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons - ScaleColors( r, g, b, a ); - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values - x = ScreenWidth - AmmoWidth; - - if ( m_HUD_ammoicon ) - { - // Draw the ammo icon - x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); - y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); - - SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); - } - else - { // move the cursor by the '0' char instead, since we don't have an icon to work with - x -= AmmoWidth; - y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); - } - - // draw the ammo counts, in reverse order, from right to left - for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) - { - if ( m_iAmmoAmounts[i] < 0 ) - continue; // negative ammo amounts imply that they shouldn't be drawn - - // half a char gap between the ammo number and the previous pic - x -= (AmmoWidth / 2); - - // draw the number, right-aligned - x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); - gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); - - if ( i != 0 ) - { - // draw the divider bar - x -= (AmmoWidth / 2); - FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); - } - } - - return 1; -} - -// Message handler for Secondary Ammo Value -// accepts one value: -// string: sprite name -int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); - - return 1; -} - -// Message handler for Secondary Ammo Icon -// Sets an ammo value -// takes two values: -// byte: ammo index -// byte: ammo value -int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int index = READ_BYTE(); - if ( index < 0 || index >= MAX_SEC_AMMO_VALUES ) - return 1; - - m_iAmmoAmounts[index] = READ_BYTE(); - m_iFlags |= HUD_ACTIVE; - - // check to see if there is anything left to draw - int count = 0; - for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) - { - count += max( 0, m_iAmmoAmounts[i] ); - } - - if ( count == 0 ) - { // the ammo fields are all empty, so turn off this hud area - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - - // make the icons light up - m_fFade = 200.0f; - - return 1; -} - - +/*** +* +* 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. +* +****/ +// +// ammo_secondary.cpp +// +// implementation of CHudAmmoSecondary class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); + +int CHudAmmoSecondary :: Init( void ) +{ + HOOK_MESSAGE( SecAmmoVal ); + HOOK_MESSAGE( SecAmmoIcon ); + + gHUD.AddHudElem(this); + m_HUD_ammoicon = 0; + + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + m_iAmmoAmounts[i] = -1; // -1 means don't draw this value + + Reset(); + + return 1; +} + +void CHudAmmoSecondary :: Reset( void ) +{ + m_fFade = 0; +} + +int CHudAmmoSecondary :: VidInit( void ) +{ + return 1; +} + +int CHudAmmoSecondary :: Draw(float flTime) +{ + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // draw secondary ammo icons above normal ammo readout + int a, x, y, r, g, b, AmmoWidth; + UnpackRGB( r, g, b, RGB_YELLOWISH ); + a = (int) max( MIN_ALPHA, m_fFade ); + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons + ScaleColors( r, g, b, a ); + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values + x = ScreenWidth - AmmoWidth; + + if ( m_HUD_ammoicon ) + { + // Draw the ammo icon + x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); + y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); + + SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); + } + else + { // move the cursor by the '0' char instead, since we don't have an icon to work with + x -= AmmoWidth; + y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); + } + + // draw the ammo counts, in reverse order, from right to left + for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) + { + if ( m_iAmmoAmounts[i] < 0 ) + continue; // negative ammo amounts imply that they shouldn't be drawn + + // half a char gap between the ammo number and the previous pic + x -= (AmmoWidth / 2); + + // draw the number, right-aligned + x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); + gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); + + if ( i != 0 ) + { + // draw the divider bar + x -= (AmmoWidth / 2); + FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); + } + } + + return 1; +} + +// Message handler for Secondary Ammo Value +// accepts one value: +// string: sprite name +int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); + + return 1; +} + +// Message handler for Secondary Ammo Icon +// Sets an ammo value +// takes two values: +// byte: ammo index +// byte: ammo value +int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + if ( index < 0 || index >= MAX_SEC_AMMO_VALUES ) + return 1; + + m_iAmmoAmounts[index] = READ_BYTE(); + m_iFlags |= HUD_ACTIVE; + + // check to see if there is anything left to draw + int count = 0; + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + { + count += max( 0, m_iAmmoAmounts[i] ); + } + + if ( count == 0 ) + { // the ammo fields are all empty, so turn off this hud area + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + + // make the icons light up + m_fFade = 200.0f; + + return 1; +} + + diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp index cf3a2cf4..86e9cb09 100644 --- a/cl_dll/ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -1,192 +1,192 @@ -/*** -* -* 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. -* -****/ -// -// ammohistory.cpp -// - - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - -#include "ammohistory.h" - -HistoryResource gHR; - -#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) -#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) -#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) - -#define MAX_ITEM_NAME 32 -int HISTORY_DRAW_TIME = 5; - -// keep a list of items -struct ITEM_INFO -{ - char szName[MAX_ITEM_NAME]; - HSPRITE spr; - wrect_t rect; -}; - -void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) -{ - if ( iType == HISTSLOT_AMMO && !iCount ) - return; // no amount, so don't add - - if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { // the pic would have to be drawn too high - // so start from the bottom - iCurrentHistorySlot = 0; - } - - HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot - HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); - - freeslot->type = iType; - freeslot->iId = iId; - freeslot->iCount = iCount; - freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; -} - -void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) -{ - if ( iType != HISTSLOT_ITEM ) - return; - - if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { // the pic would have to be drawn too high - // so start from the bottom - iCurrentHistorySlot = 0; - } - - HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot - - // I am really unhappy with all the code in this file - - int i = gHUD.GetSpriteIndex( szName ); - if ( i == -1 ) - return; // unknown sprite name, don't add it to history - - freeslot->iId = i; - freeslot->type = iType; - freeslot->iCount = iCount; - - HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); - freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; -} - - -void HistoryResource :: CheckClearHistory( void ) -{ - for ( int i = 0; i < MAX_HISTORY; i++ ) - { - if ( rgAmmoHistory[i].type ) - return; - } - - iCurrentHistorySlot = 0; -} - -// -// Draw Ammo pickup history -// -int HistoryResource :: DrawAmmoHistory( float flTime ) -{ - for ( int i = 0; i < MAX_HISTORY; i++ ) - { - if ( rgAmmoHistory[i].type ) - { - rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); - - if ( rgAmmoHistory[i].DisplayTime <= flTime ) - { // pic drawing time has expired - memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); - CheckClearHistory(); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) - { - wrect_t rcPic; - HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); - - int r, g, b; - UnpackRGB(r,g,b, RGB_YELLOWISH); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - // Draw the pic - int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth - 24; - if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic - { // the dll has to make sure it has sent info the weapons you need - SPR_Set( *spr, r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); - } - +/*** +* +* 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. +* +****/ +// +// ammohistory.cpp +// + + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +#include "ammohistory.h" + +HistoryResource gHR; + +#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) +#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) +#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) + +#define MAX_ITEM_NAME 32 +int HISTORY_DRAW_TIME = 5; + +// keep a list of items +struct ITEM_INFO +{ + char szName[MAX_ITEM_NAME]; + HSPRITE spr; + wrect_t rect; +}; + +void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) +{ + if ( iType == HISTSLOT_AMMO && !iCount ) + return; // no amount, so don't add + + if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) + { // the pic would have to be drawn too high + // so start from the bottom + iCurrentHistorySlot = 0; + } + + HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot + HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); + + freeslot->type = iType; + freeslot->iId = iId; + freeslot->iCount = iCount; + freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; +} + +void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) +{ + if ( iType != HISTSLOT_ITEM ) + return; + + if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) + { // the pic would have to be drawn too high + // so start from the bottom + iCurrentHistorySlot = 0; + } + + HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot + + // I am really unhappy with all the code in this file + + int i = gHUD.GetSpriteIndex( szName ); + if ( i == -1 ) + return; // unknown sprite name, don't add it to history + + freeslot->iId = i; + freeslot->type = iType; + freeslot->iCount = iCount; + + HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" ); + freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; +} + + +void HistoryResource :: CheckClearHistory( void ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + return; + } + + iCurrentHistorySlot = 0; +} + +// +// Draw Ammo pickup history +// +int HistoryResource :: DrawAmmoHistory( float flTime ) +{ + for ( int i = 0; i < MAX_HISTORY; i++ ) + { + if ( rgAmmoHistory[i].type ) + { + rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); + + if ( rgAmmoHistory[i].DisplayTime <= flTime ) + { // pic drawing time has expired + memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); + CheckClearHistory(); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) + { + wrect_t rcPic; + HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); + + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + // Draw the pic + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - 24; + if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic + { // the dll has to make sure it has sent info the weapons you need + SPR_Set( *spr, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); + } + // do not draw black console string if( !(( hud_textmode->value == 2 ) && ( scale < 200 )) ) // Draw the number - gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) - { - WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); - - if ( !weap ) - return 1; // we don't know about the weapon yet, so don't draw anything - - int r, g, b; - UnpackRGB(r,g,b, RGB_YELLOWISH); - - if ( !gWR.HasAmmo( weap ) ) - UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red - - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left); - SPR_Set( weap->hInactive, r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); - } - else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) - { - int r, g, b; - - if ( !rgAmmoHistory[i].iId ) - continue; // sprite not loaded - - wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); - - UnpackRGB(r,g,b, RGB_YELLOWISH); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); - - int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth - (rect.right - rect.left) - 10; - - SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); - SPR_DrawAdditive( 0, xpos, ypos, &rect ); - } - } - } - - - return 1; -} - - + gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) + { + WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); + + if ( !weap ) + return 1; // we don't know about the weapon yet, so don't draw anything + + int r, g, b; + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if ( !gWR.HasAmmo( weap ) ) + UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red + + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left); + SPR_Set( weap->hInactive, r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); + } + else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) + { + int r, g, b; + + if ( !rgAmmoHistory[i].iId ) + continue; // sprite not loaded + + wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); + + UnpackRGB(r,g,b, RGB_YELLOWISH); + float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; + ScaleColors(r, g, b, min(scale, 255) ); + + int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); + int xpos = ScreenWidth - (rect.right - rect.left) - 10; + + SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); + SPR_DrawAdditive( 0, xpos, ypos, &rect ); + } + } + } + + + return 1; +} + + diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 74bf43f5..48eeafca 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -1,143 +1,143 @@ -/*** -* -* 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. -* -****/ -// -// ammohistory.h -// - -// this is the max number of items in each bucket -#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS - -class WeaponsResource -{ -private: - // Information about weapons & ammo - WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array - - // counts of weapons * ammo - WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there - int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type - -public: - void Init( void ) - { - memset( rgWeapons, 0, sizeof rgWeapons ); - Reset(); - } - - void Reset( void ) - { - iOldWeaponBits = 0; - memset( rgSlots, 0, sizeof rgSlots ); - memset( riAmmo, 0, sizeof riAmmo ); - } - -///// WEAPON ///// - int iOldWeaponBits; - - WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; } - void AddWeapon( WEAPON *wp ) - { - rgWeapons[ wp->iId ] = *wp; - LoadWeaponSprites( &rgWeapons[ wp->iId ] ); - } - - void PickupWeapon( WEAPON *wp ) - { - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; - } - - void DropWeapon( WEAPON *wp ) - { - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; - } - - void DropAllWeapons( void ) - { - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iId ) - DropWeapon( &rgWeapons[i] ); - } - } - - WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; } - - void LoadWeaponSprites( WEAPON* wp ); - void LoadAllWeaponSprites( void ); - WEAPON* GetFirstPos( int iSlot ); - void SelectSlot( int iSlot, int fAdvance, int iDirection ); - WEAPON* GetNextActivePos( int iSlot, int iSlotPos ); - - int HasAmmo( WEAPON *p ); - -///// AMMO ///// - AMMO GetAmmo( int iId ) { return iId; } - - void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; } - - int CountAmmo( int iId ); - - HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); -}; - -extern WeaponsResource gWR; - - -#define MAX_HISTORY 12 -enum { - HISTSLOT_EMPTY, - HISTSLOT_AMMO, - HISTSLOT_WEAP, - HISTSLOT_ITEM, -}; - -class HistoryResource -{ -private: - struct HIST_ITEM { - int type; - float DisplayTime; // the time at which this item should be removed from the history - int iCount; - int iId; - }; - - HIST_ITEM rgAmmoHistory[MAX_HISTORY]; - -public: - - void Init( void ) - { - Reset(); - } - - void Reset( void ) - { - memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); - } - - int iHistoryGap; - int iCurrentHistorySlot; - - void AddToHistory( int iType, int iId, int iCount = 0 ); - void AddToHistory( int iType, const char *szName, int iCount = 0 ); - - void CheckClearHistory( void ); - int DrawAmmoHistory( float flTime ); -}; - -extern HistoryResource gHR; - - - +/*** +* +* 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. +* +****/ +// +// ammohistory.h +// + +// this is the max number of items in each bucket +#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS + +class WeaponsResource +{ +private: + // Information about weapons & ammo + WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array + + // counts of weapons * ammo + WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there + int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type + +public: + void Init( void ) + { + memset( rgWeapons, 0, sizeof rgWeapons ); + Reset(); + } + + void Reset( void ) + { + iOldWeaponBits = 0; + memset( rgSlots, 0, sizeof rgSlots ); + memset( riAmmo, 0, sizeof riAmmo ); + } + +///// WEAPON ///// + int iOldWeaponBits; + + WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; } + void AddWeapon( WEAPON *wp ) + { + rgWeapons[ wp->iId ] = *wp; + LoadWeaponSprites( &rgWeapons[ wp->iId ] ); + } + + void PickupWeapon( WEAPON *wp ) + { + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; + } + + void DropWeapon( WEAPON *wp ) + { + rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; + } + + void DropAllWeapons( void ) + { + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iId ) + DropWeapon( &rgWeapons[i] ); + } + } + + WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; } + + void LoadWeaponSprites( WEAPON* wp ); + void LoadAllWeaponSprites( void ); + WEAPON* GetFirstPos( int iSlot ); + void SelectSlot( int iSlot, int fAdvance, int iDirection ); + WEAPON* GetNextActivePos( int iSlot, int iSlotPos ); + + int HasAmmo( WEAPON *p ); + +///// AMMO ///// + AMMO GetAmmo( int iId ) { return iId; } + + void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; } + + int CountAmmo( int iId ); + + HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); +}; + +extern WeaponsResource gWR; + + +#define MAX_HISTORY 12 +enum { + HISTSLOT_EMPTY, + HISTSLOT_AMMO, + HISTSLOT_WEAP, + HISTSLOT_ITEM, +}; + +class HistoryResource +{ +private: + struct HIST_ITEM { + int type; + float DisplayTime; // the time at which this item should be removed from the history + int iCount; + int iId; + }; + + HIST_ITEM rgAmmoHistory[MAX_HISTORY]; + +public: + + void Init( void ) + { + Reset(); + } + + void Reset( void ) + { + memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); + } + + int iHistoryGap; + int iCurrentHistorySlot; + + void AddToHistory( int iType, int iId, int iCount = 0 ); + void AddToHistory( int iType, const char *szName, int iCount = 0 ); + + void CheckClearHistory( void ); + int DrawAmmoHistory( float flTime ); +}; + +extern HistoryResource gHR; + + + diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp index 0ec45542..dc9a3fbe 100644 --- a/cl_dll/battery.cpp +++ b/cl_dll/battery.cpp @@ -1,138 +1,138 @@ -/*** -* -* 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. -* -****/ -// -// battery.cpp -// -// implementation of CHudBattery class -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - -DECLARE_MESSAGE(m_Battery, Battery) - -int CHudBattery::Init(void) -{ - m_iBat = 0; - m_fFade = 0; - m_iFlags = 0; - - HOOK_MESSAGE(Battery); - - gHUD.AddHudElem(this); - - return 1; -}; - - -int CHudBattery::VidInit(void) -{ - int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); - int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); - - m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded - m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty ); - m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full ); - m_iHeight = m_prc2->bottom - m_prc1->top; - m_fFade = 0; - return 1; -}; - -int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - - BEGIN_READ( pbuf, iSize ); - int x = READ_SHORT(); - - if (x != m_iBat) - { - m_fFade = FADE_TIME; - m_iBat = x; - } - - return 1; -} - - -int CHudBattery::Draw(float flTime) -{ - if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) - return 1; - - int r, g, b, x, y, a; - wrect_t rc; - - rc = *m_prc2; - rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - // Has health changed? Flash the health # - if (m_fFade) - { - if (m_fFade > FADE_TIME) - m_fFade = FADE_TIME; - - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) - { - a = 128; - m_fFade = 0; - } - - // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - - } - else - a = MIN_ALPHA; - - ScaleColors(r, g, b, a ); - - int iOffset = (m_prc1->bottom - m_prc1->top)/6; - - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = ScreenWidth/5; - - // make sure we have the right sprite handles - if ( !m_hSprite1 ) - m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); - if ( !m_hSprite2 ) - m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); - - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); - - if (rc.bottom > rc.top) - { - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); - } - - x += (m_prc1->right - m_prc1->left); - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); - - return 1; +/*** +* +* 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. +* +****/ +// +// battery.cpp +// +// implementation of CHudBattery class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE(m_Battery, Battery) + +int CHudBattery::Init(void) +{ + m_iBat = 0; + m_fFade = 0; + m_iFlags = 0; + + HOOK_MESSAGE(Battery); + + gHUD.AddHudElem(this); + + return 1; +}; + + +int CHudBattery::VidInit(void) +{ + int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); + int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); + + m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded + m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty ); + m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full ); + m_iHeight = m_prc2->bottom - m_prc1->top; + m_fFade = 0; + return 1; +}; + +int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + + BEGIN_READ( pbuf, iSize ); + int x = READ_SHORT(); + + if (x != m_iBat) + { + m_fFade = FADE_TIME; + m_iBat = x; + } + + return 1; +} + + +int CHudBattery::Draw(float flTime) +{ + if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + rc = *m_prc2; + rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + // Has health changed? Flash the health # + if (m_fFade) + { + if (m_fFade > FADE_TIME) + m_fFade = FADE_TIME; + + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = 128; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + ScaleColors(r, g, b, a ); + + int iOffset = (m_prc1->bottom - m_prc1->top)/6; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = ScreenWidth/5; + + // make sure we have the right sprite handles + if ( !m_hSprite1 ) + m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); + if ( !m_hSprite2 ) + m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); + + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); + + if (rc.bottom > rc.top) + { + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); + } + + x += (m_prc1->right - m_prc1->left); + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); + + return 1; } \ No newline at end of file diff --git a/cl_dll/camera.h b/cl_dll/camera.h index 83dc04ff..08c87920 100644 --- a/cl_dll/camera.h +++ b/cl_dll/camera.h @@ -1,24 +1,24 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// Camera.h -- defines and such for a 3rd person camera -// NOTE: must include quakedef.h first - -#ifndef _CAMERA_H_ -#define _CAMERA_H_ - -// pitch, yaw, dist -extern vec3_t cam_ofs; -// Using third person camera -extern int cam_thirdperson; - -void CAM_Init( void ); -void CAM_ClearStates( void ); -void CAM_StartMouseMove(void); -void CAM_EndMouseMove(void); - -#endif // _CAMERA_H_ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Camera.h -- defines and such for a 3rd person camera +// NOTE: must include quakedef.h first + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +// pitch, yaw, dist +extern vec3_t cam_ofs; +// Using third person camera +extern int cam_thirdperson; + +void CAM_Init( void ); +void CAM_ClearStates( void ); +void CAM_StartMouseMove(void); +void CAM_EndMouseMove(void); + +#endif // _CAMERA_H_ diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index ea512306..80fdfe81 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -1,278 +1,278 @@ -/*** -* -* 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.c -// -// this implementation handles the linking of the engine to the DLL -// - -#include "hud.h" -#include "cl_util.h" -#include "netadr.h" - -extern "C" -{ -#include "pm_shared.h" -} - -#include - -cl_enginefunc_t gEngfuncs; -CHud gHUD; -mobile_engfuncs_t *gMobileEngfuncs = NULL; -void InitInput (void); -void EV_HookEvents( void ); -void IN_Commands( void ); - -/* -========================== - Initialize - -Called when the DLL is first loaded. -========================== -*/ -extern "C" -{ -int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); -int DLLEXPORT HUD_VidInit( void ); -void DLLEXPORT HUD_Init( void ); -int DLLEXPORT HUD_Redraw( float flTime, int intermission ); -int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); -void DLLEXPORT HUD_Reset ( void ); -void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ); -void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ); -char DLLEXPORT HUD_PlayerMoveTexture( char *name ); -int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); -int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); -void DLLEXPORT HUD_Frame( double time ); -void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking); -void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ); -void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ); -} - -/* -================================ -HUD_GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch ( hullnumber ) - { - case 0: // Normal player - mins = Vector(-16, -16, -36); - maxs = Vector(16, 16, 36); - iret = 1; - break; - case 1: // Crouched player - mins = Vector(-16, -16, -18 ); - maxs = Vector(16, 16, 18 ); - iret = 1; - break; - case 2: // Point based hull - mins = Vector( 0, 0, 0 ); - maxs = Vector( 0, 0, 0 ); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -HUD_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 DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - // Parse stuff from args - int max_buffer_size = *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; -} - -void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) -{ - PM_Init( ppmove ); -} - -char DLLEXPORT HUD_PlayerMoveTexture( char *name ) -{ - return PM_FindTextureType( name ); -} - -void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) -{ - PM_Move( ppmove, server ); -} - -int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) -{ - gEngfuncs = *pEnginefuncs; - - if (iVersion != CLDLL_INTERFACE_VERSION) - return 0; - - memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); - - EV_HookEvents(); - - return 1; -} - - -/* -========================== - HUD_VidInit - -Called when the game initializes -and whenever the vid_mode is changed -so the HUD can reinitialize itself. -========================== -*/ - -int DLLEXPORT HUD_VidInit( void ) -{ - gHUD.VidInit(); - - return 1; -} - -/* -========================== - HUD_Init - -Called whenever the client connects -to a server. Reinitializes all -the hud variables. -========================== -*/ - -void DLLEXPORT HUD_Init( void ) -{ - InitInput(); - gHUD.Init(); -} - - -/* -========================== - HUD_Redraw - -called every screen frame to -redraw the HUD. -=========================== -*/ - -int DLLEXPORT HUD_Redraw( float time, int intermission ) -{ - gHUD.Redraw( time, intermission ); - - return 1; -} - - -/* -========================== - HUD_UpdateClientData - -called every time shared client -dll/engine data gets changed, -and gives the cdll a chance -to modify the data. - -returns 1 if anything has been changed, 0 otherwise. -========================== -*/ - -int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) -{ - IN_Commands(); - - return gHUD.UpdateClientData(pcldata, flTime ); -} - -/* -========================== - HUD_Reset - -Called at start and end of demos to restore to "non"HUD state. -========================== -*/ - -void DLLEXPORT HUD_Reset( void ) -{ - gHUD.VidInit(); -} - -/* -========================== -HUD_Frame - -Called by engine every frame that client .dll is loaded -========================== -*/ - -void DLLEXPORT HUD_Frame( double time ) -{ -} - - -/* -========================== -HUD_VoiceStatus - -Called when a player starts or stops talking. -========================== -*/ - -void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) -{ - -} - -/* -========================== -HUD_DirectorEvent - -Called when a director event message was received -========================== -*/ - -void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) -{ - gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); -} - -void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ) -{ - if( gpMobileEngfuncs->version != MOBILITY_API_VERSION ) - return; - gMobileEngfuncs = gpMobileEngfuncs; -} +/*** +* +* 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.c +// +// this implementation handles the linking of the engine to the DLL +// + +#include "hud.h" +#include "cl_util.h" +#include "netadr.h" + +extern "C" +{ +#include "pm_shared.h" +} + +#include + +cl_enginefunc_t gEngfuncs; +CHud gHUD; +mobile_engfuncs_t *gMobileEngfuncs = NULL; +void InitInput (void); +void EV_HookEvents( void ); +void IN_Commands( void ); + +/* +========================== + Initialize + +Called when the DLL is first loaded. +========================== +*/ +extern "C" +{ +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); +int DLLEXPORT HUD_VidInit( void ); +void DLLEXPORT HUD_Init( void ); +int DLLEXPORT HUD_Redraw( float flTime, int intermission ); +int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); +void DLLEXPORT HUD_Reset ( void ); +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ); +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ); +char DLLEXPORT HUD_PlayerMoveTexture( char *name ); +int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); +void DLLEXPORT HUD_Frame( double time ); +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking); +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ); +void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ); +} + +/* +================================ +HUD_GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Normal player + mins = Vector(-16, -16, -36); + maxs = Vector(16, 16, 36); + iret = 1; + break; + case 1: // Crouched player + mins = Vector(-16, -16, -18 ); + maxs = Vector(16, 16, 18 ); + iret = 1; + break; + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +HUD_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 DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *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; +} + +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) +{ + PM_Init( ppmove ); +} + +char DLLEXPORT HUD_PlayerMoveTexture( char *name ) +{ + return PM_FindTextureType( name ); +} + +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) +{ + PM_Move( ppmove, server ); +} + +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) +{ + gEngfuncs = *pEnginefuncs; + + if (iVersion != CLDLL_INTERFACE_VERSION) + return 0; + + memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + + EV_HookEvents(); + + return 1; +} + + +/* +========================== + HUD_VidInit + +Called when the game initializes +and whenever the vid_mode is changed +so the HUD can reinitialize itself. +========================== +*/ + +int DLLEXPORT HUD_VidInit( void ) +{ + gHUD.VidInit(); + + return 1; +} + +/* +========================== + HUD_Init + +Called whenever the client connects +to a server. Reinitializes all +the hud variables. +========================== +*/ + +void DLLEXPORT HUD_Init( void ) +{ + InitInput(); + gHUD.Init(); +} + + +/* +========================== + HUD_Redraw + +called every screen frame to +redraw the HUD. +=========================== +*/ + +int DLLEXPORT HUD_Redraw( float time, int intermission ) +{ + gHUD.Redraw( time, intermission ); + + return 1; +} + + +/* +========================== + HUD_UpdateClientData + +called every time shared client +dll/engine data gets changed, +and gives the cdll a chance +to modify the data. + +returns 1 if anything has been changed, 0 otherwise. +========================== +*/ + +int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) +{ + IN_Commands(); + + return gHUD.UpdateClientData(pcldata, flTime ); +} + +/* +========================== + HUD_Reset + +Called at start and end of demos to restore to "non"HUD state. +========================== +*/ + +void DLLEXPORT HUD_Reset( void ) +{ + gHUD.VidInit(); +} + +/* +========================== +HUD_Frame + +Called by engine every frame that client .dll is loaded +========================== +*/ + +void DLLEXPORT HUD_Frame( double time ) +{ +} + + +/* +========================== +HUD_VoiceStatus + +Called when a player starts or stops talking. +========================== +*/ + +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +{ + +} + +/* +========================== +HUD_DirectorEvent + +Called when a director event message was received +========================== +*/ + +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) +{ + gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); +} + +void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ) +{ + if( gpMobileEngfuncs->version != MOBILITY_API_VERSION ) + return; + gMobileEngfuncs = gpMobileEngfuncs; +} diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index 4b28b3a6..de1b5d4a 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -1,46 +1,46 @@ -/*** -* -* 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. -* -****/ -// -// cl_dll.h -// - -// 4-23-98 JOHN - -// -// This DLL is linked by the client when they first initialize. -// This DLL is responsible for the following tasks: -// - Loading the HUD graphics upon initialization -// - Drawing the HUD graphics every frame -// - Handling the custum HUD-update packets -// -typedef unsigned char byte; -typedef unsigned short word; -typedef float vec_t; -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); - -#include "util_vector.h" - -#include "../engine/cdll_int.h" -#include "../dlls/cdll_dll.h" - -#ifndef __MSC_VER -#define _cdecl -#endif -#include "exportdef.h" -#include - -extern cl_enginefunc_t gEngfuncs; -#include "../engine/mobility_int.h" -extern mobile_engfuncs_t *gMobileEngfuncs; +/*** +* +* 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. +* +****/ +// +// cl_dll.h +// + +// 4-23-98 JOHN + +// +// This DLL is linked by the client when they first initialize. +// This DLL is responsible for the following tasks: +// - Loading the HUD graphics upon initialization +// - Drawing the HUD graphics every frame +// - Handling the custum HUD-update packets +// +typedef unsigned char byte; +typedef unsigned short word; +typedef float vec_t; +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); + +#include "util_vector.h" + +#include "../engine/cdll_int.h" +#include "../dlls/cdll_dll.h" + +#ifndef __MSC_VER +#define _cdecl +#endif +#include "exportdef.h" +#include + +extern cl_enginefunc_t gEngfuncs; +#include "../engine/mobility_int.h" +extern mobile_engfuncs_t *gMobileEngfuncs; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 436b122b..aa2cd853 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -1,176 +1,176 @@ -/*** -* -* 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. -* -****/ -// -// cl_util.h -// -#include "exportdef.h" -#include "cvardef.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -// Macros to hook function calls into the HUD object - -#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ - { \ - return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ - } - - -#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); -#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ - { \ - gHUD.y.UserCmd_##x( ); \ - } - - -inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } -inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } -inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } - -#define SPR_Load (*gEngfuncs.pfnSPR_Load) -#define SPR_Set (*gEngfuncs.pfnSPR_Set) -#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) -#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) - -// SPR_Draw draws a the current sprite as solid -#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) -// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) -#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) -// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) -#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) - -// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. -#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) -// SPR_DisableScissor disables the clipping rect -#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) -// -#define FillRGBA (*gEngfuncs.pfnFillRGBA) - - -// ScreenHeight returns the height of the screen, in pixels -#define ScreenHeight (gHUD.m_scrinfo.iHeight) -// ScreenWidth returns the width of the screen, in pixels -#define ScreenWidth (gHUD.m_scrinfo.iWidth) - -// Use this to set any co-ords in 640x480 space -#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) -#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) - -// use this to project world coordinates to screen coordinates -#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f ) -#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f ) - -#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) -#define ServerCmd (*gEngfuncs.pfnServerCmd) -#define ClientCmd (*gEngfuncs.pfnClientCmd) -#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) -#define AngleVectors (*gEngfuncs.pfnAngleVectors) -extern cvar_t *hud_textmode; -extern float g_hud_text_color[3]; -inline void DrawSetTextColor(float r, float g, float b) -{ - if( hud_textmode->value == 1 ) - g_hud_text_color[0]=r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; - else - gEngfuncs.pfnDrawSetTextColor( r, g, b ); -} -// Gets the height & width of a sprite, at the specified frame -inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } -inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } - -inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } -inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) -{ - return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); -} - -inline int DrawConsoleString( int x, int y, const char *string ) -{ - if( hud_textmode->value == 1 ) - return gHUD.DrawHudString( x, y, 9999, (char*)string, 255*g_hud_text_color[0], 255*g_hud_text_color[1], 255*g_hud_text_color[2]); - return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); -} - -inline void GetConsoleStringSize( const char *string, int *width, int *height ) -{ - if( hud_textmode->value == 1 ) - *height = 13, *width = gHUD.DrawHudStringLen( (char*)string ); - else - gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); -} - -inline int ConsoleStringLen( const char *string ) -{ - int _width = 0, _height = 0; - if( hud_textmode->value == 1 ) - return gHUD.DrawHudStringLen((char*)string); - GetConsoleStringSize( string, &_width, &_height ); - return _width; -} - -inline void ConsolePrint( const char *string ) -{ - gEngfuncs.pfnConsolePrint( string ); -} - -inline void CenterPrint( const char *string ) -{ - gEngfuncs.pfnCenterPrint( string ); -} - -// returns the players name of entity no. -#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) - -// sound functions -inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } -inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } - -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) - -void ScaleColors( int &r, int &g, int &b, int a ); - -#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -#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];} -inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} -float Length(const float *v); -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); -void VectorScale (const float *in, float scale, float *out); -float VectorNormalize (float *v); -void VectorInverse ( float *v ); - -extern vec3_t vec3_origin; - -// disable 'possible loss of data converting float to int' warning message -#pragma warning( disable: 4244 ) -// disable 'truncation from 'const double' to 'float' warning message -#pragma warning( disable: 4305 ) - -inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ -{\ - r = (ulRGB & 0xFF0000) >>16;\ - g = (ulRGB & 0xFF00) >> 8;\ - b = ulRGB & 0xFF;\ -} - -HSPRITE LoadSprite(const char *pszName); +/*** +* +* 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. +* +****/ +// +// cl_util.h +// +#include "exportdef.h" +#include "cvardef.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +// Macros to hook function calls into the HUD object + +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); + +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ + { \ + return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } + + +#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + gHUD.y.UserCmd_##x( ); \ + } + + +inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } +inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } +inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } + +#define SPR_Load (*gEngfuncs.pfnSPR_Load) +#define SPR_Set (*gEngfuncs.pfnSPR_Set) +#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) +#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) + +// SPR_Draw draws a the current sprite as solid +#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) +// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) +#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) +// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) +#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) + +// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. +#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) +// SPR_DisableScissor disables the clipping rect +#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) +// +#define FillRGBA (*gEngfuncs.pfnFillRGBA) + + +// ScreenHeight returns the height of the screen, in pixels +#define ScreenHeight (gHUD.m_scrinfo.iHeight) +// ScreenWidth returns the width of the screen, in pixels +#define ScreenWidth (gHUD.m_scrinfo.iWidth) + +// Use this to set any co-ords in 640x480 space +#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) +#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) + +// use this to project world coordinates to screen coordinates +#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f ) +#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f ) + +#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) +#define ServerCmd (*gEngfuncs.pfnServerCmd) +#define ClientCmd (*gEngfuncs.pfnClientCmd) +#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) +#define AngleVectors (*gEngfuncs.pfnAngleVectors) +extern cvar_t *hud_textmode; +extern float g_hud_text_color[3]; +inline void DrawSetTextColor(float r, float g, float b) +{ + if( hud_textmode->value == 1 ) + g_hud_text_color[0]=r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; + else + gEngfuncs.pfnDrawSetTextColor( r, g, b ); +} +// Gets the height & width of a sprite, at the specified frame +inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } +inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } + +inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } +inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) +{ + return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); +} + +inline int DrawConsoleString( int x, int y, const char *string ) +{ + if( hud_textmode->value == 1 ) + return gHUD.DrawHudString( x, y, 9999, (char*)string, 255*g_hud_text_color[0], 255*g_hud_text_color[1], 255*g_hud_text_color[2]); + return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); +} + +inline void GetConsoleStringSize( const char *string, int *width, int *height ) +{ + if( hud_textmode->value == 1 ) + *height = 13, *width = gHUD.DrawHudStringLen( (char*)string ); + else + gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); +} + +inline int ConsoleStringLen( const char *string ) +{ + int _width = 0, _height = 0; + if( hud_textmode->value == 1 ) + return gHUD.DrawHudStringLen((char*)string); + GetConsoleStringSize( string, &_width, &_height ); + return _width; +} + +inline void ConsolePrint( const char *string ) +{ + gEngfuncs.pfnConsolePrint( string ); +} + +inline void CenterPrint( const char *string ) +{ + gEngfuncs.pfnCenterPrint( string ); +} + +// returns the players name of entity no. +#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) + +// sound functions +inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } +inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) + +void ScaleColors( int &r, int &g, int &b, int a ); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#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];} +inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} +float Length(const float *v); +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); +void VectorScale (const float *in, float scale, float *out); +float VectorNormalize (float *v); +void VectorInverse ( float *v ); + +extern vec3_t vec3_origin; + +// disable 'possible loss of data converting float to int' warning message +#pragma warning( disable: 4244 ) +// disable 'truncation from 'const double' to 'float' warning message +#pragma warning( disable: 4305 ) + +inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ +{\ + r = (ulRGB & 0xFF0000) >>16;\ + g = (ulRGB & 0xFF00) >> 8;\ + b = ulRGB & 0xFF;\ +} + +HSPRITE LoadSprite(const char *pszName); diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index 66b1c82d..df84daf8 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -1,277 +1,277 @@ -/*** -* -* 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. -* -****/ - -// Com_Weapons.cpp -// Shared weapons common/shared functions -#include -#include "hud.h" -#include "cl_util.h" -#include "com_weapons.h" - -#include "const.h" -#include "entity_state.h" -#include "r_efx.h" - -// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing -// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be -// updating state info, but not firing events -int g_runfuncs = 0; - -// During our weapon prediction processing, we'll need to reference some data that is part of -// the final state passed into the postthink functionality. We'll set this pointer and then -// reset it to NULL as appropriate -struct local_state_s *g_finalstate = NULL; - -/* -==================== -COM_Log - -Log debug messages to file ( appends ) -==================== -*/ -void COM_Log( char *pszFile, char *fmt, ...) -{ - va_list argptr; - char string[1024]; - FILE *fp; - char *pfilename; - - if ( !pszFile ) - { - pfilename = "c:\\hllog.txt"; - } - else - { - pfilename = pszFile; - } - - va_start (argptr,fmt); - vsprintf (string, fmt,argptr); - va_end (argptr); - - fp = fopen( pfilename, "a+t"); - if (fp) - { - fprintf(fp, "%s", string); - fclose(fp); - } -} - -// remember the current animation for the view model, in case we get out of sync with -// server. -static int g_currentanim; - -/* -===================== -HUD_SendWeaponAnim - -Change weapon model animation -===================== -*/ -void HUD_SendWeaponAnim( int iAnim, int body, int force ) -{ - // Don't actually change it. - if ( !g_runfuncs && !force ) - return; - - g_currentanim = iAnim; - - // Tell animation system new info - gEngfuncs.pfnWeaponAnim( iAnim, body ); -} - -/* -===================== -HUD_GetWeaponAnim - -Retrieve current predicted weapon animation -===================== -*/ -int HUD_GetWeaponAnim( void ) -{ - return g_currentanim; -} - -/* -===================== -HUD_PlaySound - -Play a sound, if we are seeing this command for the first time -===================== -*/ -void HUD_PlaySound( char *sound, float volume ) -{ - if ( !g_runfuncs || !g_finalstate ) - return; - - gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); -} - -/* -===================== -HUD_PlaybackEvent - -Directly queue up an event on the client -===================== -*/ -void HUD_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 ) -{ - vec3_t org; - vec3_t ang; - - if ( !g_runfuncs || !g_finalstate ) - return; - - // Weapon prediction events are assumed to occur at the player's origin - org = g_finalstate->playerstate.origin; - ang = v_angles; - gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); -} - -/* -===================== -HUD_SetMaxSpeed - -===================== -*/ -void HUD_SetMaxSpeed( const edict_t *ed, float speed ) -{ -} - - -/* -===================== -UTIL_WeaponTimeBase - -Always 0.0 on client, even if not predicting weapons ( won't get called - in that case ) -===================== -*/ -float UTIL_WeaponTimeBase( void ) -{ - return 0.0; -} - -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 = high - low; - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -/* -====================== -stub_* - -stub functions for such things as precaching. So we don't have to modify weapons code that - is compiled into both game and client .dlls. -====================== -*/ -int stub_PrecacheModel ( char* s ) { return 0; } -int stub_PrecacheSound ( char* s ) { return 0; } -unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } -const char *stub_NameForFunction ( unsigned long function ) { return "func"; } -void stub_SetModel ( edict_t *e, const char *m ) {} +/*** +* +* 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. +* +****/ + +// Com_Weapons.cpp +// Shared weapons common/shared functions +#include +#include "hud.h" +#include "cl_util.h" +#include "com_weapons.h" + +#include "const.h" +#include "entity_state.h" +#include "r_efx.h" + +// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing +// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be +// updating state info, but not firing events +int g_runfuncs = 0; + +// During our weapon prediction processing, we'll need to reference some data that is part of +// the final state passed into the postthink functionality. We'll set this pointer and then +// reset it to NULL as appropriate +struct local_state_s *g_finalstate = NULL; + +/* +==================== +COM_Log + +Log debug messages to file ( appends ) +==================== +*/ +void COM_Log( char *pszFile, char *fmt, ...) +{ + va_list argptr; + char string[1024]; + FILE *fp; + char *pfilename; + + if ( !pszFile ) + { + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + fp = fopen( pfilename, "a+t"); + if (fp) + { + fprintf(fp, "%s", string); + fclose(fp); + } +} + +// remember the current animation for the view model, in case we get out of sync with +// server. +static int g_currentanim; + +/* +===================== +HUD_SendWeaponAnim + +Change weapon model animation +===================== +*/ +void HUD_SendWeaponAnim( int iAnim, int body, int force ) +{ + // Don't actually change it. + if ( !g_runfuncs && !force ) + return; + + g_currentanim = iAnim; + + // Tell animation system new info + gEngfuncs.pfnWeaponAnim( iAnim, body ); +} + +/* +===================== +HUD_GetWeaponAnim + +Retrieve current predicted weapon animation +===================== +*/ +int HUD_GetWeaponAnim( void ) +{ + return g_currentanim; +} + +/* +===================== +HUD_PlaySound + +Play a sound, if we are seeing this command for the first time +===================== +*/ +void HUD_PlaySound( char *sound, float volume ) +{ + if ( !g_runfuncs || !g_finalstate ) + return; + + gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); +} + +/* +===================== +HUD_PlaybackEvent + +Directly queue up an event on the client +===================== +*/ +void HUD_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 ) +{ + vec3_t org; + vec3_t ang; + + if ( !g_runfuncs || !g_finalstate ) + return; + + // Weapon prediction events are assumed to occur at the player's origin + org = g_finalstate->playerstate.origin; + ang = v_angles; + gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); +} + +/* +===================== +HUD_SetMaxSpeed + +===================== +*/ +void HUD_SetMaxSpeed( const edict_t *ed, float speed ) +{ +} + + +/* +===================== +UTIL_WeaponTimeBase + +Always 0.0 on client, even if not predicting weapons ( won't get called + in that case ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +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 = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +/* +====================== +stub_* + +stub functions for such things as precaching. So we don't have to modify weapons code that + is compiled into both game and client .dlls. +====================== +*/ +int stub_PrecacheModel ( char* s ) { return 0; } +int stub_PrecacheSound ( char* s ) { return 0; } +unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } +const char *stub_NameForFunction ( unsigned long function ) { return "func"; } +void stub_SetModel ( edict_t *e, const char *m ) {} diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index e2fd2749..c924d8b4 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -1,48 +1,48 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// com_weapons.h -// Shared weapons common function prototypes -#if !defined( COM_WEAPONSH ) -#define COM_WEAPONSH -#ifdef _WIN32 -#pragma once -#endif - -#include "hud_iface.h" - -extern "C" -{ - void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); -} - -void COM_Log( char *pszFile, char *fmt, ...); -int CL_IsDead( void ); - -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); - -int HUD_GetWeaponAnim( void ); -void HUD_SendWeaponAnim( int iAnim, int body, int force ); -void HUD_PlaySound( char *sound, float volume ); -void HUD_PlaybackEvent( 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 ); -void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); -int stub_PrecacheModel( char* s ); -int stub_PrecacheSound( char* s ); -unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction ( unsigned long function ); -void stub_SetModel ( struct edict_s *e, const char *m ); - - -extern cvar_t *cl_lw; - -extern int g_runfuncs; -extern vec3_t v_angles; -extern float g_lastFOV; -extern struct local_state_s *g_finalstate; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_weapons.h +// Shared weapons common function prototypes +#if !defined( COM_WEAPONSH ) +#define COM_WEAPONSH +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_iface.h" + +extern "C" +{ + void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +} + +void COM_Log( char *pszFile, char *fmt, ...); +int CL_IsDead( void ); + +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); + +int HUD_GetWeaponAnim( void ); +void HUD_SendWeaponAnim( int iAnim, int body, int force ); +void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaybackEvent( 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 ); +void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); +int stub_PrecacheModel( char* s ); +int stub_PrecacheSound( char* s ); +unsigned short stub_PrecacheEvent( int type, const char *s ); +const char *stub_NameForFunction ( unsigned long function ); +void stub_SetModel ( struct edict_s *e, const char *m ); + + +extern cvar_t *cl_lw; + +extern int g_runfuncs; +extern vec3_t v_angles; +extern float g_lastFOV; +extern struct local_state_s *g_finalstate; + #endif \ No newline at end of file diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index fdeaae46..97d4900e 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -1,304 +1,304 @@ -/*** -* -* 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. -* -****/ -// -// death notice -// -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - -DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); - -struct DeathNoticeItem { - char szKiller[MAX_PLAYER_NAME_LENGTH*2]; - char szVictim[MAX_PLAYER_NAME_LENGTH*2]; - int iId; // the index number of the associated sprite - int iSuicide; - int iTeamKill; - int iNonPlayerKill; - float flDisplayTime; - float *KillerColor; - float *VictimColor; -}; - -#define MAX_DEATHNOTICES 4 -static int DEATHNOTICE_DISPLAY_TIME = 6; - -#define DEATHNOTICE_TOP 32 - -DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; - -float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; -float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; -float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; -float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; -float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; - -float *GetClientColor( int clientIndex ) -{ - switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) - { - case 1: return g_ColorBlue; - case 2: return g_ColorRed; - case 3: return g_ColorYellow; - case 4: return g_ColorGreen; - case 0: return g_ColorYellow; - - default : return g_ColorGrey; - } - - return NULL; -} - -int CHudDeathNotice :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( DeathMsg ); - - CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); - - return 1; -} - - -void CHudDeathNotice :: InitHUDData( void ) -{ - memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); -} - - -int CHudDeathNotice :: VidInit( void ) -{ - m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); - - return 1; -} - -int CHudDeathNotice :: Draw( float flTime ) -{ - int x, y, r, g, b; - - for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if ( rgDeathNoticeList[i].iId == 0 ) - break; // we've gone through them all - - if ( rgDeathNoticeList[i].flDisplayTime < flTime ) - { // display time has expired - // remove the current item from the list - memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); - i--; // continue on the next item; stop the counter getting incremented - continue; - } - - rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); - - // Only draw if the viewport will let me - // vgui dropped out - //if ( gViewPort && gViewPort->AllowedToPrintText() ) - { - // Draw the death notice - y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!! - - int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; - x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - if ( !rgDeathNoticeList[i].iSuicide ) - { - x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); - - // Draw killers name - if ( rgDeathNoticeList[i].KillerColor ) - DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); - x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); - } - - r = 255; g = 80; b = 0; - if ( rgDeathNoticeList[i].iTeamKill ) - { - r = 10; g = 240; b = 10; // display it in sickly green - } - - // Draw death weapon - SPR_Set( gHUD.GetSprite(id), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); - - x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - // Draw victims name (if it was a player that was killed) - if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) - { - if ( rgDeathNoticeList[i].VictimColor ) - DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); - x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); - } - } - } - - return 1; -} - -// This message handler may be better off elsewhere -int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) -{ +/*** +* +* 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. +* +****/ +// +// death notice +// +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); + +struct DeathNoticeItem { + char szKiller[MAX_PLAYER_NAME_LENGTH*2]; + char szVictim[MAX_PLAYER_NAME_LENGTH*2]; + int iId; // the index number of the associated sprite + int iSuicide; + int iTeamKill; + int iNonPlayerKill; + float flDisplayTime; + float *KillerColor; + float *VictimColor; +}; + +#define MAX_DEATHNOTICES 4 +static int DEATHNOTICE_DISPLAY_TIME = 6; + +#define DEATHNOTICE_TOP 32 + +DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; + +float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; +float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; +float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; +float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; +float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; + +float *GetClientColor( int clientIndex ) +{ + switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) + { + case 1: return g_ColorBlue; + case 2: return g_ColorRed; + case 3: return g_ColorYellow; + case 4: return g_ColorGreen; + case 0: return g_ColorYellow; + + default : return g_ColorGrey; + } + + return NULL; +} + +int CHudDeathNotice :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( DeathMsg ); + + CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); + + return 1; +} + + +void CHudDeathNotice :: InitHUDData( void ) +{ + memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); +} + + +int CHudDeathNotice :: VidInit( void ) +{ + m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); + + return 1; +} + +int CHudDeathNotice :: Draw( float flTime ) +{ + int x, y, r, g, b; + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; // we've gone through them all + + if ( rgDeathNoticeList[i].flDisplayTime < flTime ) + { // display time has expired + // remove the current item from the list + memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); + i--; // continue on the next item; stop the counter getting incremented + continue; + } + + rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); + + // Only draw if the viewport will let me + // vgui dropped out + //if ( gViewPort && gViewPort->AllowedToPrintText() ) + { + // Draw the death notice + y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!! + + int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + if ( !rgDeathNoticeList[i].iSuicide ) + { + x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + + // Draw killers name + if ( rgDeathNoticeList[i].KillerColor ) + DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + } + + r = 255; g = 80; b = 0; + if ( rgDeathNoticeList[i].iTeamKill ) + { + r = 10; g = 240; b = 10; // display it in sickly green + } + + // Draw death weapon + SPR_Set( gHUD.GetSprite(id), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); + + x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + // Draw victims name (if it was a player that was killed) + if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + { + if ( rgDeathNoticeList[i].VictimColor ) + DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); + } + } + } + + return 1; +} + +// This message handler may be better off elsewhere +int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) +{ int i; - m_iFlags |= HUD_ACTIVE; - - BEGIN_READ( pbuf, iSize ); - - int killer = READ_BYTE(); - int victim = READ_BYTE(); - - char killedwith[32]; - strcpy( killedwith, "d_" ); - strncat( killedwith, READ_STRING(), 32 ); - - - gHUD.m_Spectator.DeathMessage(victim); - - for ( i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if ( rgDeathNoticeList[i].iId == 0 ) - break; - } - if ( i == MAX_DEATHNOTICES ) - { // move the rest of the list forward to make room for this item - memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); - i = MAX_DEATHNOTICES - 1; - } - - //if (gViewPort) - // gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - - - // Get the Killer's name - char *killer_name = g_PlayerInfoList[ killer ].name; - if ( !killer_name ) - { - killer_name = ""; - rgDeathNoticeList[i].szKiller[0] = 0; - } - else - { - rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); - strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; - } - - // Get the Victim's name - char *victim_name = NULL; - // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) - if ( ((char)victim) != -1 ) - victim_name = g_PlayerInfoList[ victim ].name; - if ( !victim_name ) - { - victim_name = ""; - rgDeathNoticeList[i].szVictim[0] = 0; - } - else - { - rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); - strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; - } - - // Is it a non-player object kill? - if ( ((char)victim) == -1 ) - { - rgDeathNoticeList[i].iNonPlayerKill = TRUE; - - // Store the object's name in the Victim slot (skip the d_ bit) - strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); - } - else - { - if ( killer == victim || killer == 0 ) - rgDeathNoticeList[i].iSuicide = TRUE; - - if ( !strcmp( killedwith, "d_teammate" ) ) - rgDeathNoticeList[i].iTeamKill = TRUE; - } - - // Find the sprite in the list - int spr = gHUD.GetSpriteIndex( killedwith ); - - rgDeathNoticeList[i].iId = spr; - - DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); - rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; - - if (rgDeathNoticeList[i].iNonPlayerKill) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed a " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - ConsolePrint( "\n" ); - } - else - { - // record the death notice in the console - if ( rgDeathNoticeList[i].iSuicide ) - { - ConsolePrint( rgDeathNoticeList[i].szVictim ); - - if ( !strcmp( killedwith, "d_world" ) ) - { - ConsolePrint( " died" ); - } - else - { - ConsolePrint( " killed self" ); - } - } - else if ( rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed his teammate " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - else - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - - if ( *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( " with " ); - - // replace the code names with the 'real' names - if ( !strcmp( killedwith+2, "egon" ) ) - strcpy( killedwith, "d_gluon gun" ); - if ( !strcmp( killedwith+2, "gauss" ) ) - strcpy( killedwith, "d_tau cannon" ); - - ConsolePrint( killedwith+2 ); // skip over the "d_" part - } - - ConsolePrint( "\n" ); - } - - return 1; -} - - - - + m_iFlags |= HUD_ACTIVE; + + BEGIN_READ( pbuf, iSize ); + + int killer = READ_BYTE(); + int victim = READ_BYTE(); + + char killedwith[32]; + strcpy( killedwith, "d_" ); + strncat( killedwith, READ_STRING(), 32 ); + + + gHUD.m_Spectator.DeathMessage(victim); + + for ( i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; + } + if ( i == MAX_DEATHNOTICES ) + { // move the rest of the list forward to make room for this item + memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); + i = MAX_DEATHNOTICES - 1; + } + + //if (gViewPort) + // gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + // Get the Killer's name + char *killer_name = g_PlayerInfoList[ killer ].name; + if ( !killer_name ) + { + killer_name = ""; + rgDeathNoticeList[i].szKiller[0] = 0; + } + else + { + rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); + strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Get the Victim's name + char *victim_name = NULL; + // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) + if ( ((char)victim) != -1 ) + victim_name = g_PlayerInfoList[ victim ].name; + if ( !victim_name ) + { + victim_name = ""; + rgDeathNoticeList[i].szVictim[0] = 0; + } + else + { + rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); + strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Is it a non-player object kill? + if ( ((char)victim) == -1 ) + { + rgDeathNoticeList[i].iNonPlayerKill = TRUE; + + // Store the object's name in the Victim slot (skip the d_ bit) + strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); + } + else + { + if ( killer == victim || killer == 0 ) + rgDeathNoticeList[i].iSuicide = TRUE; + + if ( !strcmp( killedwith, "d_teammate" ) ) + rgDeathNoticeList[i].iTeamKill = TRUE; + } + + // Find the sprite in the list + int spr = gHUD.GetSpriteIndex( killedwith ); + + rgDeathNoticeList[i].iId = spr; + + DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); + rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; + + if (rgDeathNoticeList[i].iNonPlayerKill) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed a " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + ConsolePrint( "\n" ); + } + else + { + // record the death notice in the console + if ( rgDeathNoticeList[i].iSuicide ) + { + ConsolePrint( rgDeathNoticeList[i].szVictim ); + + if ( !strcmp( killedwith, "d_world" ) ) + { + ConsolePrint( " died" ); + } + else + { + ConsolePrint( " killed self" ); + } + } + else if ( rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed his teammate " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + else + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + + if ( *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( " with " ); + + // replace the code names with the 'real' names + if ( !strcmp( killedwith+2, "egon" ) ) + strcpy( killedwith, "d_gluon gun" ); + if ( !strcmp( killedwith+2, "gauss" ) ) + strcpy( killedwith, "d_tau cannon" ); + + ConsolePrint( killedwith+2 ); // skip over the "d_" part + } + + ConsolePrint( "\n" ); + } + + return 1; +} + + + + diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp index a62b239f..dfa7f8ef 100644 --- a/cl_dll/demo.cpp +++ b/cl_dll/demo.cpp @@ -1,101 +1,101 @@ -/*** -* -* 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 "hud.h" -#include "cl_util.h" -#include "demo.h" -#include "demo_api.h" -#include - -int g_demosniper = 0; -int g_demosniperdamage = 0; -float g_demosniperorg[3]; -float g_demosniperangles[3]; -float g_demozoom; - -// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. - -extern "C" -{ - void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ); -} - -/* -===================== -Demo_WriteBuffer - -Write some data to the demo stream -===================== -*/ -void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) -{ - int pos = 0; - unsigned char buf[ 32 * 1024 ]; - *( int * )&buf[pos] = type; - pos+=sizeof( int ); - - memcpy( &buf[pos], buffer, size ); - - // Write full buffer out - gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); -} - -/* -===================== -Demo_ReadBuffer - -Engine wants us to parse some data from the demo stream -===================== -*/ -void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) -{ - int type; - int i = 0; - - type = *( int * )buffer; - i += sizeof( int ); - switch ( type ) - { - case TYPE_SNIPERDOT: - g_demosniper = *(int * )&buffer[ i ]; - i += sizeof( int ); - - if ( g_demosniper ) - { - g_demosniperdamage = *( int * )&buffer[ i ]; - i += sizeof( int ); - - g_demosniperangles[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); - } - break; - case TYPE_ZOOM: - g_demozoom = *(float * )&buffer[ i ]; - i += sizeof( float ); - break; - default: - gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); - break; - } -} +/*** +* +* 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 "hud.h" +#include "cl_util.h" +#include "demo.h" +#include "demo_api.h" +#include + +int g_demosniper = 0; +int g_demosniperdamage = 0; +float g_demosniperorg[3]; +float g_demosniperangles[3]; +float g_demozoom; + +// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. + +extern "C" +{ + void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ); +} + +/* +===================== +Demo_WriteBuffer + +Write some data to the demo stream +===================== +*/ +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) +{ + int pos = 0; + unsigned char buf[ 32 * 1024 ]; + *( int * )&buf[pos] = type; + pos+=sizeof( int ); + + memcpy( &buf[pos], buffer, size ); + + // Write full buffer out + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); +} + +/* +===================== +Demo_ReadBuffer + +Engine wants us to parse some data from the demo stream +===================== +*/ +void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) +{ + int type; + int i = 0; + + type = *( int * )buffer; + i += sizeof( int ); + switch ( type ) + { + case TYPE_SNIPERDOT: + g_demosniper = *(int * )&buffer[ i ]; + i += sizeof( int ); + + if ( g_demosniper ) + { + g_demosniperdamage = *( int * )&buffer[ i ]; + i += sizeof( int ); + + g_demosniperangles[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + } + break; + case TYPE_ZOOM: + g_demozoom = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + default: + gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); + break; + } +} diff --git a/cl_dll/demo.h b/cl_dll/demo.h index c5a5057b..3163ef38 100644 --- a/cl_dll/demo.h +++ b/cl_dll/demo.h @@ -1,27 +1,27 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( DEMOH ) -#define DEMOH -#pragma once - -// Types of demo messages we can write/parse -enum -{ - TYPE_SNIPERDOT = 0, - TYPE_ZOOM -}; - -void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); - -extern int g_demosniper; -extern int g_demosniperdamage; -extern float g_demosniperorg[3]; -extern float g_demosniperangles[3]; -extern float g_demozoom; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( DEMOH ) +#define DEMOH +#pragma once + +// Types of demo messages we can write/parse +enum +{ + TYPE_SNIPERDOT = 0, + TYPE_ZOOM +}; + +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); + +extern int g_demosniper; +extern int g_demosniperdamage; +extern float g_demosniperorg[3]; +extern float g_demosniperangles[3]; +extern float g_demozoom; + #endif \ No newline at end of file diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index fb5770c6..0228e70d 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -1,974 +1,974 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// Client side entity management functions - -#include - -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "entity_types.h" -#include "studio_event.h" // def. of mstudioevent_t -#include "r_efx.h" -#include "event_api.h" -#include "pm_defs.h" -#include "pmtrace.h" -#include "pm_shared.h" - - -void Game_AddObjects( void ); - -extern vec3_t v_origin; - -int g_iAlive = 1; - -extern "C" -{ - int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); - void DLLEXPORT HUD_CreateEntities( void ); - void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); - void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); - void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); - void DLLEXPORT HUD_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 ); - void DLLEXPORT HUD_TempEntUpdate( 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 ) ); - struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index ); -} - -/* -======================== -HUD_AddEntity - Return 0 to filter entity from visible list for rendering -======================== -*/ -int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) -{ - switch ( type ) - { - case ET_NORMAL: - case ET_PLAYER: - case ET_BEAM: - case ET_TEMPENTITY: - case ET_FRAGMENTED: - default: - break; - } - // each frame every entity passes this function, so the overview hooks it to filter the overview entities - // in spectator mode: - // each frame every entity passes this function, so the overview hooks - // it to filter the overview entities - - if ( g_iUser1 ) - { - gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); - - if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && - ent->index == g_iUser2 ) - return 0; // don't draw the player we are following in eye - - } - - return 1; -} - -/* -========================= -HUD_TxferLocalOverrides - -The server sends us our origin with extra precision as part of the clientdata structure, not during the normal -playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate -structure, we need to copy them into the state structure at this point. -========================= -*/ -void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) -{ - VectorCopy( client->origin, state->origin ); - - // Spectator - state->iuser1 = client->iuser1; - state->iuser2 = client->iuser2; - - // Duck prevention - state->iuser3 = client->iuser3; - - // Fire prevention - state->iuser4 = client->iuser4; -} - -/* -========================= -HUD_ProcessPlayerState - -We have received entity_state_t for this player over the network. We need to copy appropriate fields to the -playerstate structure -========================= -*/ -void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) -{ - // Copy in network data - VectorCopy( src->origin, dst->origin ); - VectorCopy( src->angles, dst->angles ); - - VectorCopy( src->velocity, dst->velocity ); - - dst->frame = src->frame; - dst->modelindex = src->modelindex; - dst->skin = src->skin; - dst->effects = src->effects; - dst->weaponmodel = src->weaponmodel; - dst->movetype = src->movetype; - dst->sequence = src->sequence; - dst->animtime = src->animtime; - - dst->solid = src->solid; - - dst->rendermode = src->rendermode; - dst->renderamt = src->renderamt; - dst->rendercolor.r = src->rendercolor.r; - dst->rendercolor.g = src->rendercolor.g; - dst->rendercolor.b = src->rendercolor.b; - dst->renderfx = src->renderfx; - - dst->framerate = src->framerate; - dst->body = src->body; - - memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); - memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); - - VectorCopy( src->basevelocity, dst->basevelocity ); - - dst->friction = src->friction; - dst->gravity = src->gravity; - dst->gaitsequence = src->gaitsequence; - dst->spectator = src->spectator; - dst->usehull = src->usehull; - dst->playerclass = src->playerclass; - dst->team = src->team; - dst->colormap = src->colormap; - - // Save off some data so other areas of the Client DLL can get to it - cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index - if ( dst->number == player->index ) - { - g_iPlayerClass = dst->playerclass; - g_iTeamNumber = dst->team; - - g_iUser1 = src->iuser1; - g_iUser2 = src->iuser2; - g_iUser3 = src->iuser3; - } -} - -/* -========================= -HUD_TxferPredictionData - -Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in - from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's - up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server - update is occupying. -========================= -*/ -void DLLEXPORT HUD_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 ) -{ - ps->oldbuttons = pps->oldbuttons; - ps->flFallVelocity = pps->flFallVelocity; - ps->iStepLeft = pps->iStepLeft; - ps->playerclass = pps->playerclass; - - pcd->viewmodel = ppcd->viewmodel; - pcd->m_iId = ppcd->m_iId; - pcd->ammo_shells = ppcd->ammo_shells; - pcd->ammo_nails = ppcd->ammo_nails; - pcd->ammo_cells = ppcd->ammo_cells; - pcd->ammo_rockets = ppcd->ammo_rockets; - pcd->m_flNextAttack = ppcd->m_flNextAttack; - pcd->fov = ppcd->fov; - pcd->weaponanim = ppcd->weaponanim; - pcd->tfstate = ppcd->tfstate; - pcd->maxspeed = ppcd->maxspeed; - - pcd->deadflag = ppcd->deadflag; - - // Spectating or not dead == get control over view angles. - g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; - - // Spectator - pcd->iuser1 = ppcd->iuser1; - pcd->iuser2 = ppcd->iuser2; - - // Duck prevention - pcd->iuser3 = ppcd->iuser3; - - if ( gEngfuncs.IsSpectateOnly() ) - { - // in specator mode we tell the engine who we want to spectate and how - // iuser3 is not used for duck prevention (since the spectator can't duck at all) - pcd->iuser1 = g_iUser1; // observer mode - pcd->iuser2 = g_iUser2; // first target - pcd->iuser3 = g_iUser3; // second target - - } - - // Fire prevention - pcd->iuser4 = ppcd->iuser4; - - pcd->fuser2 = ppcd->fuser2; - pcd->fuser3 = ppcd->fuser3; - - VectorCopy( ppcd->vuser1, pcd->vuser1 ); - VectorCopy( ppcd->vuser2, pcd->vuser2 ); - VectorCopy( ppcd->vuser3, pcd->vuser3 ); - VectorCopy( ppcd->vuser4, pcd->vuser4 ); - - memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); -} - -/* -//#define TEST_IT -#if defined( TEST_IT ) - -cl_entity_t mymodel[9]; - -void MoveModel( void ) -{ - cl_entity_t *player; - int i, j; - int modelindex; - struct model_s *mod; - - // Load it up with some bogus data - player = gEngfuncs.GetLocalPlayer(); - if ( !player ) - return; - - mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - for ( i = 0; i < 3; i++ ) - { - for ( j = 0; j < 3; j++ ) - { - // Don't draw over ourself... - if ( ( i == 1 ) && ( j == 1 ) ) - continue; - - mymodel[ i * 3 + j ] = *player; - - mymodel[ i * 3 + j ].player = 0; - - mymodel[ i * 3 + j ].model = mod; - mymodel[ i * 3 + j ].curstate.modelindex = modelindex; - - // Move it out a bit - mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); - mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); - } - } - -} - -#endif - -//#define TRACE_TEST -#if defined( TRACE_TEST ) - -extern int hitent; - -cl_entity_t hit; - -void TraceModel( void ) -{ - cl_entity_t *ent; - - if ( hitent <= 0 ) - return; - - // Load it up with some bogus data - ent = gEngfuncs.GetEntityByIndex( hitent ); - if ( !ent ) - return; - - hit = *ent; - //hit.curstate.rendermode = kRenderTransTexture; - //hit.curstate.renderfx = kRenderFxGlowShell; - //hit.curstate.renderamt = 100; - - hit.origin[2] += 40; - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); -} - -#endif -*/ - -/* -void ParticleCallback( struct particle_s *particle, float frametime ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - particle->org[ i ] += particle->vel[ i ] * frametime; - } -} - -cvar_t *color = NULL; -void Particles( void ) -{ - static float lasttime; - float curtime; - - curtime = gEngfuncs.GetClientTime(); - - if ( ( curtime - lasttime ) < 2.0 ) - return; - - if ( !color ) - { - color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); - } - - lasttime = curtime; - - // Create a few particles - particle_t *p; - int i, j; - - for ( i = 0; i < 1000; i++ ) - { - int r, g, b; - p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); - if ( !p ) - break; - - for ( j = 0; j < 3; j++ ) - { - p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; - p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); - } - - if ( color ) - { - sscanf( color->string, "%i %i %i", &r, &g, &b ); - } - else - { - r = 192; - g = 0; - b = 0; - } - - p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); - gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); - - // p->die is set to current time so all you have to do is add an additional time to it - p->die += 3.0; - } -} -*/ - -/* -void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; - } -} - -void TempEnts( void ) -{ - static float lasttime; - float curtime; - - curtime = gEngfuncs.GetClientTime(); - - if ( ( curtime - lasttime ) < 10.0 ) - return; - - lasttime = curtime; - - TEMPENTITY *p; - int i, j; - struct model_s *mod; - vec3_t origin; - int index; - - mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); - - for ( i = 0; i < 100; i++ ) - { - for ( j = 0; j < 3; j++ ) - { - origin[ j ] = v_origin[ j ]; - if ( j != 2 ) - { - origin[ j ] += 75; - } - } - - p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); - if ( !p ) - break; - - for ( j = 0; j < 3; j++ ) - { - p->entity.curstate.origin[ j ] = origin[ j ]; - - // Store velocity in baseline origin - p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); - } - - // p->die is set to current time so all you have to do is add an additional time to it - p->die += 10.0; - } -} -*/ - -#if defined( BEAM_TEST ) -// Note can't index beam[ 0 ] in Beam callback, so don't use that index -// Room for 1 beam ( 0 can't be used ) -static cl_entity_t beams[ 2 ]; - -void BeamEndModel( void ) -{ - cl_entity_t *player, *model; - int modelindex; - struct model_s *mod; - - // Load it up with some bogus data - player = gEngfuncs.GetLocalPlayer(); - if ( !player ) - return; - - mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - if ( !mod ) - return; - - // Slot 1 - model = &beams[ 1 ]; - - *model = *player; - model->player = 0; - model->model = mod; - model->curstate.modelindex = modelindex; - - // Move it out a bit - model->origin[0] = player->origin[0] - 100; - model->origin[1] = player->origin[1]; - - model->attachment[0] = model->origin; - model->attachment[1] = model->origin; - model->attachment[2] = model->origin; - model->attachment[3] = model->origin; - - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); -} - -void Beams( void ) -{ - static float lasttime; - float curtime; - struct model_s *mod; - int index; - - BeamEndModel(); - - curtime = gEngfuncs.GetClientTime(); - float end[ 3 ]; - - if ( ( curtime - lasttime ) < 10.0 ) - return; - - mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); - if ( !mod ) - return; - - lasttime = curtime; - - end [ 0 ] = v_origin.x + 100; - end [ 1 ] = v_origin.y + 100; - end [ 2 ] = v_origin.z; - - BEAM *p1; - p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, - 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); -} -#endif - -/* -========================= -HUD_CreateEntities - -Gives us a chance to add additional entities to the render this frame -========================= -*/ -void DLLEXPORT HUD_CreateEntities( void ) -{ - // e.g., create a persistent cl_entity_t somewhere. - // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) - // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list -/* -#if defined( TEST_IT ) - MoveModel(); -#endif - -#if defined( TRACE_TEST ) - TraceModel(); -#endif -*/ -/* - Particles(); -*/ -/* - TempEnts(); -*/ - -#if defined( BEAM_TEST ) - Beams(); -#endif - - // Add in any game specific objects - Game_AddObjects(); -} - -/* -========================= -HUD_StudioEvent - -The entity's studio model description indicated an event was -fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) -========================= -*/ -void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) -{ - switch( event->event ) - { - case 5001: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); - break; - case 5011: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); - break; - case 5021: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); - break; - case 5031: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); - break; - case 5002: - gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); - break; - // Client side sound - case 5004: - gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); - break; - default: - break; - } -} - -/* -================= -CL_UpdateTEnts - -Simulation and cleanup of temporary entities -================= -*/ -void DLLEXPORT HUD_TempEntUpdate ( - double frametime, // Simulation time - double client_time, // Absolute time on client - double cl_gravity, // True gravity on client - TEMPENTITY **ppTempEntFree, // List of freed temporary ents - TEMPENTITY **ppTempEntActive, // List - int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), - void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) -{ - static int gTempEntFrame = 0; - int i; - TEMPENTITY *pTemp, *pnext, *pprev; - float freq, gravity, gravitySlow, life, fastFreq; - - // Nothing to simulate - if ( !*ppTempEntActive ) - return; - - // in order to have tents collide with players, we have to run the player prediction code so - // that the client has the player list. We run this code once when we detect any COLLIDEALL - // tent, then set this BOOL to true so the code doesn't get run again if there's more than - // one COLLIDEALL ent for this update. (often are). - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); - - // !!!BUGBUG -- This needs to be time based - gTempEntFrame = (gTempEntFrame+1) & 31; - - pTemp = *ppTempEntActive; - - // !!! Don't simulate while paused.... This is sort of a hack, revisit. - if ( frametime <= 0 ) - { - while ( pTemp ) - { - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - Callback_AddVisibleEntity( &pTemp->entity ); - } - pTemp = pTemp->next; - } - goto finish; - } - - pprev = NULL; - freq = client_time * 0.01; - fastFreq = client_time * 5.5; - gravity = -frametime * cl_gravity; - gravitySlow = gravity * 0.5; - - while ( pTemp ) - { - int active; - - active = 1; - - life = pTemp->die - client_time; - pnext = pTemp->next; - if ( life < 0 ) - { - if ( pTemp->flags & FTENT_FADEOUT ) - { - if (pTemp->entity.curstate.rendermode == kRenderNormal) - pTemp->entity.curstate.rendermode = kRenderTransTexture; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); - if ( pTemp->entity.curstate.renderamt <= 0 ) - active = 0; - - } - else - active = 0; - } - if ( !active ) // Kill it - { - pTemp->next = *ppTempEntFree; - *ppTempEntFree = pTemp; - if ( !pprev ) // Deleting at head of list - *ppTempEntActive = pnext; - else - pprev->next = pnext; - } - else - { - pprev = pTemp; - - VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // Adjust speed if it's time - // Scale is next think time - if ( client_time > pTemp->entity.baseline.scale ) - { - // Show Sparks - gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); - - // Reduce life - pTemp->entity.baseline.framerate -= 0.1; - - if ( pTemp->entity.baseline.framerate <= 0.0 ) - { - pTemp->die = client_time; - } - else - { - // So it will die no matter what - pTemp->die = client_time + 0.5; - - // Next think - pTemp->entity.baseline.scale = client_time + 0.1; - } - } - } - else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) - { - cl_entity_t *pClient; - - pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); - - VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); - } - else if ( pTemp->flags & FTENT_SINEWAVE ) - { - pTemp->x += pTemp->entity.baseline.origin[0] * frametime; - pTemp->y += pTemp->entity.baseline.origin[1] * frametime; - - pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); - pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; - } - else if ( pTemp->flags & FTENT_SPIRAL ) - { - float s, c; - s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); - c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); - - pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)(size_t)pTemp ); - pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)(size_t)pTemp ); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; - } - - else - { - for ( i = 0; i < 3; i++ ) - pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; - } - - if ( pTemp->flags & FTENT_SPRANIMATE ) - { - pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - - if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) - { - // this animating sprite isn't set to loop, so destroy it. - pTemp->die = client_time; - pTemp = pnext; - continue; - } - } - } - else if ( pTemp->flags & FTENT_SPRCYCLE ) - { - pTemp->entity.curstate.frame += frametime * 10; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - } - } -// Experiment -#if 0 - if ( pTemp->flags & FTENT_SCALE ) - pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); -#endif - - if ( pTemp->flags & FTENT_ROTATE ) - { - pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; - pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; - pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; - - VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); - } - - if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) - { - vec3_t traceNormal; - float traceFraction = 1; - - if ( pTemp->flags & FTENT_COLLIDEALL ) - { - pmtrace_t pmtrace; - physent_t *pe; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); - - - if ( pmtrace.fraction != 1 ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); - - if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) - { - traceFraction = pmtrace.fraction; - VectorCopy( pmtrace.plane.normal, traceNormal ); - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - } - else if ( pTemp->flags & FTENT_COLLIDEWORLD ) - { - pmtrace_t pmtrace; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); - - if ( pmtrace.fraction != 1 ) - { - traceFraction = pmtrace.fraction; - VectorCopy( pmtrace.plane.normal, traceNormal ); - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // Chop spark speeds a bit more - // - VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); - - if ( Length( pTemp->entity.baseline.origin ) < 10 ) - { - pTemp->entity.baseline.framerate = 0.0; - } - } - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - - if ( traceFraction != 1 ) // Decent collision now, and damping works - { - float proj, damp; - - // Place at contact point - VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); - // Damp velocity - damp = pTemp->bounceFactor; - if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) - { - damp *= 0.5; - if ( traceNormal[2] > 0.9 ) // Hit floor? - { - if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) - { - damp = 0; // Stop - pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); - pTemp->entity.angles[0] = 0; - pTemp->entity.angles[2] = 0; - } - } - } - - if (pTemp->hitSound) - { - Callback_TempEntPlaySound(pTemp, damp); - } - - if (pTemp->flags & FTENT_COLLIDEKILL) - { - // die on impact - pTemp->flags &= ~FTENT_FADEOUT; - pTemp->die = client_time; - } - else - { - // Reflect velocity - if ( damp != 0 ) - { - proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); - VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); - // Reflect rotation (fake) - - pTemp->entity.angles[1] = -pTemp->entity.angles[1]; - } - - if ( damp != 1 ) - { - - VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); - VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); - } - } - } - } - - - if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) - { - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); - VectorCopy (pTemp->entity.origin, dl->origin); - dl->radius = 60; - dl->color.r = 255; - dl->color.g = 120; - dl->color.b = 0; - dl->die = client_time + 0.01; - } - - if ( pTemp->flags & FTENT_SMOKETRAIL ) - { - gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); - } - - if ( pTemp->flags & FTENT_GRAVITY ) - pTemp->entity.baseline.origin[2] += gravity; - else if ( pTemp->flags & FTENT_SLOWGRAVITY ) - pTemp->entity.baseline.origin[2] += gravitySlow; - - if ( pTemp->flags & FTENT_CLIENTCUSTOM ) - { - if ( pTemp->callback ) - { - ( *pTemp->callback )( pTemp, frametime, client_time ); - } - } - - // Cull to PVS (not frustum cull, just PVS) - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) - { - if ( !(pTemp->flags & FTENT_PERSIST) ) - { - pTemp->die = client_time; // If we can't draw it this frame, just dump it. - pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die - } - } - } - } - pTemp = pnext; - } - -finish: - // Restore state info - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -/* -================= -HUD_GetUserEntity - -If you specify negative numbers for beam start and end point entities, then - the engine will call back into this function requesting a pointer to a cl_entity_t - object that describes the entity to attach the beam onto. - -Indices must start at 1, not zero. -================= -*/ -cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) -{ -#if defined( BEAM_TEST ) - // None by default, you would return a valic pointer if you create a client side - // beam and attach it to a client side entity. - if ( index > 0 && index <= 1 ) - { - return &beams[ index ]; - } - else - { - return NULL; - } -#else - return NULL; -#endif -} - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Client side entity management functions + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_types.h" +#include "studio_event.h" // def. of mstudioevent_t +#include "r_efx.h" +#include "event_api.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "pm_shared.h" + + +void Game_AddObjects( void ); + +extern vec3_t v_origin; + +int g_iAlive = 1; + +extern "C" +{ + int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void DLLEXPORT HUD_CreateEntities( void ); + void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); + void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); + void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); + void DLLEXPORT HUD_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 ); + void DLLEXPORT HUD_TempEntUpdate( 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 ) ); + struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index ); +} + +/* +======================== +HUD_AddEntity + Return 0 to filter entity from visible list for rendering +======================== +*/ +int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) +{ + switch ( type ) + { + case ET_NORMAL: + case ET_PLAYER: + case ET_BEAM: + case ET_TEMPENTITY: + case ET_FRAGMENTED: + default: + break; + } + // each frame every entity passes this function, so the overview hooks it to filter the overview entities + // in spectator mode: + // each frame every entity passes this function, so the overview hooks + // it to filter the overview entities + + if ( g_iUser1 ) + { + gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && + ent->index == g_iUser2 ) + return 0; // don't draw the player we are following in eye + + } + + return 1; +} + +/* +========================= +HUD_TxferLocalOverrides + +The server sends us our origin with extra precision as part of the clientdata structure, not during the normal +playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate +structure, we need to copy them into the state structure at this point. +========================= +*/ +void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) +{ + VectorCopy( client->origin, state->origin ); + + // Spectator + state->iuser1 = client->iuser1; + state->iuser2 = client->iuser2; + + // Duck prevention + state->iuser3 = client->iuser3; + + // Fire prevention + state->iuser4 = client->iuser4; +} + +/* +========================= +HUD_ProcessPlayerState + +We have received entity_state_t for this player over the network. We need to copy appropriate fields to the +playerstate structure +========================= +*/ +void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) +{ + // Copy in network data + VectorCopy( src->origin, dst->origin ); + VectorCopy( src->angles, dst->angles ); + + VectorCopy( src->velocity, dst->velocity ); + + dst->frame = src->frame; + dst->modelindex = src->modelindex; + dst->skin = src->skin; + dst->effects = src->effects; + dst->weaponmodel = src->weaponmodel; + dst->movetype = src->movetype; + dst->sequence = src->sequence; + dst->animtime = src->animtime; + + dst->solid = src->solid; + + dst->rendermode = src->rendermode; + dst->renderamt = src->renderamt; + dst->rendercolor.r = src->rendercolor.r; + dst->rendercolor.g = src->rendercolor.g; + dst->rendercolor.b = src->rendercolor.b; + dst->renderfx = src->renderfx; + + dst->framerate = src->framerate; + dst->body = src->body; + + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + + VectorCopy( src->basevelocity, dst->basevelocity ); + + dst->friction = src->friction; + dst->gravity = src->gravity; + dst->gaitsequence = src->gaitsequence; + dst->spectator = src->spectator; + dst->usehull = src->usehull; + dst->playerclass = src->playerclass; + dst->team = src->team; + dst->colormap = src->colormap; + + // Save off some data so other areas of the Client DLL can get to it + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index + if ( dst->number == player->index ) + { + g_iPlayerClass = dst->playerclass; + g_iTeamNumber = dst->team; + + g_iUser1 = src->iuser1; + g_iUser2 = src->iuser2; + g_iUser3 = src->iuser3; + } +} + +/* +========================= +HUD_TxferPredictionData + +Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in + from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's + up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server + update is occupying. +========================= +*/ +void DLLEXPORT HUD_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 ) +{ + ps->oldbuttons = pps->oldbuttons; + ps->flFallVelocity = pps->flFallVelocity; + ps->iStepLeft = pps->iStepLeft; + ps->playerclass = pps->playerclass; + + pcd->viewmodel = ppcd->viewmodel; + pcd->m_iId = ppcd->m_iId; + pcd->ammo_shells = ppcd->ammo_shells; + pcd->ammo_nails = ppcd->ammo_nails; + pcd->ammo_cells = ppcd->ammo_cells; + pcd->ammo_rockets = ppcd->ammo_rockets; + pcd->m_flNextAttack = ppcd->m_flNextAttack; + pcd->fov = ppcd->fov; + pcd->weaponanim = ppcd->weaponanim; + pcd->tfstate = ppcd->tfstate; + pcd->maxspeed = ppcd->maxspeed; + + pcd->deadflag = ppcd->deadflag; + + // Spectating or not dead == get control over view angles. + g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; + + // Spectator + pcd->iuser1 = ppcd->iuser1; + pcd->iuser2 = ppcd->iuser2; + + // Duck prevention + pcd->iuser3 = ppcd->iuser3; + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in specator mode we tell the engine who we want to spectate and how + // iuser3 is not used for duck prevention (since the spectator can't duck at all) + pcd->iuser1 = g_iUser1; // observer mode + pcd->iuser2 = g_iUser2; // first target + pcd->iuser3 = g_iUser3; // second target + + } + + // Fire prevention + pcd->iuser4 = ppcd->iuser4; + + pcd->fuser2 = ppcd->fuser2; + pcd->fuser3 = ppcd->fuser3; + + VectorCopy( ppcd->vuser1, pcd->vuser1 ); + VectorCopy( ppcd->vuser2, pcd->vuser2 ); + VectorCopy( ppcd->vuser3, pcd->vuser3 ); + VectorCopy( ppcd->vuser4, pcd->vuser4 ); + + memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); +} + +/* +//#define TEST_IT +#if defined( TEST_IT ) + +cl_entity_t mymodel[9]; + +void MoveModel( void ) +{ + cl_entity_t *player; + int i, j; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + // Don't draw over ourself... + if ( ( i == 1 ) && ( j == 1 ) ) + continue; + + mymodel[ i * 3 + j ] = *player; + + mymodel[ i * 3 + j ].player = 0; + + mymodel[ i * 3 + j ].model = mod; + mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + + // Move it out a bit + mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + } + } + +} + +#endif + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern int hitent; + +cl_entity_t hit; + +void TraceModel( void ) +{ + cl_entity_t *ent; + + if ( hitent <= 0 ) + return; + + // Load it up with some bogus data + ent = gEngfuncs.GetEntityByIndex( hitent ); + if ( !ent ) + return; + + hit = *ent; + //hit.curstate.rendermode = kRenderTransTexture; + //hit.curstate.renderfx = kRenderFxGlowShell; + //hit.curstate.renderamt = 100; + + hit.origin[2] += 40; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); +} + +#endif +*/ + +/* +void ParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + particle->org[ i ] += particle->vel[ i ] * frametime; + } +} + +cvar_t *color = NULL; +void Particles( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 2.0 ) + return; + + if ( !color ) + { + color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); + } + + lasttime = curtime; + + // Create a few particles + particle_t *p; + int i, j; + + for ( i = 0; i < 1000; i++ ) + { + int r, g, b; + p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; + p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + } + + if ( color ) + { + sscanf( color->string, "%i %i %i", &r, &g, &b ); + } + else + { + r = 192; + g = 0; + b = 0; + } + + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 3.0; + } +} +*/ + +/* +void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + } +} + +void TempEnts( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + lasttime = curtime; + + TEMPENTITY *p; + int i, j; + struct model_s *mod; + vec3_t origin; + int index; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); + + for ( i = 0; i < 100; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + origin[ j ] = v_origin[ j ]; + if ( j != 2 ) + { + origin[ j ] += 75; + } + } + + p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->entity.curstate.origin[ j ] = origin[ j ]; + + // Store velocity in baseline origin + p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + } + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 10.0; + } +} +*/ + +#if defined( BEAM_TEST ) +// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Room for 1 beam ( 0 can't be used ) +static cl_entity_t beams[ 2 ]; + +void BeamEndModel( void ) +{ + cl_entity_t *player, *model; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + if ( !mod ) + return; + + // Slot 1 + model = &beams[ 1 ]; + + *model = *player; + model->player = 0; + model->model = mod; + model->curstate.modelindex = modelindex; + + // Move it out a bit + model->origin[0] = player->origin[0] - 100; + model->origin[1] = player->origin[1]; + + model->attachment[0] = model->origin; + model->attachment[1] = model->origin; + model->attachment[2] = model->origin; + model->attachment[3] = model->origin; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); +} + +void Beams( void ) +{ + static float lasttime; + float curtime; + struct model_s *mod; + int index; + + BeamEndModel(); + + curtime = gEngfuncs.GetClientTime(); + float end[ 3 ]; + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); + if ( !mod ) + return; + + lasttime = curtime; + + end [ 0 ] = v_origin.x + 100; + end [ 1 ] = v_origin.y + 100; + end [ 2 ] = v_origin.z; + + BEAM *p1; + p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, + 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); +} +#endif + +/* +========================= +HUD_CreateEntities + +Gives us a chance to add additional entities to the render this frame +========================= +*/ +void DLLEXPORT HUD_CreateEntities( void ) +{ + // e.g., create a persistent cl_entity_t somewhere. + // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) + // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list +/* +#if defined( TEST_IT ) + MoveModel(); +#endif + +#if defined( TRACE_TEST ) + TraceModel(); +#endif +*/ +/* + Particles(); +*/ +/* + TempEnts(); +*/ + +#if defined( BEAM_TEST ) + Beams(); +#endif + + // Add in any game specific objects + Game_AddObjects(); +} + +/* +========================= +HUD_StudioEvent + +The entity's studio model description indicated an event was +fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) +========================= +*/ +void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) +{ + switch( event->event ) + { + case 5001: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + break; + case 5011: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + break; + case 5021: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + break; + case 5031: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + break; + case 5002: + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + break; + // Client side sound + case 5004: + gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); + break; + default: + break; + } +} + +/* +================= +CL_UpdateTEnts + +Simulation and cleanup of temporary entities +================= +*/ +void DLLEXPORT HUD_TempEntUpdate ( + double frametime, // Simulation time + double client_time, // Absolute time on client + double cl_gravity, // True gravity on client + TEMPENTITY **ppTempEntFree, // List of freed temporary ents + TEMPENTITY **ppTempEntActive, // List + int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), + void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) +{ + static int gTempEntFrame = 0; + int i; + TEMPENTITY *pTemp, *pnext, *pprev; + float freq, gravity, gravitySlow, life, fastFreq; + + // Nothing to simulate + if ( !*ppTempEntActive ) + return; + + // in order to have tents collide with players, we have to run the player prediction code so + // that the client has the player list. We run this code once when we detect any COLLIDEALL + // tent, then set this BOOL to true so the code doesn't get run again if there's more than + // one COLLIDEALL ent for this update. (often are). + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); + + // !!!BUGBUG -- This needs to be time based + gTempEntFrame = (gTempEntFrame+1) & 31; + + pTemp = *ppTempEntActive; + + // !!! Don't simulate while paused.... This is sort of a hack, revisit. + if ( frametime <= 0 ) + { + while ( pTemp ) + { + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + Callback_AddVisibleEntity( &pTemp->entity ); + } + pTemp = pTemp->next; + } + goto finish; + } + + pprev = NULL; + freq = client_time * 0.01; + fastFreq = client_time * 5.5; + gravity = -frametime * cl_gravity; + gravitySlow = gravity * 0.5; + + while ( pTemp ) + { + int active; + + active = 1; + + life = pTemp->die - client_time; + pnext = pTemp->next; + if ( life < 0 ) + { + if ( pTemp->flags & FTENT_FADEOUT ) + { + if (pTemp->entity.curstate.rendermode == kRenderNormal) + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); + if ( pTemp->entity.curstate.renderamt <= 0 ) + active = 0; + + } + else + active = 0; + } + if ( !active ) // Kill it + { + pTemp->next = *ppTempEntFree; + *ppTempEntFree = pTemp; + if ( !pprev ) // Deleting at head of list + *ppTempEntActive = pnext; + else + pprev->next = pnext; + } + else + { + pprev = pTemp; + + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Adjust speed if it's time + // Scale is next think time + if ( client_time > pTemp->entity.baseline.scale ) + { + // Show Sparks + gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); + + // Reduce life + pTemp->entity.baseline.framerate -= 0.1; + + if ( pTemp->entity.baseline.framerate <= 0.0 ) + { + pTemp->die = client_time; + } + else + { + // So it will die no matter what + pTemp->die = client_time + 0.5; + + // Next think + pTemp->entity.baseline.scale = client_time + 0.1; + } + } + } + else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + { + cl_entity_t *pClient; + + pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); + + VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); + } + else if ( pTemp->flags & FTENT_SINEWAVE ) + { + pTemp->x += pTemp->entity.baseline.origin[0] * frametime; + pTemp->y += pTemp->entity.baseline.origin[1] * frametime; + + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else if ( pTemp->flags & FTENT_SPIRAL ) + { + float s, c; + s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); + + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)(size_t)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)(size_t)pTemp ); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + + else + { + for ( i = 0; i < 3; i++ ) + pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; + } + + if ( pTemp->flags & FTENT_SPRANIMATE ) + { + pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + + if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + { + // this animating sprite isn't set to loop, so destroy it. + pTemp->die = client_time; + pTemp = pnext; + continue; + } + } + } + else if ( pTemp->flags & FTENT_SPRCYCLE ) + { + pTemp->entity.curstate.frame += frametime * 10; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + } + } +// Experiment +#if 0 + if ( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); +#endif + + if ( pTemp->flags & FTENT_ROTATE ) + { + pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; + pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; + pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; + + VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); + } + + if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + { + vec3_t traceNormal; + float traceFraction = 1; + + if ( pTemp->flags & FTENT_COLLIDEALL ) + { + pmtrace_t pmtrace; + physent_t *pe; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); + + + if ( pmtrace.fraction != 1 ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); + + if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + } + else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + { + pmtrace_t pmtrace; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + + if ( pmtrace.fraction != 1 ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Chop spark speeds a bit more + // + VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); + + if ( Length( pTemp->entity.baseline.origin ) < 10 ) + { + pTemp->entity.baseline.framerate = 0.0; + } + } + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + + if ( traceFraction != 1 ) // Decent collision now, and damping works + { + float proj, damp; + + // Place at contact point + VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + // Damp velocity + damp = pTemp->bounceFactor; + if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + { + damp *= 0.5; + if ( traceNormal[2] > 0.9 ) // Hit floor? + { + if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + { + damp = 0; // Stop + pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->entity.angles[0] = 0; + pTemp->entity.angles[2] = 0; + } + } + } + + if (pTemp->hitSound) + { + Callback_TempEntPlaySound(pTemp, damp); + } + + if (pTemp->flags & FTENT_COLLIDEKILL) + { + // die on impact + pTemp->flags &= ~FTENT_FADEOUT; + pTemp->die = client_time; + } + else + { + // Reflect velocity + if ( damp != 0 ) + { + proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); + VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + // Reflect rotation (fake) + + pTemp->entity.angles[1] = -pTemp->entity.angles[1]; + } + + if ( damp != 1 ) + { + + VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); + VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); + } + } + } + } + + + if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + { + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); + VectorCopy (pTemp->entity.origin, dl->origin); + dl->radius = 60; + dl->color.r = 255; + dl->color.g = 120; + dl->color.b = 0; + dl->die = client_time + 0.01; + } + + if ( pTemp->flags & FTENT_SMOKETRAIL ) + { + gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + } + + if ( pTemp->flags & FTENT_GRAVITY ) + pTemp->entity.baseline.origin[2] += gravity; + else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + pTemp->entity.baseline.origin[2] += gravitySlow; + + if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + { + if ( pTemp->callback ) + { + ( *pTemp->callback )( pTemp, frametime, client_time ); + } + } + + // Cull to PVS (not frustum cull, just PVS) + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + { + if ( !(pTemp->flags & FTENT_PERSIST) ) + { + pTemp->die = client_time; // If we can't draw it this frame, just dump it. + pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die + } + } + } + } + pTemp = pnext; + } + +finish: + // Restore state info + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +================= +HUD_GetUserEntity + +If you specify negative numbers for beam start and end point entities, then + the engine will call back into this function requesting a pointer to a cl_entity_t + object that describes the entity to attach the beam onto. + +Indices must start at 1, not zero. +================= +*/ +cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) +{ +#if defined( BEAM_TEST ) + // None by default, you would return a valic pointer if you create a client side + // beam and attach it to a client side entity. + if ( index > 0 && index <= 1 ) + { + return &beams[ index ]; + } + else + { + return NULL; + } +#else + return NULL; +#endif +} + diff --git a/cl_dll/ev_common.cpp b/cl_dll/ev_common.cpp index 224633dd..e5826a49 100644 --- a/cl_dll/ev_common.cpp +++ b/cl_dll/ev_common.cpp @@ -1,205 +1,205 @@ -/*** -* -* 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. -* -****/ -// shared event functions -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" - -#include "r_efx.h" - -#include "eventscripts.h" -#include "event_api.h" -#include "pm_shared.h" - -#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) ) -/* -================= -GetEntity - -Return's the requested cl_entity_t -================= -*/ -struct cl_entity_s *GetEntity( int idx ) -{ - return gEngfuncs.GetEntityByIndex( idx ); -} - -/* -================= -GetViewEntity - -Return's the current weapon/view model -================= -*/ -struct cl_entity_s *GetViewEntity( void ) -{ - return gEngfuncs.GetViewModel(); -} - -/* -================= -EV_CreateTracer - -Creates a tracer effect -================= -*/ -void EV_CreateTracer( float *start, float *end ) -{ - gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); -} - -/* -================= -EV_IsPlayer - -Is the entity's index in the player range? -================= -*/ -qboolean EV_IsPlayer( int idx ) -{ - if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) - return true; - - return false; -} - -/* -================= -EV_IsLocal - -Is the entity == the local player -================= -*/ -qboolean EV_IsLocal( int idx ) -{ - // check if we are in some way in first person spec mode - if ( IS_FIRSTPERSON_SPEC ) - return (g_iUser2 == idx); - else - return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; -} - -/* -================= -EV_GetGunPosition - -Figure out the height of the gun -================= -*/ -void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) -{ - int idx; - vec3_t view_ofs; - - idx = args->entindex; - - VectorClear( view_ofs ); - view_ofs[2] = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx ) ) - { - // in spec mode use entity viewheigh, not own - if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) - { - // Grab predicted result for local player - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - VectorAdd( origin, view_ofs, pos ); -} - -/* -================= -EV_EjectBrass - -Bullet shell casings -================= -*/ -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) -{ - vec3_t endpos; - VectorClear( endpos ); - endpos[1] = rotation; - gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); -} - -/* -================= -EV_GetDefaultShellInfo - -Determine where to eject shells from -================= -*/ -void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) -{ - int i; - vec3_t view_ofs; - float fR, fU; - - int idx; - - idx = args->entindex; - - VectorClear( view_ofs ); - view_ofs[2] = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx ) ) - { - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - fR = gEngfuncs.pfnRandomFloat( 50, 70 ); - fU = gEngfuncs.pfnRandomFloat( 100, 150 ); - - for ( i = 0; i < 3; i++ ) - { - ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; - ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; - } -} - -/* -================= -EV_MuzzleFlash - -Flag weapon/view model for muzzle flash -================= -*/ -void EV_MuzzleFlash( void ) -{ - // Add muzzle flash to current weapon model - cl_entity_t *ent = GetViewEntity(); - if ( !ent ) - { - return; - } - - // Or in the muzzle flash - ent->curstate.effects |= EF_MUZZLEFLASH; +/*** +* +* 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. +* +****/ +// shared event functions +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "r_efx.h" + +#include "eventscripts.h" +#include "event_api.h" +#include "pm_shared.h" + +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) ) +/* +================= +GetEntity + +Return's the requested cl_entity_t +================= +*/ +struct cl_entity_s *GetEntity( int idx ) +{ + return gEngfuncs.GetEntityByIndex( idx ); +} + +/* +================= +GetViewEntity + +Return's the current weapon/view model +================= +*/ +struct cl_entity_s *GetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +/* +================= +EV_CreateTracer + +Creates a tracer effect +================= +*/ +void EV_CreateTracer( float *start, float *end ) +{ + gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); +} + +/* +================= +EV_IsPlayer + +Is the entity's index in the player range? +================= +*/ +qboolean EV_IsPlayer( int idx ) +{ + if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + return true; + + return false; +} + +/* +================= +EV_IsLocal + +Is the entity == the local player +================= +*/ +qboolean EV_IsLocal( int idx ) +{ + // check if we are in some way in first person spec mode + if ( IS_FIRSTPERSON_SPEC ) + return (g_iUser2 == idx); + else + return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; +} + +/* +================= +EV_GetGunPosition + +Figure out the height of the gun +================= +*/ +void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) +{ + int idx; + vec3_t view_ofs; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + // in spec mode use entity viewheigh, not own + if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) + { + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + VectorAdd( origin, view_ofs, pos ); +} + +/* +================= +EV_EjectBrass + +Bullet shell casings +================= +*/ +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) +{ + vec3_t endpos; + VectorClear( endpos ); + endpos[1] = rotation; + gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); +} + +/* +================= +EV_GetDefaultShellInfo + +Determine where to eject shells from +================= +*/ +void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) +{ + int i; + vec3_t view_ofs; + float fR, fU; + + int idx; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + fR = gEngfuncs.pfnRandomFloat( 50, 70 ); + fU = gEngfuncs.pfnRandomFloat( 100, 150 ); + + for ( i = 0; i < 3; i++ ) + { + ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + } +} + +/* +================= +EV_MuzzleFlash + +Flag weapon/view model for muzzle flash +================= +*/ +void EV_MuzzleFlash( void ) +{ + // Add muzzle flash to current weapon model + cl_entity_t *ent = GetViewEntity(); + if ( !ent ) + { + return; + } + + // Or in the muzzle flash + ent->curstate.effects |= EF_MUZZLEFLASH; } \ No newline at end of file diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 82818295..5a4162fb 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1,1700 +1,1700 @@ -/*** -* -* 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 "hud.h" -#include "cl_util.h" -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "entity_types.h" -#include "usercmd.h" -#include "pm_defs.h" -#include "pm_materials.h" - -#include "eventscripts.h" -#include "ev_hldm.h" - -#include "r_efx.h" -#include "event_api.h" -#include "event_args.h" -#include "in_defs.h" - -#include - -#include "r_studioint.h" -#include "com_model.h" - -extern engine_studio_api_t IEngineStudio; - -static int tracerCount[ 32 ]; - -extern "C" char PM_FindTextureType( char *name ); - -void V_PunchAxis( int axis, float punch ); -void VectorAngles( const float *forward, float *angles ); - -extern cvar_t *cl_lw; - -extern "C" -{ - -// HLDM -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); - - -void EV_TrainPitchAdjust( struct event_args_s *args ); -} - -#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) -#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) -#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) -#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) -#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) -#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) -#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) -#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) -#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) -#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) -#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) -#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) - -// 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 EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType ) -{ - // hit the world, try to play sound based on texture material type - char chTextureType = CHAR_TEX_CONCRETE; - float fvol; - float fvolbar; - char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - int entity; - char *pTextureName; - char texname[ 64 ]; - char szbuffer[ 64 ]; - - entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); - - // FIXME check if playtexture sounds movevar is set - // - - chTextureType = 0; - - // Player - if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) - { - // hit body - chTextureType = CHAR_TEX_FLESH; - } - else if ( entity == 0 ) - { - // get texture from entity or world (world is ent(0)) - pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); - - if ( pTextureName ) - { - strcpy( texname, pTextureName ); - pTextureName = texname; - - // 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; - - // get texture type - chTextureType = PM_FindTextureType( 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; - } - - // play material hit sound - gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); - return fvolbar; -} - -char *EV_HLDM_DamageDecal( physent_t *pe ) -{ - static char decalname[ 32 ]; - int idx; - - if ( pe->classnumber == 1 ) - { - idx = gEngfuncs.pfnRandomLong( 0, 2 ); - sprintf( decalname, "{break%i", idx + 1 ); - } - else if ( pe->rendermode != kRenderNormal ) - { - sprintf( decalname, "{bproof1" ); - } - else - { - idx = gEngfuncs.pfnRandomLong( 0, 4 ); - sprintf( decalname, "{shot%i", idx + 1 ); - } - return decalname; -} - -void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) -{ - int iRand; - physent_t *pe; - - gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); - - iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); - if ( iRand < (0x7fff/2) )// not every bullet makes a sound. - { - switch( iRand % 5) - { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - } - } - - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - - // Only decal brush models such as the world etc. - if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) - { - if ( CVAR_GET_FLOAT( "r_decals" ) ) - { - gEngfuncs.pEfxAPI->R_DecalShoot( - gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), - gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); - } - } -} - -void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) -{ - physent_t *pe; - - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - - if ( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) - { - 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 - EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) ); - break; - } - } -} - -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) -{ - int tracer = 0; - int i; - qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; - - if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) - { - vec3_t vecTracerSrc; - - if ( player ) - { - vec3_t offset( 0, 0, -4 ); - - // adjust tracer position for player - for ( i = 0; i < 3; i++ ) - { - vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; - } - } - else - { - VectorCopy( vecSrc, vecTracerSrc ); - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - - switch( iBulletType ) - { - case BULLET_PLAYER_MP5: - case BULLET_MONSTER_MP5: - case BULLET_MONSTER_9MM: - case BULLET_MONSTER_12MM: - default: - EV_CreateTracer( vecTracerSrc, end ); - break; - } - } - - return tracer; -} - - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. -================ -*/ -void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) -{ - int i; - pmtrace_t tr; - int iShot; - int tracer; - - for ( iShot = 1; iShot <= cShots; iShot++ ) - { - vec3_t vecDir, vecEnd; - - float x, y, z; - //We randomize for the Shotgun. - if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) - { - do { - x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - - for ( i = 0 ; i < 3; i++ ) - { - vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; - vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; - } - }//But other guns already have their spread randomized in the synched spread. - else - { - - for ( i = 0 ; i < 3; i++ ) - { - vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; - vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; - } - } - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); - - // do damage, paint decals - if ( tr.fraction != 1.0 ) - { - switch(iBulletType) - { - default: - case BULLET_PLAYER_9MM: - - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); - EV_HLDM_DecalGunshot( &tr, iBulletType ); - - break; - case BULLET_PLAYER_MP5: - - if ( !tracer ) - { - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); - EV_HLDM_DecalGunshot( &tr, iBulletType ); - } - break; - case BULLET_PLAYER_BUCKSHOT: - - EV_HLDM_DecalGunshot( &tr, iBulletType ); - - break; - case BULLET_PLAYER_357: - - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); - EV_HLDM_DecalGunshot( &tr, iBulletType ); - - break; - - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); - } -} - -//====================== -// GLOCK START -//====================== -void EV_FireGlock1( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - int empty; - - vec3_t ShellVelocity; - vec3_t ShellOrigin; - int shell; - vec3_t vecSrc, vecAiming; - vec3_t up, right, forward; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - empty = args->bparam1; - AngleVectors( angles, forward, right, up ); - - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) - { - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); - - V_PunchAxis( 0, -2.0 ); - } - - EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); - - EV_GetGunPosition( args, vecSrc, origin ); - - VectorCopy( forward, vecAiming ); - - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2 ); -} - -void EV_FireGlock2( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - vec3_t ShellVelocity; - vec3_t ShellOrigin; - int shell; - vec3_t vecSrc, vecAiming; - vec3_t vecSpread; - vec3_t up, right, forward; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); - - V_PunchAxis( 0, -2.0 ); - } - - EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); - - EV_GetGunPosition( args, vecSrc, origin ); - - VectorCopy( forward, vecAiming ); - - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); - -} -//====================== -// GLOCK END -//====================== - -//====================== -// SHOTGUN START -//====================== -void EV_FireShotGunDouble( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - int j; - vec3_t ShellVelocity; - vec3_t ShellOrigin; - int shell; - vec3_t vecSrc, vecAiming; - vec3_t vecSpread; - vec3_t up, right, forward; - float flSpread = 0.01; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); - V_PunchAxis( 0, -10.0 ); - } - - for ( j = 0; j < 2; j++ ) - { - EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); - - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); - } - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - - EV_GetGunPosition( args, vecSrc, origin ); - VectorCopy( forward, vecAiming ); - - if ( gEngfuncs.GetMaxClients() > 1 ) - { - EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); - } - else - { - EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); - } -} - -void EV_FireShotGunSingle( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - vec3_t ShellVelocity; - vec3_t ShellOrigin; - int shell; - vec3_t vecSrc, vecAiming; - vec3_t vecSpread; - vec3_t up, right, forward; - float flSpread = 0.01; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); - - V_PunchAxis( 0, -5.0 ); - } - - EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); - - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - - EV_GetGunPosition( args, vecSrc, origin ); - VectorCopy( forward, vecAiming ); - - if ( gEngfuncs.GetMaxClients() > 1 ) - { - EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); - } - else - { - EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); - } -} -//====================== -// SHOTGUN END -//====================== - -//====================== -// MP5 START -//====================== -void EV_FireMP5( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - vec3_t ShellVelocity; - vec3_t ShellOrigin; - int shell; - vec3_t vecSrc, vecAiming; - vec3_t up, right, forward; - float flSpread = 0.01; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); - - V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); - } - - EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); - - switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) - { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); - break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); - break; - } - - EV_GetGunPosition( args, vecSrc, origin ); - VectorCopy( forward, vecAiming ); - - if ( gEngfuncs.GetMaxClients() > 1 ) - { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); - } - else - { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); - } -} - -// We only predict the animation and sound -// The grenade is still launched from the server. -void EV_FireMP52( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); - V_PunchAxis( 0, -10 ); - } - - switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) - { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); - break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); - break; - } -} -//====================== -// MP5 END -//====================== - -//====================== -// PHYTON START -// ( .357 ) -//====================== -void EV_FirePython( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - vec3_t vecSrc, vecAiming; - vec3_t up, right, forward; - float flSpread = 0.01; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - if ( EV_IsLocal( idx ) ) - { - // Python uses different body in multiplayer versus single player - int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; - - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); - - V_PunchAxis( 0, -10.0 ); - } - - switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) - { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); - break; - } - - EV_GetGunPosition( args, vecSrc, origin ); - - VectorCopy( forward, vecAiming ); - - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); -} -//====================== -// PHYTON END -// ( .357 ) -//====================== - -//====================== -// GAUSS START -//====================== -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch - -void EV_SpinGauss( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - int iSoundState = 0; - - int pitch; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - pitch = args->iparam1; - - iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); -} - -/* -============================== -EV_StopPreviousGauss - -============================== -*/ -void EV_StopPreviousGauss( int idx ) -{ - // Make sure we don't have a gauss spin event in the queue for this guy - gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); -} - -extern float g_flApplyVel; - -void EV_FireGauss( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - float flDamage = args->fparam1; - int primaryfire = args->bparam1; - - int m_fPrimaryFire = args->bparam1; - int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - vec3_t vecSrc; - vec3_t vecDest; - edict_t *pentIgnore; - pmtrace_t tr, beam_tr; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - physent_t *pEntity; - int m_iBeam, m_iGlow, m_iBalls; - vec3_t up, right, forward; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - VectorCopy( args->velocity, velocity ); - - if ( args->bparam2 ) - { - EV_StopPreviousGauss( idx ); - return; - } - -// Con_Printf( "Firing gauss with %f\n", flDamage ); - EV_GetGunPosition( args, vecSrc, origin ); - - m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); - m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); - - AngleVectors( angles, forward, right, up ); - - VectorMA( vecSrc, 8192, forward, vecDest ); - - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, -2.0 ); - gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); - - if ( m_fPrimaryFire == false ) - g_flApplyVel = flDamage; - - } - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - - while (flDamage > 10 && nMaxHits > 0) - { - nMaxHits--; - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - if ( tr.allsolid ) - break; - - if (fFirstBeam) - { - if ( EV_IsLocal( idx ) ) - { - // Add muzzle flash to current weapon model - EV_MuzzleFlash(); - } - fFirstBeam = 0; - - gEngfuncs.pEfxAPI->R_BeamEntPoint( - idx | 0x1000, - tr.endpos, - m_iBeam, - 0.1, - m_fPrimaryFire ? 1.0 : 2.5, - 0.0, - m_fPrimaryFire ? 128.0 : flDamage, - 0, - 0, - 0, - m_fPrimaryFire ? 255 : 255, - m_fPrimaryFire ? 128 : 255, - m_fPrimaryFire ? 0 : 255 - ); - } - else - { - gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, - tr.endpos, - m_iBeam, - 0.1, - m_fPrimaryFire ? 1.0 : 2.5, - 0.0, - m_fPrimaryFire ? 128.0 : flDamage, - 0, - 0, - 0, - m_fPrimaryFire ? 255 : 255, - m_fPrimaryFire ? 128 : 255, - m_fPrimaryFire ? 0 : 255 - ); - } - - pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - if ( pEntity == NULL ) - break; - - if ( pEntity->solid == SOLID_BSP ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct( tr.plane.normal, forward ); - - if (n < 0.5) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - vec3_t r; - - VectorMA( forward, 2.0 * n, tr.plane.normal, r ); - - flMaxFrac = flMaxFrac - tr.fraction; - - VectorCopy( r, forward ); - - VectorMA( tr.endpos, 8.0, forward, vecSrc ); - VectorMA( vecSrc, 8192.0, forward, vecDest ); - - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); - - vec3_t fwd; - VectorAdd( tr.endpos, tr.plane.normal, fwd ); - - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 100 ); - - // lose energy - if ( n == 0 ) - { - n = 0.1; - } - - flDamage = flDamage * (1 - n); - - } - else - { - // tunnel - EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); - - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); - - // 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 ) - { - vec3_t start; - - VectorMA( tr.endpos, 8.0, forward, start ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); - - if ( !beam_tr.allsolid ) - { - vec3_t delta; - float n; - - // trace backwards to find exit point - - gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); - - VectorSubtract( beam_tr.endpos, tr.endpos, delta ); - - n = Length( delta ); - - if (n < flDamage) - { - if (n == 0) - n = 1; - flDamage -= n; - - // absorption balls - { - vec3_t fwd; - VectorSubtract( tr.endpos, forward, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 100 ); - } - - //////////////////////////////////// WHAT TO DO HERE - // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); - - gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); - - // balls - { - vec3_t fwd; - VectorSubtract( beam_tr.endpos, forward, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, - 255, 40 ); - } - - VectorAdd( beam_tr.endpos, forward, vecSrc ); - } - } - else - { - flDamage = 0; - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); - } - else - { - if ( m_fPrimaryFire ) - { - // slug doesn't punch through ever with primary - // fire, so leave a little glowy bit and make some balls - gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); - - { - vec3_t fwd; - VectorAdd( tr.endpos, tr.plane.normal, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, - 255, 200 ); - } - } - - flDamage = 0; - } - } - } - else - { - VectorAdd( tr.endpos, forward, vecSrc ); - } - } -} -//====================== -// GAUSS END -//====================== - -//====================== -// CROWBAR START -//====================== - -enum crowbar_e { - CROWBAR_IDLE = 0, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT -}; - -int g_iSwing; - -//Only predict the miss sounds, hit sounds are still played -//server side, so players don't get the wrong idea. -void EV_Crowbar( event_args_t *args ) -{ - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - //Play Swing sound - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); - - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); - - switch( (g_iSwing++) % 3 ) - { - case 0: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; - case 1: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; - case 2: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; - } - } -} -//====================== -// CROWBAR END -//====================== - -//====================== -// CROSSBOW START -//====================== -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 -}; - -//===================== -// EV_BoltCallback -// This function is used to correct the origin and angles -// of the bolt, so it looks like it's stuck on the wall. -//===================== -void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) -{ - ent->entity.origin = ent->entity.baseline.vuser1; - ent->entity.angles = ent->entity.baseline.vuser2; -} - -void EV_FireCrossbow2( event_args_t *args ) -{ - vec3_t vecSrc, vecEnd; - vec3_t up, right, forward; - pmtrace_t tr; - - int idx; - vec3_t origin; - vec3_t angles; - vec3_t velocity; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - - VectorCopy( args->velocity, velocity ); - - AngleVectors( angles, forward, right, up ); - - EV_GetGunPosition( args, vecSrc, origin ); - - VectorMA( vecSrc, 8192, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - - if ( EV_IsLocal( idx ) ) - { - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); - else if ( args->iparam2 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); - } - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - //We hit something - if ( tr.fraction < 1.0 ) - { - physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - - //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). - if ( pe->solid != SOLID_BSP ) - { - switch( gEngfuncs.pfnRandomLong(0,1) ) - { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; - } - } - //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. - else if ( pe->rendermode == kRenderNormal ) - { - gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); - - //Not underwater, do some sparks... - if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) - gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); - - vec3_t vBoltAngles; - int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); - - VectorAngles( forward, vBoltAngles ); - - TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); - - if ( bolt ) - { - bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. - bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit - bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward! - bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall) - } - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -//TODO: Fully predict the fliying bolt. -void EV_FireCrossbow( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); - else if ( args->iparam2 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); - - V_PunchAxis( 0, -2.0 ); - } -} -//====================== -// CROSSBOW END -//====================== - -//====================== -// RPG START -//====================== -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 -}; - -void EV_FireRpg( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); - - V_PunchAxis( 0, -5.0 ); - } -} -//====================== -// RPG END -//====================== - -//====================== -// EGON END -//====================== -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 -}; - -int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; -int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; - -enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; -enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; - -#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 ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -BEAM *pBeam; -BEAM *pBeam2; - -void EV_EgonFire( event_args_t *args ) -{ - int idx, iFireState, iFireMode; - vec3_t origin; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - iFireState = args->iparam1; - iFireMode = args->iparam2; - int iStartup = args->bparam1; - - - if ( iStartup ) - { - if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); - else - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); - } - else - { - if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); - else - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); - } - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); - - if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. - { - vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; - pmtrace_t tr; - - cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); - - if ( pl ) - { - VectorCopy( gHUD.m_vecAngles, angles ); - - AngleVectors( angles, forward, right, up ); - - EV_GetGunPosition( args, vecSrc, pl->origin ); - - VectorMA( vecSrc, 2048, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); - - float r = 50.0f; - float g = 50.0f; - float b = 125.0f; - - if ( IEngineStudio.IsHardware() ) - { - r /= 100.0f; - g /= 100.0f; - } - - - pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); - - if ( pBeam ) - pBeam->flags |= ( FBEAM_SINENOISE ); - - pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); - } - } -} - -void EV_EgonStop( event_args_t *args ) -{ - int idx; - vec3_t origin; - - idx = args->entindex; - VectorCopy ( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); - - if ( args->iparam1 ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); - - if ( EV_IsLocal( idx ) ) - { - if ( pBeam ) - { - pBeam->die = 0.0; - pBeam = NULL; - } - - - if ( pBeam2 ) - { - pBeam2->die = 0.0; - pBeam2 = NULL; - } - } -} -//====================== -// EGON END -//====================== - -//====================== -// HORNET START -//====================== -enum hgun_e { - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -void EV_HornetGunFire( event_args_t *args ) -{ - int idx, iFireMode; - vec3_t origin, angles, vecSrc, forward, right, up; - - idx = args->entindex; - VectorCopy( args->origin, origin ); - VectorCopy( args->angles, angles ); - iFireMode = args->iparam1; - - //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - { - V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); - gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); - } - - switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) - { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; - } -} -//====================== -// HORNET END -//====================== - -//====================== -// TRIPMINE START -//====================== -enum tripmine_e { - TRIPMINE_IDLE1 = 0, - TRIPMINE_IDLE2, - TRIPMINE_ARM1, - TRIPMINE_ARM2, - TRIPMINE_FIDGET, - TRIPMINE_HOLSTER, - TRIPMINE_DRAW, - TRIPMINE_WORLD, - TRIPMINE_GROUND, -}; - -//We only check if it's possible to put a trip mine -//and if it is, then we play the animation. Server still places it. -void EV_TripmineFire( event_args_t *args ) -{ - int idx; - vec3_t vecSrc, angles, view_ofs, forward; - pmtrace_t tr; - - idx = args->entindex; - VectorCopy( args->origin, vecSrc ); - VectorCopy( args->angles, angles ); - - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) - return; - - // Grab predicted result for local player - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - - vecSrc = vecSrc + view_ofs; - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); - - //Hit something solid - if ( tr.fraction < 1.0 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} -//====================== -// TRIPMINE END -//====================== - -//====================== -// SQUEAK START -//====================== -enum squeak_e { - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -#define VEC_HULL_MIN Vector(-16, -16, -36) -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) - -void EV_SnarkFire( event_args_t *args ) -{ - int idx; - vec3_t vecSrc, angles, view_ofs, forward; - pmtrace_t tr; - - idx = args->entindex; - VectorCopy( args->origin, vecSrc ); - VectorCopy( args->angles, angles ); - - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) - return; - - if ( args->ducking ) - vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); - - //Find space to drop the thing. - if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} -//====================== -// SQUEAK END -//====================== - -void EV_TrainPitchAdjust( event_args_t *args ) -{ - int idx; - vec3_t origin; - - unsigned short us_params; - int noise; - float m_flVolume; - int pitch; - int stop; - - char sz[ 256 ]; - - idx = args->entindex; - - VectorCopy( args->origin, origin ); - - us_params = (unsigned short)args->iparam1; - stop = args->bparam1; - - m_flVolume = (float)(us_params & 0x003f)/40.0; - noise = (int)(((us_params) >> 12 ) & 0x0007); - pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); - - switch ( noise ) - { - case 1: strcpy( sz, "plats/ttrain1.wav"); break; - case 2: strcpy( sz, "plats/ttrain2.wav"); break; - case 3: strcpy( sz, "plats/ttrain3.wav"); break; - case 4: strcpy( sz, "plats/ttrain4.wav"); break; - case 5: strcpy( sz, "plats/ttrain6.wav"); break; - case 6: strcpy( sz, "plats/ttrain7.wav"); break; - default: - // no sound - strcpy( sz, "" ); - return; - } - - if ( stop ) - { - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); - } - else - { - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); - } -} - -int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) -{ - return 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 "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" + +#include "eventscripts.h" +#include "ev_hldm.h" + +#include "r_efx.h" +#include "event_api.h" +#include "event_args.h" +#include "in_defs.h" + +#include + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +static int tracerCount[ 32 ]; + +extern "C" char PM_FindTextureType( char *name ); + +void V_PunchAxis( int axis, float punch ); +void VectorAngles( const float *forward, float *angles ); + +extern cvar_t *cl_lw; + +extern "C" +{ + +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +// 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 EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType ) +{ + // hit the world, try to play sound based on texture material type + char chTextureType = CHAR_TEX_CONCRETE; + float fvol; + float fvolbar; + char *rgsz[4]; + int cnt; + float fattn = ATTN_NORM; + int entity; + char *pTextureName; + char texname[ 64 ]; + char szbuffer[ 64 ]; + + entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); + + // FIXME check if playtexture sounds movevar is set + // + + chTextureType = 0; + + // Player + if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + { + // hit body + chTextureType = CHAR_TEX_FLESH; + } + else if ( entity == 0 ) + { + // get texture from entity or world (world is ent(0)) + pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); + + if ( pTextureName ) + { + strcpy( texname, pTextureName ); + pTextureName = texname; + + // 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; + + // get texture type + chTextureType = PM_FindTextureType( 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; + } + + // play material hit sound + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); + return fvolbar; +} + +char *EV_HLDM_DamageDecal( physent_t *pe ) +{ + static char decalname[ 32 ]; + int idx; + + if ( pe->classnumber == 1 ) + { + idx = gEngfuncs.pfnRandomLong( 0, 2 ); + sprintf( decalname, "{break%i", idx + 1 ); + } + else if ( pe->rendermode != kRenderNormal ) + { + sprintf( decalname, "{bproof1" ); + } + else + { + idx = gEngfuncs.pfnRandomLong( 0, 4 ); + sprintf( decalname, "{shot%i", idx + 1 ); + } + return decalname; +} + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) +{ + int iRand; + physent_t *pe; + + gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); + + iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); + if ( iRand < (0x7fff/2) )// not every bullet makes a sound. + { + switch( iRand % 5) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + // Only decal brush models such as the world etc. + if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) + { + if ( CVAR_GET_FLOAT( "r_decals" ) ) + { + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); + } + } +} + +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) +{ + physent_t *pe; + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + if ( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) + { + 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 + EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) ); + break; + } + } +} + +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) +{ + int tracer = 0; + int i; + qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; + + if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) + { + vec3_t vecTracerSrc; + + if ( player ) + { + vec3_t offset( 0, 0, -4 ); + + // adjust tracer position for player + for ( i = 0; i < 3; i++ ) + { + vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + } + } + else + { + VectorCopy( vecSrc, vecTracerSrc ); + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = 1; + + switch( iBulletType ) + { + case BULLET_PLAYER_MP5: + case BULLET_MONSTER_MP5: + case BULLET_MONSTER_9MM: + case BULLET_MONSTER_12MM: + default: + EV_CreateTracer( vecTracerSrc, end ); + break; + } + } + + return tracer; +} + + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. +================ +*/ +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) +{ + int i; + pmtrace_t tr; + int iShot; + int tracer; + + for ( iShot = 1; iShot <= cShots; iShot++ ) + { + vec3_t vecDir, vecEnd; + + float x, y, z; + //We randomize for the Shotgun. + if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) + { + do { + x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + z = x*x+y*y; + } while (z > 1); + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + }//But other guns already have their spread randomized in the synched spread. + else + { + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + } + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); + + // do damage, paint decals + if ( tr.fraction != 1.0 ) + { + switch(iBulletType) + { + default: + case BULLET_PLAYER_9MM: + + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + case BULLET_PLAYER_MP5: + + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + case BULLET_PLAYER_BUCKSHOT: + + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + case BULLET_PLAYER_357: + + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + + break; + + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } +} + +//====================== +// GLOCK START +//====================== +void EV_FireGlock1( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int empty; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + empty = args->bparam1; + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); + + V_PunchAxis( 0, -2.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2 ); +} + +void EV_FireGlock2( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); + + V_PunchAxis( 0, -2.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + +} +//====================== +// GLOCK END +//====================== + +//====================== +// SHOTGUN START +//====================== +void EV_FireShotGunDouble( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + int j; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); + V_PunchAxis( 0, -10.0 ); + } + + for ( j = 0; j < 2; j++ ) + { + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + } +} + +void EV_FireShotGunSingle( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); + + V_PunchAxis( 0, -5.0 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + } +} +//====================== +// SHOTGUN END +//====================== + +//====================== +// MP5 START +//====================== +void EV_FireMP5( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); + + V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + } +} + +// We only predict the animation and sound +// The grenade is still launched from the server. +void EV_FireMP52( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); + V_PunchAxis( 0, -10 ); + } + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + } +} +//====================== +// MP5 END +//====================== + +//====================== +// PHYTON START +// ( .357 ) +//====================== +void EV_FirePython( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + if ( EV_IsLocal( idx ) ) + { + // Python uses different body in multiplayer versus single player + int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; + + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); + + V_PunchAxis( 0, -10.0 ); + } + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); +} +//====================== +// PHYTON END +// ( .357 ) +//====================== + +//====================== +// GAUSS START +//====================== +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +void EV_SpinGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int iSoundState = 0; + + int pitch; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + pitch = args->iparam1; + + iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); +} + +/* +============================== +EV_StopPreviousGauss + +============================== +*/ +void EV_StopPreviousGauss( int idx ) +{ + // Make sure we don't have a gauss spin event in the queue for this guy + gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); +} + +extern float g_flApplyVel; + +void EV_FireGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + float flDamage = args->fparam1; + int primaryfire = args->bparam1; + + int m_fPrimaryFire = args->bparam1; + int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + vec3_t vecSrc; + vec3_t vecDest; + edict_t *pentIgnore; + pmtrace_t tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + physent_t *pEntity; + int m_iBeam, m_iGlow, m_iBalls; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + if ( args->bparam2 ) + { + EV_StopPreviousGauss( idx ); + return; + } + +// Con_Printf( "Firing gauss with %f\n", flDamage ); + EV_GetGunPosition( args, vecSrc, origin ); + + m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); + m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); + + AngleVectors( angles, forward, right, up ); + + VectorMA( vecSrc, 8192, forward, vecDest ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); + + if ( m_fPrimaryFire == false ) + g_flApplyVel = flDamage; + + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + while (flDamage > 10 && nMaxHits > 0) + { + nMaxHits--; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( tr.allsolid ) + break; + + if (fFirstBeam) + { + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + } + fFirstBeam = 0; + + gEngfuncs.pEfxAPI->R_BeamEntPoint( + idx | 0x1000, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + else + { + gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + + pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + if ( pEntity == NULL ) + break; + + if ( pEntity->solid == SOLID_BSP ) + { + float n; + + pentIgnore = NULL; + + n = -DotProduct( tr.plane.normal, forward ); + + if (n < 0.5) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + vec3_t r; + + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); + + flMaxFrac = flMaxFrac - tr.fraction; + + VectorCopy( r, forward ); + + VectorMA( tr.endpos, 8.0, forward, vecSrc ); + VectorMA( vecSrc, 8192.0, forward, vecDest ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); + + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + + // lose energy + if ( n == 0 ) + { + n = 0.1; + } + + flDamage = flDamage * (1 - n); + + } + else + { + // tunnel + EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // 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 ) + { + vec3_t start; + + VectorMA( tr.endpos, 8.0, forward, start ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); + + if ( !beam_tr.allsolid ) + { + vec3_t delta; + float n; + + // trace backwards to find exit point + + gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); + + VectorSubtract( beam_tr.endpos, tr.endpos, delta ); + + n = Length( delta ); + + if (n < flDamage) + { + if (n == 0) + n = 1; + flDamage -= n; + + // absorption balls + { + vec3_t fwd; + VectorSubtract( tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + } + + //////////////////////////////////// WHAT TO DO HERE + // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // balls + { + vec3_t fwd; + VectorSubtract( beam_tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + 255, 40 ); + } + + VectorAdd( beam_tr.endpos, forward, vecSrc ); + } + } + else + { + flDamage = 0; + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } + else + { + if ( m_fPrimaryFire ) + { + // slug doesn't punch through ever with primary + // fire, so leave a little glowy bit and make some balls + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); + + { + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 200 ); + } + } + + flDamage = 0; + } + } + } + else + { + VectorAdd( tr.endpos, forward, vecSrc ); + } + } +} +//====================== +// GAUSS END +//====================== + +//====================== +// CROWBAR START +//====================== + +enum crowbar_e { + CROWBAR_IDLE = 0, + CROWBAR_DRAW, + CROWBAR_HOLSTER, + CROWBAR_ATTACK1HIT, + CROWBAR_ATTACK1MISS, + CROWBAR_ATTACK2MISS, + CROWBAR_ATTACK2HIT, + CROWBAR_ATTACK3MISS, + CROWBAR_ATTACK3HIT +}; + +int g_iSwing; + +//Only predict the miss sounds, hit sounds are still played +//server side, so players don't get the wrong idea. +void EV_Crowbar( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + //Play Swing sound + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); + + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); + + switch( (g_iSwing++) % 3 ) + { + case 0: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; + case 1: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; + case 2: + gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; + } + } +} +//====================== +// CROWBAR END +//====================== + +//====================== +// CROSSBOW START +//====================== +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 +}; + +//===================== +// EV_BoltCallback +// This function is used to correct the origin and angles +// of the bolt, so it looks like it's stuck on the wall. +//===================== +void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + ent->entity.origin = ent->entity.baseline.vuser1; + ent->entity.angles = ent->entity.baseline.vuser2; +} + +void EV_FireCrossbow2( event_args_t *args ) +{ + vec3_t vecSrc, vecEnd; + vec3_t up, right, forward; + pmtrace_t tr; + + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorMA( vecSrc, 8192, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + } + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + //We hit something + if ( tr.fraction < 1.0 ) + { + physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + + //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). + if ( pe->solid != SOLID_BSP ) + { + switch( gEngfuncs.pfnRandomLong(0,1) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. + else if ( pe->rendermode == kRenderNormal ) + { + gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); + + //Not underwater, do some sparks... + if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) + gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); + + vec3_t vBoltAngles; + int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); + + VectorAngles( forward, vBoltAngles ); + + TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); + + if ( bolt ) + { + bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. + bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit + bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward! + bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall) + } + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +//TODO: Fully predict the fliying bolt. +void EV_FireCrossbow( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); + else if ( args->iparam2 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); + + V_PunchAxis( 0, -2.0 ); + } +} +//====================== +// CROSSBOW END +//====================== + +//====================== +// RPG START +//====================== +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 +}; + +void EV_FireRpg( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); + + V_PunchAxis( 0, -5.0 ); + } +} +//====================== +// RPG END +//====================== + +//====================== +// EGON END +//====================== +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 +}; + +int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; +int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; + +enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; +enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + +#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 ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +BEAM *pBeam; +BEAM *pBeam2; + +void EV_EgonFire( event_args_t *args ) +{ + int idx, iFireState, iFireMode; + vec3_t origin; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + iFireState = args->iparam1; + iFireMode = args->iparam2; + int iStartup = args->bparam1; + + + if ( iStartup ) + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); + } + else + { + if ( iFireMode == FIRE_WIDE ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); + } + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); + + if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. + { + vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; + pmtrace_t tr; + + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); + + if ( pl ) + { + VectorCopy( gHUD.m_vecAngles, angles ); + + AngleVectors( angles, forward, right, up ); + + EV_GetGunPosition( args, vecSrc, pl->origin ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); + + float r = 50.0f; + float g = 50.0f; + float b = 125.0f; + + if ( IEngineStudio.IsHardware() ) + { + r /= 100.0f; + g /= 100.0f; + } + + + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); + + if ( pBeam ) + pBeam->flags |= ( FBEAM_SINENOISE ); + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); + } + } +} + +void EV_EgonStop( event_args_t *args ) +{ + int idx; + vec3_t origin; + + idx = args->entindex; + VectorCopy ( args->origin, origin ); + + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); + + if ( args->iparam1 ) + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); + + if ( EV_IsLocal( idx ) ) + { + if ( pBeam ) + { + pBeam->die = 0.0; + pBeam = NULL; + } + + + if ( pBeam2 ) + { + pBeam2->die = 0.0; + pBeam2 = NULL; + } + } +} +//====================== +// EGON END +//====================== + +//====================== +// HORNET START +//====================== +enum hgun_e { + HGUN_IDLE1 = 0, + HGUN_FIDGETSWAY, + HGUN_FIDGETSHAKE, + HGUN_DOWN, + HGUN_UP, + HGUN_SHOOT +}; + +void EV_HornetGunFire( event_args_t *args ) +{ + int idx, iFireMode; + vec3_t origin, angles, vecSrc, forward, right, up; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + iFireMode = args->iparam1; + + //Only play the weapon anims if I shot it. + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); + gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); + } + + switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; + } +} +//====================== +// HORNET END +//====================== + +//====================== +// TRIPMINE START +//====================== +enum tripmine_e { + TRIPMINE_IDLE1 = 0, + TRIPMINE_IDLE2, + TRIPMINE_ARM1, + TRIPMINE_ARM2, + TRIPMINE_FIDGET, + TRIPMINE_HOLSTER, + TRIPMINE_DRAW, + TRIPMINE_WORLD, + TRIPMINE_GROUND, +}; + +//We only check if it's possible to put a trip mine +//and if it is, then we play the animation. Server still places it. +void EV_TripmineFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + + vecSrc = vecSrc + view_ofs; + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); + + //Hit something solid + if ( tr.fraction < 1.0 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// TRIPMINE END +//====================== + +//====================== +// SQUEAK START +//====================== +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) + +void EV_SnarkFire( event_args_t *args ) +{ + int idx; + vec3_t vecSrc, angles, view_ofs, forward; + pmtrace_t tr; + + idx = args->entindex; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); + + AngleVectors ( angles, forward, NULL, NULL ); + + if ( !EV_IsLocal ( idx ) ) + return; + + if ( args->ducking ) + vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); + + //Find space to drop the thing. + if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} +//====================== +// SQUEAK END +//====================== + +void EV_TrainPitchAdjust( event_args_t *args ) +{ + int idx; + vec3_t origin; + + unsigned short us_params; + int noise; + float m_flVolume; + int pitch; + int stop; + + char sz[ 256 ]; + + idx = args->entindex; + + VectorCopy( args->origin, origin ); + + us_params = (unsigned short)args->iparam1; + stop = args->bparam1; + + m_flVolume = (float)(us_params & 0x003f)/40.0; + noise = (int)(((us_params) >> 12 ) & 0x0007); + pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); + + switch ( noise ) + { + case 1: strcpy( sz, "plats/ttrain1.wav"); break; + case 2: strcpy( sz, "plats/ttrain2.wav"); break; + case 3: strcpy( sz, "plats/ttrain3.wav"); break; + case 4: strcpy( sz, "plats/ttrain4.wav"); break; + case 5: strcpy( sz, "plats/ttrain6.wav"); break; + case 6: strcpy( sz, "plats/ttrain7.wav"); break; + default: + // no sound + strcpy( sz, "" ); + return; + } + + if ( stop ) + { + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); + } + else + { + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + } +} + +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) +{ + return 0; } \ No newline at end of file diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h index 567e6877..5fd90c1a 100644 --- a/cl_dll/ev_hldm.h +++ b/cl_dll/ev_hldm.h @@ -1,95 +1,95 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined ( EV_HLDMH ) -#define EV_HLDMH - -// bullet types -typedef enum -{ - BULLET_NONE = 0, - BULLET_PLAYER_9MM, // glock - BULLET_PLAYER_MP5, // mp5 - BULLET_PLAYER_357, // python - BULLET_PLAYER_BUCKSHOT, // shotgun - BULLET_PLAYER_CROWBAR, // crowbar swipe - - BULLET_MONSTER_9MM, - BULLET_MONSTER_MP5, - BULLET_MONSTER_12MM, -} Bullet; - -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 -}; - -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 -}; - -enum mp5_e -{ - MP5_LONGIDLE = 0, - MP5_IDLE1, - MP5_LAUNCH, - MP5_RELOAD, - MP5_DEPLOY, - MP5_FIRE1, - MP5_FIRE2, - MP5_FIRE3, -}; - -enum python_e { - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -#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 -}; - -void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); -void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); -void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( EV_HLDMH ) +#define EV_HLDMH + +// bullet types +typedef enum +{ + BULLET_NONE = 0, + BULLET_PLAYER_9MM, // glock + BULLET_PLAYER_MP5, // mp5 + BULLET_PLAYER_357, // python + BULLET_PLAYER_BUCKSHOT, // shotgun + BULLET_PLAYER_CROWBAR, // crowbar swipe + + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, +} Bullet; + +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 +}; + +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 +}; + +enum mp5_e +{ + MP5_LONGIDLE = 0, + MP5_IDLE1, + MP5_LAUNCH, + MP5_RELOAD, + MP5_DEPLOY, + MP5_FIRE1, + MP5_FIRE2, + MP5_FIRE3, +}; + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +#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 +}; + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); + #endif // EV_HLDMH \ No newline at end of file diff --git a/cl_dll/events.cpp b/cl_dll/events.cpp index 65c842bc..a51dd72f 100644 --- a/cl_dll/events.cpp +++ b/cl_dll/events.cpp @@ -1,23 +1,23 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" - -void Game_HookEvents( void ); - -/* -=================== -EV_HookEvents - -See if game specific code wants to hook any events. -=================== -*/ -void EV_HookEvents( void ) -{ - Game_HookEvents(); +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" + +void Game_HookEvents( void ); + +/* +=================== +EV_HookEvents + +See if game specific code wants to hook any events. +=================== +*/ +void EV_HookEvents( void ) +{ + Game_HookEvents(); } \ No newline at end of file diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h index e8b145be..5c4677a2 100644 --- a/cl_dll/eventscripts.h +++ b/cl_dll/eventscripts.h @@ -1,73 +1,73 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// eventscripts.h -#if !defined ( EVENTSCRIPTSH ) -#define EVENTSCRIPTSH - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 -#define VEC_DUCK_VIEW 12 - -#define FTENT_FADEOUT 0x00000080 - -#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. - -// time-based damage -//mask off TF-specific stuff too -#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage - -#define DMG_DROWN (1 << 14) // Drowning -#define DMG_FIRSTTIMEBASED DMG_DROWN - -#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) - -//TF ADDITIONS -#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn -#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance -#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. -#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor -#define DMG_AIMED (1 << 28) // Does Hit location damage -#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls - -#define DMG_CALTROP (1<<30) -#define DMG_HALLUC (1<<31) - -// Some of these are HL/TFC specific? -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); -void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); -void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); -qboolean EV_IsLocal( int idx ); -qboolean EV_IsPlayer( int idx ); -void EV_CreateTracer( float *start, float *end ); - -struct cl_entity_s *GetEntity( int idx ); -struct cl_entity_s *GetViewEntity( void ); -void EV_MuzzleFlash( void ); - -#endif // EVENTSCRIPTSH +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// eventscripts.h +#if !defined ( EVENTSCRIPTSH ) +#define EVENTSCRIPTSH + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 +#define VEC_DUCK_VIEW 12 + +#define FTENT_FADEOUT 0x00000080 + +#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. + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#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) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// Some of these are HL/TFC specific? +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); +void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); +void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); +qboolean EV_IsLocal( int idx ); +qboolean EV_IsPlayer( int idx ); +void EV_CreateTracer( float *start, float *end ); + +struct cl_entity_s *GetEntity( int idx ); +struct cl_entity_s *GetViewEntity( void ); +void EV_MuzzleFlash( void ); + +#endif // EVENTSCRIPTSH diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index ab8f70a4..23b0691e 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -1,101 +1,101 @@ -/*** -* -* 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. -* -****/ -// -// flashlight.cpp -// -// implementation of CHudFlashlight class -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - - - -DECLARE_MESSAGE(m_Flash, FlashBat) -DECLARE_MESSAGE(m_Flash, Flashlight) - -#define BAT_NAME "sprites/%d_Flashlight.spr" - -int CHudFlashlight::Init(void) -{ - m_fFade = 0; - m_fOn = 0; - - HOOK_MESSAGE(Flashlight); - HOOK_MESSAGE(FlashBat); - - m_iFlags |= HUD_ACTIVE; - - gHUD.AddHudElem(this); - - return 1; -}; - -void CHudFlashlight::Reset(void) -{ - m_fFade = 0; - m_fOn = 0; -} - -int CHudFlashlight::VidInit(void) -{ - int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); - int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); - int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); - - m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); - m_hSprite2 = gHUD.GetSprite(HUD_flash_full); - m_hBeam = gHUD.GetSprite(HUD_flash_beam); - m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); - m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); - m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); - m_iWidth = m_prc2->right - m_prc2->left; - - return 1; -}; - -int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) -{ - - - BEGIN_READ( pbuf, iSize ); - int x = READ_BYTE(); - m_iBat = x; - m_flBat = ((float)x)/100.0; - - return 1; -} - -int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) -{ - - BEGIN_READ( pbuf, iSize ); - m_fOn = READ_BYTE(); - int x = READ_BYTE(); - m_iBat = x; - m_flBat = ((float)x)/100.0; - - return 1; -} - -int CHudFlashlight::Draw(float flTime) -{ +/*** +* +* 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. +* +****/ +// +// flashlight.cpp +// +// implementation of CHudFlashlight class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + + +DECLARE_MESSAGE(m_Flash, FlashBat) +DECLARE_MESSAGE(m_Flash, Flashlight) + +#define BAT_NAME "sprites/%d_Flashlight.spr" + +int CHudFlashlight::Init(void) +{ + m_fFade = 0; + m_fOn = 0; + + HOOK_MESSAGE(Flashlight); + HOOK_MESSAGE(FlashBat); + + m_iFlags |= HUD_ACTIVE; + + gHUD.AddHudElem(this); + + return 1; +}; + +void CHudFlashlight::Reset(void) +{ + m_fFade = 0; + m_fOn = 0; +} + +int CHudFlashlight::VidInit(void) +{ + int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); + int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); + int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); + + m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); + m_hSprite2 = gHUD.GetSprite(HUD_flash_full); + m_hBeam = gHUD.GetSprite(HUD_flash_beam); + m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); + m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); + m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); + m_iWidth = m_prc2->right - m_prc2->left; + + return 1; +}; + +int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) +{ + + + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) +{ + + BEGIN_READ( pbuf, iSize ); + m_fOn = READ_BYTE(); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight::Draw(float flTime) +{ static bool show = ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ); if( show != !( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) ) { @@ -106,53 +106,53 @@ int CHudFlashlight::Draw(float flTime) } } if ( !show ) - return 1; - - int r, g, b, x, y, a; - wrect_t rc; - - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) - return 1; - - if (m_fOn) - a = 225; - else - a = MIN_ALPHA; - - if (m_flBat < 0.20) - UnpackRGB(r,g,b, RGB_REDISH); - else - UnpackRGB(r,g,b, RGB_YELLOWISH); - - ScaleColors(r, g, b, a); - - y = (m_prc1->bottom - m_prc2->top)/2; - x = ScreenWidth - m_iWidth - m_iWidth/2 ; - - // Draw the flashlight casing - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prc1); - - if ( m_fOn ) - { // draw the flashlight beam - x = ScreenWidth - m_iWidth/2; - - SPR_Set( m_hBeam, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prcBeam ); - } - - // draw the flashlight energy level - x = ScreenWidth - m_iWidth - m_iWidth/2 ; - int iOffset = m_iWidth * (1.0 - m_flBat); - if (iOffset < m_iWidth) - { - rc = *m_prc2; - rc.left += iOffset; - - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x + iOffset, y, &rc); - } - - - return 1; + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if (m_fOn) + a = 225; + else + a = MIN_ALPHA; + + if (m_flBat < 0.20) + UnpackRGB(r,g,b, RGB_REDISH); + else + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a); + + y = (m_prc1->bottom - m_prc2->top)/2; + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + + // Draw the flashlight casing + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prc1); + + if ( m_fOn ) + { // draw the flashlight beam + x = ScreenWidth - m_iWidth/2; + + SPR_Set( m_hBeam, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prcBeam ); + } + + // draw the flashlight energy level + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + int iOffset = m_iWidth * (1.0 - m_flBat); + if (iOffset < m_iWidth) + { + rc = *m_prc2; + rc.left += iOffset; + + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x + iOffset, y, &rc); + } + + + return 1; } \ No newline at end of file diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 1a514815..71f97923 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -1,184 +1,184 @@ -/*** -* -* 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. -* -****/ -// -// Geiger.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include - -#include "parsemsg.h" - -DECLARE_MESSAGE(m_Geiger, Geiger ) - -int CHudGeiger::Init(void) -{ - HOOK_MESSAGE( Geiger ); - - m_iGeigerRange = 0; - m_iFlags = 0; - - gHUD.AddHudElem(this); - - srand( (unsigned)time( NULL ) ); - - return 1; -}; - -int CHudGeiger::VidInit(void) -{ - return 1; -}; - -int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) -{ - - BEGIN_READ( pbuf, iSize ); - - // update geiger data - m_iGeigerRange = READ_BYTE(); - m_iGeigerRange = m_iGeigerRange << 2; - - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -int CHudGeiger::Draw (float flTime) -{ - int pct; - float flvol = 0.0f; - int rg[3]; - int i; - - if (m_iGeigerRange < 1000 && m_iGeigerRange > 0) - { - // peicewise linear is better than continuous formula for this - if (m_iGeigerRange > 800) - { - pct = 0; //Con_Printf ( "range > 800\n"); - } - else if (m_iGeigerRange > 600) - { - pct = 2; - flvol = 0.4; //Con_Printf ( "range > 600\n"); - rg[0] = 1; - rg[1] = 1; - i = 2; - } - else if (m_iGeigerRange > 500) - { - pct = 4; - flvol = 0.5; //Con_Printf ( "range > 500\n"); - rg[0] = 1; - rg[1] = 2; - i = 2; - } - else if (m_iGeigerRange > 400) - { - pct = 8; - flvol = 0.6; //Con_Printf ( "range > 400\n"); - rg[0] = 1; - rg[1] = 2; - rg[2] = 3; - i = 3; - } - else if (m_iGeigerRange > 300) - { - pct = 8; - flvol = 0.7; //Con_Printf ( "range > 300\n"); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; - i = 3; - } - else if (m_iGeigerRange > 200) - { - pct = 28; - flvol = 0.78; //Con_Printf ( "range > 200\n"); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; - i = 3; - } - else if (m_iGeigerRange > 150) - { - pct = 40; - flvol = 0.80; //Con_Printf ( "range > 150\n"); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; - i = 3; - } - else if (m_iGeigerRange > 100) - { - pct = 60; - flvol = 0.85; //Con_Printf ( "range > 100\n"); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; - i = 3; - } - else if (m_iGeigerRange > 75) - { - pct = 80; - flvol = 0.9; //Con_Printf ( "range > 75\n"); - //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; - rg[0] = 4; - rg[1] = 5; - rg[2] = 6; - i = 3; - } - else if (m_iGeigerRange > 50) - { - pct = 90; - flvol = 0.95; //Con_Printf ( "range > 50\n"); - rg[0] = 5; - rg[1] = 6; - i = 2; - } - else - { - pct = 95; - flvol = 1.0; //Con_Printf ( "range < 50\n"); - rg[0] = 5; - rg[1] = 6; - i = 2; - } - - flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); - - if ((rand() & 127) < pct || (rand() & 127) < pct) - { - //S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100); - char sz[256]; - - int j = rand() & 1; - if (i > 2) - j += rand() & 1; - - sprintf(sz, "player/geiger%d.wav", j + 1); - PlaySound(sz, flvol); - - } - } - - return 1; -} +/*** +* +* 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. +* +****/ +// +// Geiger.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include + +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Geiger, Geiger ) + +int CHudGeiger::Init(void) +{ + HOOK_MESSAGE( Geiger ); + + m_iGeigerRange = 0; + m_iFlags = 0; + + gHUD.AddHudElem(this); + + srand( (unsigned)time( NULL ) ); + + return 1; +}; + +int CHudGeiger::VidInit(void) +{ + return 1; +}; + +int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) +{ + + BEGIN_READ( pbuf, iSize ); + + // update geiger data + m_iGeigerRange = READ_BYTE(); + m_iGeigerRange = m_iGeigerRange << 2; + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +int CHudGeiger::Draw (float flTime) +{ + int pct; + float flvol = 0.0f; + int rg[3]; + int i; + + if (m_iGeigerRange < 1000 && m_iGeigerRange > 0) + { + // peicewise linear is better than continuous formula for this + if (m_iGeigerRange > 800) + { + pct = 0; //Con_Printf ( "range > 800\n"); + } + else if (m_iGeigerRange > 600) + { + pct = 2; + flvol = 0.4; //Con_Printf ( "range > 600\n"); + rg[0] = 1; + rg[1] = 1; + i = 2; + } + else if (m_iGeigerRange > 500) + { + pct = 4; + flvol = 0.5; //Con_Printf ( "range > 500\n"); + rg[0] = 1; + rg[1] = 2; + i = 2; + } + else if (m_iGeigerRange > 400) + { + pct = 8; + flvol = 0.6; //Con_Printf ( "range > 400\n"); + rg[0] = 1; + rg[1] = 2; + rg[2] = 3; + i = 3; + } + else if (m_iGeigerRange > 300) + { + pct = 8; + flvol = 0.7; //Con_Printf ( "range > 300\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 200) + { + pct = 28; + flvol = 0.78; //Con_Printf ( "range > 200\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 150) + { + pct = 40; + flvol = 0.80; //Con_Printf ( "range > 150\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 100) + { + pct = 60; + flvol = 0.85; //Con_Printf ( "range > 100\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 75) + { + pct = 80; + flvol = 0.9; //Con_Printf ( "range > 75\n"); + //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; + rg[0] = 4; + rg[1] = 5; + rg[2] = 6; + i = 3; + } + else if (m_iGeigerRange > 50) + { + pct = 90; + flvol = 0.95; //Con_Printf ( "range > 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + else + { + pct = 95; + flvol = 1.0; //Con_Printf ( "range < 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + + flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); + + if ((rand() & 127) < pct || (rand() & 127) < pct) + { + //S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100); + char sz[256]; + + int j = rand() & 1; + if (i > 2) + j += rand() & 1; + + sprintf(sz, "player/geiger%d.wav", j + 1); + PlaySound(sz, flvol); + + } + } + + return 1; +} diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index 9a4ff660..c73b0f5c 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -1,483 +1,483 @@ -/*** -* -* 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. -* -****/ -// -// Health.cpp -// -// implementation of CHudHealth class -// - -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" -#include - -#include "mobility_int.h" - -DECLARE_MESSAGE(m_Health, Health ) -DECLARE_MESSAGE(m_Health, Damage ) - -#define PAIN_NAME "sprites/%d_pain.spr" -#define DAMAGE_NAME "sprites/%d_dmg.spr" - -int giDmgHeight, giDmgWidth; - -int giDmgFlags[NUM_DMG_TYPES] = -{ - DMG_POISON, - DMG_ACID, - DMG_FREEZE|DMG_SLOWFREEZE, - DMG_DROWN, - DMG_BURN|DMG_SLOWBURN, - DMG_NERVEGAS, - DMG_RADIATION, - DMG_SHOCK, - DMG_CALTROP, - DMG_TRANQ, - DMG_CONCUSS, - DMG_HALLUC -}; - -int CHudHealth::Init(void) -{ - HOOK_MESSAGE(Health); - HOOK_MESSAGE(Damage); - m_iHealth = 100; - m_fFade = 0; - m_iFlags = 0; - m_bitsDamage = 0; - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - giDmgHeight = 0; - giDmgWidth = 0; - - memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); - - - gHUD.AddHudElem(this); - return 1; -} - -void CHudHealth::Reset( void ) -{ - // make sure the pain compass is cleared when the player respawns - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - - - // force all the flashing damage icons to expire - m_bitsDamage = 0; - for ( int i = 0; i < NUM_DMG_TYPES; i++ ) - { - m_dmg[i].fExpire = 0; - } -} - -int CHudHealth::VidInit(void) -{ - m_hSprite = 0; - - m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; - m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); - - giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; - giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; - return 1; -} - -int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) -{ - // TODO: update local health data - BEGIN_READ( pbuf, iSize ); - int x = READ_BYTE(); - - m_iFlags |= HUD_ACTIVE; - - // Only update the fade if we've changed health - if (x != m_iHealth) - { - m_fFade = FADE_TIME; - m_iHealth = x; - } - - return 1; -} - - -int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int armor = READ_BYTE(); // armor - int damageTaken = READ_BYTE(); // health - long bitsDamage = READ_LONG(); // damage bits - - vec3_t vecFrom; - - for ( int i = 0 ; i < 3 ; i++) - vecFrom[i] = READ_COORD(); - - UpdateTiles(gHUD.m_flTime, bitsDamage); - - // Actually took damage? - if ( damageTaken > 0 || armor > 0 ) - { - CalcDamageDirection(vecFrom); - - if( gMobileEngfuncs && damageTaken > 0 ) - { - float time = damageTaken * 4.0f; - - if( time > 200.0f ) time = 200.0f; - gMobileEngfuncs->pfnVibrate( time, 0 ); - } - } - - return 1; -} - - -// Returns back a color from the -// Green <-> Yellow <-> Red ramp -void CHudHealth::GetPainColor( int &r, int &g, int &b ) -{ - int iHealth = m_iHealth; - - if (iHealth > 25) - iHealth -= 25; - else if ( iHealth < 0 ) - iHealth = 0; -#if 0 - g = iHealth * 255 / 100; - r = 255 - g; - b = 0; -#else - if (m_iHealth > 25) - { - UnpackRGB(r,g,b, RGB_YELLOWISH); - } - else - { - r = 250; - g = 0; - b = 0; - } -#endif -} - -int CHudHealth::Draw(float flTime) -{ - int r, g, b; - int a = 0, x, y; - int HealthWidth; - - if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) - return 1; - - if ( !m_hSprite ) - m_hSprite = LoadSprite(PAIN_NAME); - - // Has health changed? Flash the health # - if (m_fFade) - { - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) - { - a = MIN_ALPHA; - m_fFade = 0; - } - - // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - - } - else - a = MIN_ALPHA; - - // If health is getting low, make it bright red - if (m_iHealth <= 15) - a = 255; - - GetPainColor( r, g, b ); - ScaleColors(r, g, b, a ); - - // Only draw health if we have the suit. - if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) - { - HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; - - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = CrossWidth /2; - - SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); - - x = CrossWidth + HealthWidth / 2; - - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); - - x += HealthWidth/2; - - int iHeight = gHUD.m_iFontHeight; - int iWidth = HealthWidth/10; - FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); - } - - DrawDamage(flTime); - return DrawPain(flTime); -} - -void CHudHealth::CalcDamageDirection(vec3_t vecFrom) -{ - vec3_t forward, right, up; - float side, front; - vec3_t vecOrigin, vecAngles; - - if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - return; - } - - - memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); - memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); - - - VectorSubtract (vecFrom, vecOrigin, vecFrom); - - float flDistToTarget = vecFrom.Length(); - - vecFrom = vecFrom.Normalize(); - AngleVectors (vecAngles, forward, right, up); - - front = DotProduct (vecFrom, right); - side = DotProduct (vecFrom, forward); - - if (flDistToTarget <= 50) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; - } - else - { - if (side > 0) - { - if (side > 0.3) - m_fAttackFront = max(m_fAttackFront, side); - } - else - { - float f = fabs(side); - if (f > 0.3) - m_fAttackRear = max(m_fAttackRear, f); - } - - if (front > 0) - { - if (front > 0.3) - m_fAttackRight = max(m_fAttackRight, front); - } - else - { - float f = fabs(front); - if (f > 0.3) - m_fAttackLeft = max(m_fAttackLeft, f); - } - } -} - -int CHudHealth::DrawPain(float flTime) -{ - if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) - return 1; - - int r, g, b; - int x, y, a, shade; - - // TODO: get the shift value of the health - a = 255; // max brightness until then - - float fFade = gHUD.m_flTimeDelta * 2; - - // SPR_Draw top - if (m_fAttackFront > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackFront, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; - y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; - SPR_DrawAdditive(0, x, y, NULL); - m_fAttackFront = max( 0, m_fAttackFront - fFade ); - } else - m_fAttackFront = 0; - - if (m_fAttackRight > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackRight, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; - y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; - SPR_DrawAdditive(1, x, y, NULL); - m_fAttackRight = max( 0, m_fAttackRight - fFade ); - } else - m_fAttackRight = 0; - - if (m_fAttackRear > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackRear, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; - y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; - SPR_DrawAdditive(2, x, y, NULL); - m_fAttackRear = max( 0, m_fAttackRear - fFade ); - } else - m_fAttackRear = 0; - - if (m_fAttackLeft > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackLeft, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; - y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; - SPR_DrawAdditive(3, x, y, NULL); - - m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); - } else - m_fAttackLeft = 0; - - return 1; -} - -int CHudHealth::DrawDamage(float flTime) -{ - int i, r, g, b, a; - DAMAGE_IMAGE *pdmg; - - if (!m_bitsDamage) - return 1; - - UnpackRGB(r,g,b, RGB_YELLOWISH); - - a = (int)( fabs(sin(flTime*2)) * 256.0); - - ScaleColors(r, g, b, a); - - // Draw all the items - for (i = 0; i < NUM_DMG_TYPES; i++) - { - if (m_bitsDamage & giDmgFlags[i]) - { - pdmg = &m_dmg[i]; - SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); - SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); - } - } - - - // check for bits that should be expired - for ( i = 0; i < NUM_DMG_TYPES; i++ ) - { - pdmg = &m_dmg[i]; - - if ( m_bitsDamage & giDmgFlags[i] ) - { - pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); - - if ( pdmg->fExpire <= flTime // when the time has expired - && a < 40 ) // and the flash is at the low point of the cycle - { - pdmg->fExpire = 0; - - int y = pdmg->y; - pdmg->x = pdmg->y = 0; - - // move everyone above down - for (int j = 0; j < NUM_DMG_TYPES; j++) - { - pdmg = &m_dmg[j]; - if ((pdmg->y) && (pdmg->y < y)) - pdmg->y += giDmgHeight; - - } - - m_bitsDamage &= ~giDmgFlags[i]; // clear the bits - } - } - } - - return 1; -} - - -void CHudHealth::UpdateTiles(float flTime, long bitsDamage) -{ - DAMAGE_IMAGE *pdmg; - - // Which types are new? - long bitsOn = ~m_bitsDamage & bitsDamage; - - for (int i = 0; i < NUM_DMG_TYPES; i++) - { - pdmg = &m_dmg[i]; - - // Is this one already on? - if (m_bitsDamage & giDmgFlags[i]) - { - pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration - if (!pdmg->fBaseline) - pdmg->fBaseline = flTime; - } - - // Are we just turning it on? - if (bitsOn & giDmgFlags[i]) - { - // put this one at the bottom - pdmg->x = giDmgWidth/8; - pdmg->y = ScreenHeight - giDmgHeight * 2; - pdmg->fExpire=flTime + DMG_IMAGE_LIFE; - - // move everyone else up - for (int j = 0; j < NUM_DMG_TYPES; j++) - { - if (j == i) - continue; - - pdmg = &m_dmg[j]; - if (pdmg->y) - pdmg->y -= giDmgHeight; - - } - pdmg = &m_dmg[i]; - } - } - - // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) - m_bitsDamage |= bitsDamage; -} +/*** +* +* 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. +* +****/ +// +// Health.cpp +// +// implementation of CHudHealth class +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include + +#include "mobility_int.h" + +DECLARE_MESSAGE(m_Health, Health ) +DECLARE_MESSAGE(m_Health, Damage ) + +#define PAIN_NAME "sprites/%d_pain.spr" +#define DAMAGE_NAME "sprites/%d_dmg.spr" + +int giDmgHeight, giDmgWidth; + +int giDmgFlags[NUM_DMG_TYPES] = +{ + DMG_POISON, + DMG_ACID, + DMG_FREEZE|DMG_SLOWFREEZE, + DMG_DROWN, + DMG_BURN|DMG_SLOWBURN, + DMG_NERVEGAS, + DMG_RADIATION, + DMG_SHOCK, + DMG_CALTROP, + DMG_TRANQ, + DMG_CONCUSS, + DMG_HALLUC +}; + +int CHudHealth::Init(void) +{ + HOOK_MESSAGE(Health); + HOOK_MESSAGE(Damage); + m_iHealth = 100; + m_fFade = 0; + m_iFlags = 0; + m_bitsDamage = 0; + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + giDmgHeight = 0; + giDmgWidth = 0; + + memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); + + + gHUD.AddHudElem(this); + return 1; +} + +void CHudHealth::Reset( void ) +{ + // make sure the pain compass is cleared when the player respawns + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + + + // force all the flashing damage icons to expire + m_bitsDamage = 0; + for ( int i = 0; i < NUM_DMG_TYPES; i++ ) + { + m_dmg[i].fExpire = 0; + } +} + +int CHudHealth::VidInit(void) +{ + m_hSprite = 0; + + m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; + m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); + + giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; + giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; + return 1; +} + +int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) +{ + // TODO: update local health data + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + + m_iFlags |= HUD_ACTIVE; + + // Only update the fade if we've changed health + if (x != m_iHealth) + { + m_fFade = FADE_TIME; + m_iHealth = x; + } + + return 1; +} + + +int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int armor = READ_BYTE(); // armor + int damageTaken = READ_BYTE(); // health + long bitsDamage = READ_LONG(); // damage bits + + vec3_t vecFrom; + + for ( int i = 0 ; i < 3 ; i++) + vecFrom[i] = READ_COORD(); + + UpdateTiles(gHUD.m_flTime, bitsDamage); + + // Actually took damage? + if ( damageTaken > 0 || armor > 0 ) + { + CalcDamageDirection(vecFrom); + + if( gMobileEngfuncs && damageTaken > 0 ) + { + float time = damageTaken * 4.0f; + + if( time > 200.0f ) time = 200.0f; + gMobileEngfuncs->pfnVibrate( time, 0 ); + } + } + + return 1; +} + + +// Returns back a color from the +// Green <-> Yellow <-> Red ramp +void CHudHealth::GetPainColor( int &r, int &g, int &b ) +{ + int iHealth = m_iHealth; + + if (iHealth > 25) + iHealth -= 25; + else if ( iHealth < 0 ) + iHealth = 0; +#if 0 + g = iHealth * 255 / 100; + r = 255 - g; + b = 0; +#else + if (m_iHealth > 25) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + } + else + { + r = 250; + g = 0; + b = 0; + } +#endif +} + +int CHudHealth::Draw(float flTime) +{ + int r, g, b; + int a = 0, x, y; + int HealthWidth; + + if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) + return 1; + + if ( !m_hSprite ) + m_hSprite = LoadSprite(PAIN_NAME); + + // Has health changed? Flash the health # + if (m_fFade) + { + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = MIN_ALPHA; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + // If health is getting low, make it bright red + if (m_iHealth <= 15) + a = 255; + + GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // Only draw health if we have the suit. + if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) + { + HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = CrossWidth /2; + + SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); + + x = CrossWidth + HealthWidth / 2; + + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + + x += HealthWidth/2; + + int iHeight = gHUD.m_iFontHeight; + int iWidth = HealthWidth/10; + FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); + } + + DrawDamage(flTime); + return DrawPain(flTime); +} + +void CHudHealth::CalcDamageDirection(vec3_t vecFrom) +{ + vec3_t forward, right, up; + float side, front; + vec3_t vecOrigin, vecAngles; + + if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + return; + } + + + memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); + memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); + + + VectorSubtract (vecFrom, vecOrigin, vecFrom); + + float flDistToTarget = vecFrom.Length(); + + vecFrom = vecFrom.Normalize(); + AngleVectors (vecAngles, forward, right, up); + + front = DotProduct (vecFrom, right); + side = DotProduct (vecFrom, forward); + + if (flDistToTarget <= 50) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; + } + else + { + if (side > 0) + { + if (side > 0.3) + m_fAttackFront = max(m_fAttackFront, side); + } + else + { + float f = fabs(side); + if (f > 0.3) + m_fAttackRear = max(m_fAttackRear, f); + } + + if (front > 0) + { + if (front > 0.3) + m_fAttackRight = max(m_fAttackRight, front); + } + else + { + float f = fabs(front); + if (f > 0.3) + m_fAttackLeft = max(m_fAttackLeft, f); + } + } +} + +int CHudHealth::DrawPain(float flTime) +{ + if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) + return 1; + + int r, g, b; + int x, y, a, shade; + + // TODO: get the shift value of the health + a = 255; // max brightness until then + + float fFade = gHUD.m_flTimeDelta * 2; + + // SPR_Draw top + if (m_fAttackFront > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackFront, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; + SPR_DrawAdditive(0, x, y, NULL); + m_fAttackFront = max( 0, m_fAttackFront - fFade ); + } else + m_fAttackFront = 0; + + if (m_fAttackRight > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRight, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; + SPR_DrawAdditive(1, x, y, NULL); + m_fAttackRight = max( 0, m_fAttackRight - fFade ); + } else + m_fAttackRight = 0; + + if (m_fAttackRear > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRear, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; + y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; + SPR_DrawAdditive(2, x, y, NULL); + m_fAttackRear = max( 0, m_fAttackRear - fFade ); + } else + m_fAttackRear = 0; + + if (m_fAttackLeft > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackLeft, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; + y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; + SPR_DrawAdditive(3, x, y, NULL); + + m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); + } else + m_fAttackLeft = 0; + + return 1; +} + +int CHudHealth::DrawDamage(float flTime) +{ + int i, r, g, b, a; + DAMAGE_IMAGE *pdmg; + + if (!m_bitsDamage) + return 1; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + a = (int)( fabs(sin(flTime*2)) * 256.0); + + ScaleColors(r, g, b, a); + + // Draw all the items + for (i = 0; i < NUM_DMG_TYPES; i++) + { + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg = &m_dmg[i]; + SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); + SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); + } + } + + + // check for bits that should be expired + for ( i = 0; i < NUM_DMG_TYPES; i++ ) + { + pdmg = &m_dmg[i]; + + if ( m_bitsDamage & giDmgFlags[i] ) + { + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); + + if ( pdmg->fExpire <= flTime // when the time has expired + && a < 40 ) // and the flash is at the low point of the cycle + { + pdmg->fExpire = 0; + + int y = pdmg->y; + pdmg->x = pdmg->y = 0; + + // move everyone above down + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + pdmg = &m_dmg[j]; + if ((pdmg->y) && (pdmg->y < y)) + pdmg->y += giDmgHeight; + + } + + m_bitsDamage &= ~giDmgFlags[i]; // clear the bits + } + } + } + + return 1; +} + + +void CHudHealth::UpdateTiles(float flTime, long bitsDamage) +{ + DAMAGE_IMAGE *pdmg; + + // Which types are new? + long bitsOn = ~m_bitsDamage & bitsDamage; + + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + pdmg = &m_dmg[i]; + + // Is this one already on? + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration + if (!pdmg->fBaseline) + pdmg->fBaseline = flTime; + } + + // Are we just turning it on? + if (bitsOn & giDmgFlags[i]) + { + // put this one at the bottom + pdmg->x = giDmgWidth/8; + pdmg->y = ScreenHeight - giDmgHeight * 2; + pdmg->fExpire=flTime + DMG_IMAGE_LIFE; + + // move everyone else up + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + if (j == i) + continue; + + pdmg = &m_dmg[j]; + if (pdmg->y) + pdmg->y -= giDmgHeight; + + } + pdmg = &m_dmg[i]; + } + } + + // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) + m_bitsDamage |= bitsDamage; +} diff --git a/cl_dll/health.h b/cl_dll/health.h index 41717e78..067db4b4 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -1,127 +1,127 @@ -/*** -* -* 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 DMG_IMAGE_LIFE 2 // seconds that image is up - -#define DMG_IMAGE_POISON 0 -#define DMG_IMAGE_ACID 1 -#define DMG_IMAGE_COLD 2 -#define DMG_IMAGE_DROWN 3 -#define DMG_IMAGE_BURN 4 -#define DMG_IMAGE_NERVE 5 -#define DMG_IMAGE_RAD 6 -#define DMG_IMAGE_SHOCK 7 -//tf defines -#define DMG_IMAGE_CALTROP 8 -#define DMG_IMAGE_TRANQ 9 -#define DMG_IMAGE_CONCUSS 10 -#define DMG_IMAGE_HALLUC 11 -#define NUM_DMG_TYPES 12 -// 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. - - -// time-based damage -//mask off TF-specific stuff too -#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage - - -#define DMG_DROWN (1 << 14) // Drowning -#define DMG_FIRSTTIMEBASED DMG_DROWN - -#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) - -//TF ADDITIONS -#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn -#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance -#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. -#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor -#define DMG_AIMED (1 << 28) // Does Hit location damage -#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls - -#define DMG_CALTROP (1<<30) -#define DMG_HALLUC (1<<31) - -// TF Healing Additions for TakeHealth -#define DMG_IGNORE_MAXHEALTH DMG_IGNITE -// TF Redefines since we never use the originals -#define DMG_NAIL DMG_SLASH -#define DMG_NOT_SELF DMG_FREEZE - - -#define DMG_TRANQ DMG_MORTAR -#define DMG_CONCUSS DMG_SONIC - - - -typedef struct -{ - float fExpire; - float fBaseline; - int x, y; -} DAMAGE_IMAGE; - -// -//----------------------------------------------------- -// -class CHudHealth: public CHudBase -{ -public: - virtual int Init( void ); - virtual int VidInit( void ); - virtual int Draw(float fTime); - virtual void Reset( void ); - int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); - int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); - int m_iHealth; - int m_HUD_dmg_bio; - int m_HUD_cross; - float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; - void GetPainColor( int &r, int &g, int &b ); - float m_fFade; - -private: - HSPRITE m_hSprite; - HSPRITE m_hDamage; - - DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; - int m_bitsDamage; - int DrawPain(float fTime); - int DrawDamage(float fTime); - void CalcDamageDirection(vec3_t vecFrom); - void UpdateTiles(float fTime, long bits); -}; +/*** +* +* 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 DMG_IMAGE_LIFE 2 // seconds that image is up + +#define DMG_IMAGE_POISON 0 +#define DMG_IMAGE_ACID 1 +#define DMG_IMAGE_COLD 2 +#define DMG_IMAGE_DROWN 3 +#define DMG_IMAGE_BURN 4 +#define DMG_IMAGE_NERVE 5 +#define DMG_IMAGE_RAD 6 +#define DMG_IMAGE_SHOCK 7 +//tf defines +#define DMG_IMAGE_CALTROP 8 +#define DMG_IMAGE_TRANQ 9 +#define DMG_IMAGE_CONCUSS 10 +#define DMG_IMAGE_HALLUC 11 +#define NUM_DMG_TYPES 12 +// 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. + + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#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) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// TF Healing Additions for TakeHealth +#define DMG_IGNORE_MAXHEALTH DMG_IGNITE +// TF Redefines since we never use the originals +#define DMG_NAIL DMG_SLASH +#define DMG_NOT_SELF DMG_FREEZE + + +#define DMG_TRANQ DMG_MORTAR +#define DMG_CONCUSS DMG_SONIC + + + +typedef struct +{ + float fExpire; + float fBaseline; + int x, y; +} DAMAGE_IMAGE; + +// +//----------------------------------------------------- +// +class CHudHealth: public CHudBase +{ +public: + virtual int Init( void ); + virtual int VidInit( void ); + virtual int Draw(float fTime); + virtual void Reset( void ); + int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); + int m_iHealth; + int m_HUD_dmg_bio; + int m_HUD_cross; + float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; + void GetPainColor( int &r, int &g, int &b ); + float m_fFade; + +private: + HSPRITE m_hSprite; + HSPRITE m_hDamage; + + DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; + int m_bitsDamage; + int DrawPain(float fTime); + int DrawDamage(float fTime); + void CalcDamageDirection(vec3_t vecFrom); + void UpdateTiles(float fTime, long bits); +}; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 547d5532..17a2d1ab 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -1,347 +1,347 @@ -/*** -* -* 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. -* -****/ - -/* -========================== -This file contains "stubs" of class member implementations so that we can predict certain - weapons client side. From time to time you might find that you need to implement part of the - these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and - add in the functionality you need. -========================== -*/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "skill.h" - -// Globals used by game logic -const Vector g_vecZero = Vector( 0, 0, 0 ); -int gmsgWeapPickup = 0; -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - -ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } - -// CBaseEntity Stubs -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } -CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } -int CBaseEntity::Save( CSave &save ) { return 1; } -int CBaseEntity::Restore( CRestore &restore ) { return 1; } -void CBaseEntity::SetObjectCollisionBox( void ) { } -int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } -void CBaseEntity :: MakeDormant( void ) { } -int CBaseEntity :: IsDormant( void ) { return 0; } -BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } -int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } -int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } -CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } -void CBaseEntity::SUB_Remove( void ) { } - -// CBaseDelay Stubs -void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } -int CBaseDelay::Restore( class CRestore & ) { return 1; } -int CBaseDelay::Save( class CSave & ) { return 1; } - -// CBaseAnimating Stubs -int CBaseAnimating::Restore( class CRestore & ) { return 1; } -int CBaseAnimating::Save( class CSave & ) { return 1; } - -// DEBUG Stubs -edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } -void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } - -// UTIL_* Stubs -void UTIL_PrecacheOther( const char *szClassname ) { } -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } -void UTIL_MakeVectors( const Vector &vecAngles ) { } -BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } -void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } -void UTIL_LogPrintf(char *,...) { } -void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } - -// CBaseToggle Stubs -int CBaseToggle::Restore( class CRestore & ) { return 1; } -int CBaseToggle::Save( class CSave & ) { return 1; } -void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } - -// CGrenade Stubs -void CGrenade::BounceSound( void ) { } -void CGrenade::Explode( Vector, Vector ) { } -void CGrenade::Explode( TraceResult *, int ) { } -void CGrenade::Killed( entvars_t *, int ) { } -void CGrenade::Spawn( void ) { } -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } - -void UTIL_Remove( CBaseEntity *pEntity ){ } -struct skilldata_t gSkillData; -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} - -Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } -CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } -void CBeam::PointEntInit( const Vector &start, int endIndex ) { } -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } -void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } - - -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } -void CBaseMonster :: Eat ( float flFullDuration ) { } -BOOL CBaseMonster :: FShouldEat ( void ) { return TRUE; } -void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } -void CBaseMonster :: BarnacleVictimReleased ( void ) { } -void CBaseMonster :: Listen ( void ) { } -float CBaseMonster :: FLSoundVolume ( CSound *pSound ) { return 0.0; } -BOOL CBaseMonster :: FValidateHintType ( short sHint ) { return FALSE; } -void CBaseMonster :: Look ( int iDistance ) { } -int CBaseMonster :: ISoundMask ( void ) { return 0; } -CSound* CBaseMonster :: PBestSound ( void ) { return NULL; } -CSound* CBaseMonster :: PBestScent ( void ) { return NULL; } -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } -void CBaseMonster :: MonsterThink ( void ) { } -void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } -int CBaseMonster :: IgnoreConditions ( void ) { return 0; } -void CBaseMonster :: RouteClear ( void ) { } -void CBaseMonster :: RouteNew ( void ) { } -BOOL CBaseMonster :: FRouteClear ( void ) { return FALSE; } -BOOL CBaseMonster :: FRefreshRoute ( void ) { return 0; } -BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) { return FALSE; } -BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } -BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) { return FALSE; } -BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } -int ShouldSimplify( int routeType ) { return TRUE; } -void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) { } -BOOL CBaseMonster :: FBecomeProne ( void ) { return TRUE; } -BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; } -void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) { } -BOOL CBaseMonster :: FCanCheckAttacks ( void ) { return FALSE; } -int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) { return 0; } -void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } -BOOL CBaseMonster :: PopEnemy( ) { return FALSE; } -void CBaseMonster :: SetActivity ( Activity NewActivity ) { } -void CBaseMonster :: SetSequenceByName ( char *szSequence ) { } -int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } -float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } -void CBaseMonster :: AdvanceRoute ( float distance ) { } -int CBaseMonster :: RouteClassify( int iMoveFlag ) { return 0; } -BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } -void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) { } -BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } -void CBaseMonster :: Move ( float flInterval ) { } -BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } -void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { } -void CBaseMonster :: MonsterInit ( void ) { } -void CBaseMonster :: MonsterInitThink ( void ) { } -void CBaseMonster :: StartMonster ( void ) { } -void CBaseMonster :: MovementComplete( void ) { } -int CBaseMonster::TaskIsRunning( void ) { return 0; } -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } -BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } -BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } -float CBaseMonster::FlYawDiff ( void ) { return 0.0; } -float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } -float CBaseMonster::VecToYaw ( Vector vecDir ) { return 0.0; } -int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } -void CBaseMonster :: SetEyePosition ( void ) { } -int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } -void CBaseAnimating :: ResetSequenceInfo ( ) { } -BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } -void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { } -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } -void CBaseAnimating :: InitBoneControllers ( void ) { } -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } -int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } -Vector CBaseMonster :: GetGunPosition( void ) { return g_vecZero; } -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } -BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { return TRUE; } -int CBaseMonster :: FindHintNode ( void ) { return NO_NODE; } -void CBaseMonster::ReportAIState( void ) { } -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } -BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } -int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } -BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } -Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } -BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; } -BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; } -void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } -void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } -void CBaseMonster::SentenceStop( void ) { } -void CBaseMonster::CorpseFallThink( void ) { } -void CBaseMonster :: MonsterInitDead( void ) { } -BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; } -BOOL CBaseMonster :: GetEnemy ( void ) { return FALSE; } -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } -void CBaseMonster::FadeMonster( void ) { } -void CBaseMonster :: GibMonster( void ) { } -BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } -BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } -Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } -MONSTERSTATE CBaseMonster :: GetIdealState ( void ) { return MONSTERSTATE_ALERT; } -Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { return NULL; } -Schedule_t *CBaseMonster :: GetSchedule ( void ) { return NULL; } -void CBaseMonster :: RunTask ( Task_t *pTask ) { } -void CBaseMonster :: StartTask ( Task_t *pTask ) { } -Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { return NULL;} -void CBaseMonster::BecomeDead( void ) {} -void CBaseMonster :: RunAI ( void ) {} -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } -int CBaseMonster::Restore( class CRestore & ) { return 1; } -int CBaseMonster::Save( class CSave & ) { return 1; } - -int TrainSpeed(int iSpeed, int iMax) { return 0; } -void CBasePlayer :: DeathSound( void ) { } -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } -void CBasePlayer::PackDeadPlayerItems( void ) { } -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } -void CBasePlayer::WaterMove() { } -BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } -void CBasePlayer::PlayerDeathThink(void) { } -void CBasePlayer::StartDeathCam( void ) { } -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } -void CBasePlayer::PlayerUse ( void ) { } -void CBasePlayer::Jump() { } -void CBasePlayer::Duck( ) { } -int CBasePlayer::Classify ( void ) { return 0; } -void CBasePlayer::PreThink(void) { } -void CBasePlayer::CheckTimeBasedDamage() { } -void CBasePlayer :: UpdateGeigerCounter( void ) { } -void CBasePlayer::CheckSuitUpdate() { } -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } -void CBasePlayer :: UpdatePlayerSound ( void ) { } -void CBasePlayer::PostThink() { } -void CBasePlayer :: Precache( void ) { } -int CBasePlayer::Save( CSave &save ) { return 0; } -void CBasePlayer::RenewItems(void) { } -int CBasePlayer::Restore( CRestore &restore ) { return 0; } -void CBasePlayer::SelectNextItem( int iItem ) { } -BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } -void CBasePlayer::SelectPrevItem( int iItem ) { } -CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } -BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } -void CBasePlayer :: FlashlightTurnOn( void ) { } -void CBasePlayer :: FlashlightTurnOff( void ) { } -void CBasePlayer :: ForceClientDllUpdate( void ) { } -void CBasePlayer::ImpulseCommands( ) { } -void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } -int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } -void CBasePlayer::ItemPreFrame() { } -void CBasePlayer::ItemPostFrame() { } -int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } -int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } -void CBasePlayer::SendAmmoUpdate(void) { } -void CBasePlayer :: UpdateClientData( void ) { } -BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } -void CBasePlayer :: BarnacleVictimReleased ( void ) { } -int CBasePlayer :: Illumination( void ) { return 0; } -void CBasePlayer :: EnableControl(BOOL fControl) { } -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } -void CBasePlayer :: ResetAutoaim( ) { } -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } -int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } -void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } -BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } -Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } -const char *CBasePlayer::TeamID( void ) { return ""; } -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } - -void ClearMultiDamage(void) { } -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } -void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } -void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } -int CBasePlayerItem::Restore( class CRestore & ) { return 1; } -int CBasePlayerItem::Save( class CSave & ) { return 1; } -int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } -int CBasePlayerWeapon::Save( class CSave & ) { return 1; } -void CBasePlayerItem :: SetObjectCollisionBox( void ) { } -void CBasePlayerItem :: FallInit( void ) { } -void CBasePlayerItem::FallThink ( void ) { } -void CBasePlayerItem::Materialize( void ) { } -void CBasePlayerItem::AttemptToMaterialize( void ) { } -void CBasePlayerItem :: CheckRespawn ( void ) { } -CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } -void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } -void CBasePlayerItem::DestroyItem( void ) { } -int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } -void CBasePlayerItem::Drop( void ) { } -void CBasePlayerItem::Kill( void ) { } -void CBasePlayerItem::Holster( int skiplocal ) { } -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } -int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } -BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } -int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } -void CBasePlayerAmmo::Spawn( void ) { } -CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } -void CBasePlayerAmmo::Materialize( void ) { } -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } -void CBasePlayerWeapon::RetireWeapon( void ) { } -void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} +/*** +* +* 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. +* +****/ + +/* +========================== +This file contains "stubs" of class member implementations so that we can predict certain + weapons client side. From time to time you might find that you need to implement part of the + these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and + add in the functionality you need. +========================== +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "skill.h" + +// Globals used by game logic +const Vector g_vecZero = Vector( 0, 0, 0 ); +int gmsgWeapPickup = 0; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } + +// CBaseEntity Stubs +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } +int CBaseEntity::Save( CSave &save ) { return 1; } +int CBaseEntity::Restore( CRestore &restore ) { return 1; } +void CBaseEntity::SetObjectCollisionBox( void ) { } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity :: MakeDormant( void ) { } +int CBaseEntity :: IsDormant( void ) { return 0; } +BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::SUB_Remove( void ) { } + +// CBaseDelay Stubs +void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +int CBaseDelay::Restore( class CRestore & ) { return 1; } +int CBaseDelay::Save( class CSave & ) { return 1; } + +// CBaseAnimating Stubs +int CBaseAnimating::Restore( class CRestore & ) { return 1; } +int CBaseAnimating::Save( class CSave & ) { return 1; } + +// DEBUG Stubs +edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } +void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } + +// UTIL_* Stubs +void UTIL_PrecacheOther( const char *szClassname ) { } +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_MakeVectors( const Vector &vecAngles ) { } +BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } +void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } +void UTIL_LogPrintf(char *,...) { } +void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } + +// CBaseToggle Stubs +int CBaseToggle::Restore( class CRestore & ) { return 1; } +int CBaseToggle::Save( class CSave & ) { return 1; } +void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } + +// CGrenade Stubs +void CGrenade::BounceSound( void ) { } +void CGrenade::Explode( Vector, Vector ) { } +void CGrenade::Explode( TraceResult *, int ) { } +void CGrenade::Killed( entvars_t *, int ) { } +void CGrenade::Spawn( void ) { } +CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } +CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } +void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } + +void UTIL_Remove( CBaseEntity *pEntity ){ } +struct skilldata_t gSkillData; +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } +CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} + +Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } +CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } +void CBeam::PointEntInit( const Vector &start, int endIndex ) { } +CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } +void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } + + +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } +void CBaseMonster :: Eat ( float flFullDuration ) { } +BOOL CBaseMonster :: FShouldEat ( void ) { return TRUE; } +void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBaseMonster :: BarnacleVictimReleased ( void ) { } +void CBaseMonster :: Listen ( void ) { } +float CBaseMonster :: FLSoundVolume ( CSound *pSound ) { return 0.0; } +BOOL CBaseMonster :: FValidateHintType ( short sHint ) { return FALSE; } +void CBaseMonster :: Look ( int iDistance ) { } +int CBaseMonster :: ISoundMask ( void ) { return 0; } +CSound* CBaseMonster :: PBestSound ( void ) { return NULL; } +CSound* CBaseMonster :: PBestScent ( void ) { return NULL; } +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } +void CBaseMonster :: MonsterThink ( void ) { } +void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } +int CBaseMonster :: IgnoreConditions ( void ) { return 0; } +void CBaseMonster :: RouteClear ( void ) { } +void CBaseMonster :: RouteNew ( void ) { } +BOOL CBaseMonster :: FRouteClear ( void ) { return FALSE; } +BOOL CBaseMonster :: FRefreshRoute ( void ) { return 0; } +BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +int ShouldSimplify( int routeType ) { return TRUE; } +void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) { } +BOOL CBaseMonster :: FBecomeProne ( void ) { return TRUE; } +BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; } +void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) { } +BOOL CBaseMonster :: FCanCheckAttacks ( void ) { return FALSE; } +int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) { return 0; } +void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } +BOOL CBaseMonster :: PopEnemy( ) { return FALSE; } +void CBaseMonster :: SetActivity ( Activity NewActivity ) { } +void CBaseMonster :: SetSequenceByName ( char *szSequence ) { } +int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } +float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } +void CBaseMonster :: AdvanceRoute ( float distance ) { } +int CBaseMonster :: RouteClassify( int iMoveFlag ) { return 0; } +BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } +void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) { } +BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } +void CBaseMonster :: Move ( float flInterval ) { } +BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } +void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { } +void CBaseMonster :: MonsterInit ( void ) { } +void CBaseMonster :: MonsterInitThink ( void ) { } +void CBaseMonster :: StartMonster ( void ) { } +void CBaseMonster :: MovementComplete( void ) { } +int CBaseMonster::TaskIsRunning( void ) { return 0; } +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } +BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::FlYawDiff ( void ) { return 0.0; } +float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } +float CBaseMonster::VecToYaw ( Vector vecDir ) { return 0.0; } +int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } +void CBaseMonster :: SetEyePosition ( void ) { } +int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } +void CBaseAnimating :: ResetSequenceInfo ( ) { } +BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } +void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { } +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating :: InitBoneControllers ( void ) { } +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } +Vector CBaseMonster :: GetGunPosition( void ) { return g_vecZero; } +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { return TRUE; } +int CBaseMonster :: FindHintNode ( void ) { return NO_NODE; } +void CBaseMonster::ReportAIState( void ) { } +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } +int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } +BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } +Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } +BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; } +BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; } +void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } +void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } +void CBaseMonster::SentenceStop( void ) { } +void CBaseMonster::CorpseFallThink( void ) { } +void CBaseMonster :: MonsterInitDead( void ) { } +BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; } +BOOL CBaseMonster :: GetEnemy ( void ) { return FALSE; } +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::FadeMonster( void ) { } +void CBaseMonster :: GibMonster( void ) { } +BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } +MONSTERSTATE CBaseMonster :: GetIdealState ( void ) { return MONSTERSTATE_ALERT; } +Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { return NULL; } +Schedule_t *CBaseMonster :: GetSchedule ( void ) { return NULL; } +void CBaseMonster :: RunTask ( Task_t *pTask ) { } +void CBaseMonster :: StartTask ( Task_t *pTask ) { } +Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { return NULL;} +void CBaseMonster::BecomeDead( void ) {} +void CBaseMonster :: RunAI ( void ) {} +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +int CBaseMonster::Restore( class CRestore & ) { return 1; } +int CBaseMonster::Save( class CSave & ) { return 1; } + +int TrainSpeed(int iSpeed, int iMax) { return 0; } +void CBasePlayer :: DeathSound( void ) { } +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBasePlayer::PackDeadPlayerItems( void ) { } +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } +void CBasePlayer::WaterMove() { } +BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } +void CBasePlayer::PlayerDeathThink(void) { } +void CBasePlayer::StartDeathCam( void ) { } +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } +void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::Jump() { } +void CBasePlayer::Duck( ) { } +int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer::PreThink(void) { } +void CBasePlayer::CheckTimeBasedDamage() { } +void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::CheckSuitUpdate() { } +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } +void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::PostThink() { } +void CBasePlayer :: Precache( void ) { } +int CBasePlayer::Save( CSave &save ) { return 0; } +void CBasePlayer::RenewItems(void) { } +int CBasePlayer::Restore( CRestore &restore ) { return 0; } +void CBasePlayer::SelectNextItem( int iItem ) { } +BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } +void CBasePlayer::SelectPrevItem( int iItem ) { } +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } +BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } +void CBasePlayer :: FlashlightTurnOn( void ) { } +void CBasePlayer :: FlashlightTurnOff( void ) { } +void CBasePlayer :: ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands( ) { } +void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +void CBasePlayer::ItemPreFrame() { } +void CBasePlayer::ItemPostFrame() { } +int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } +int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +void CBasePlayer::SendAmmoUpdate(void) { } +void CBasePlayer :: UpdateClientData( void ) { } +BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBasePlayer :: BarnacleVictimReleased ( void ) { } +int CBasePlayer :: Illumination( void ) { return 0; } +void CBasePlayer :: EnableControl(BOOL fControl) { } +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer :: ResetAutoaim( ) { } +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +const char *CBasePlayer::TeamID( void ) { return ""; } +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } + +void ClearMultiDamage(void) { } +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } +void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } +int CBasePlayerItem::Restore( class CRestore & ) { return 1; } +int CBasePlayerItem::Save( class CSave & ) { return 1; } +int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } +int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +void CBasePlayerItem :: SetObjectCollisionBox( void ) { } +void CBasePlayerItem :: FallInit( void ) { } +void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::Materialize( void ) { } +void CBasePlayerItem::AttemptToMaterialize( void ) { } +void CBasePlayerItem :: CheckRespawn ( void ) { } +CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerItem::DestroyItem( void ) { } +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } +void CBasePlayerItem::Drop( void ) { } +void CBasePlayerItem::Kill( void ) { } +void CBasePlayerItem::Holster( int skiplocal ) { } +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +void CBasePlayerAmmo::Spawn( void ) { } +CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } +void CBasePlayerAmmo::Materialize( void ) { } +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +void CBasePlayerWeapon::RetireWeapon( void ) { } +void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} \ No newline at end of file diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index 5ad4459e..7e9c730b 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -1,80 +1,80 @@ -/*** -* -* 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 "../hud.h" -#include "../cl_util.h" -#include "event_api.h" - -extern "C" -{ -// HLDM -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); - - - -void EV_TrainPitchAdjust( struct event_args_s *args ); -} - -/* -====================== -Game_HookEvents - -Associate script file name with callback functions. Callback's must be extern "C" so - the engine doesn't get confused about name mangling stuff. Note that the format is - always the same. Of course, a clever mod team could actually embed parameters, behavior - into the actual .sc files and create a .sc file parser and hook their functionality through - that.. i.e., a scripting system. - -That was what we were going to do, but we ran out of time...oh well. -====================== -*/ -void Game_HookEvents( void ) -{ - gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); - gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); - gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); - gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); - gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); - gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); - gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); - gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); - gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); - gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); - gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); - gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); - gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); - gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); - gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); - gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); - gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); - gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); - gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); -} +/*** +* +* 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 "../hud.h" +#include "../cl_util.h" +#include "event_api.h" + +extern "C" +{ +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +/* +====================== +Game_HookEvents + +Associate script file name with callback functions. Callback's must be extern "C" so + the engine doesn't get confused about name mangling stuff. Note that the format is + always the same. Of course, a clever mod team could actually embed parameters, behavior + into the actual .sc files and create a .sc file parser and hook their functionality through + that.. i.e., a scripting system. + +That was what we were going to do, but we ran out of time...oh well. +====================== +*/ +void Game_HookEvents( void ) +{ + gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); + gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); + gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); + gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); + gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); + gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); + gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); + gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); + gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); + gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); + gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); + gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); + gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); + gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); + gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); + gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); + gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); + gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); +} diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp index e95dfae7..e61db884 100644 --- a/cl_dll/hl/hl_objects.cpp +++ b/cl_dll/hl/hl_objects.cpp @@ -1,90 +1,90 @@ -/*** -* -* 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 "../hud.h" -#include "../cl_util.h" -#include "../demo.h" - -#include "demo_api.h" -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" - -#include "pm_defs.h" -#include "event_api.h" -#include "entity_types.h" -#include "r_efx.h" - -extern BEAM *pBeam; -extern BEAM *pBeam2; -void HUD_GetLastOrg( float *org ); - -void UpdateBeams ( void ) -{ - vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; - vec3_t view_ofs; - pmtrace_t tr; - cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); - int idx = pthisplayer->index; - - // Get our exact viewangles from engine - gEngfuncs.GetViewAngles( (float *)angles ); - - // Determine our last predicted origin - HUD_GetLastOrg( (float *)&origin ); - - AngleVectors( angles, forward, right, up ); - - VectorCopy( origin, vecSrc ); - - VectorMA( vecSrc, 2048, forward, vecEnd ); - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - if ( pBeam ) - { - pBeam->target = tr.endpos; - pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. - } - - if ( pBeam2 ) - { - pBeam2->target = tr.endpos; - pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. - } -} - -/* -===================== -Game_AddObjects - -Add game specific, client-side objects here -===================== -*/ -void Game_AddObjects( void ) -{ - if ( pBeam && pBeam2 ) - UpdateBeams(); -} +/*** +* +* 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 "../hud.h" +#include "../cl_util.h" +#include "../demo.h" + +#include "demo_api.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "pm_defs.h" +#include "event_api.h" +#include "entity_types.h" +#include "r_efx.h" + +extern BEAM *pBeam; +extern BEAM *pBeam2; +void HUD_GetLastOrg( float *org ); + +void UpdateBeams ( void ) +{ + vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; + vec3_t view_ofs; + pmtrace_t tr; + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + int idx = pthisplayer->index; + + // Get our exact viewangles from engine + gEngfuncs.GetViewAngles( (float *)angles ); + + // Determine our last predicted origin + HUD_GetLastOrg( (float *)&origin ); + + AngleVectors( angles, forward, right, up ); + + VectorCopy( origin, vecSrc ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( pBeam ) + { + pBeam->target = tr.endpos; + pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } + + if ( pBeam2 ) + { + pBeam2->target = tr.endpos; + pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } +} + +/* +===================== +Game_AddObjects + +Add game specific, client-side objects here +===================== +*/ +void Game_AddObjects( void ) +{ + if ( pBeam && pBeam2 ) + UpdateBeams(); +} diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 581b2e89..193c9d49 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -1,1101 +1,1101 @@ -/*** -* -* 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 "usercmd.h" -#include "entity_state.h" -#include "demo_api.h" -#include "pm_defs.h" -#include "event_api.h" -#include "r_efx.h" - -#include "../hud_iface.h" -#include "../com_weapons.h" -#include "../demo.h" - -extern globalvars_t *gpGlobals; -extern int g_iUser1; - -// Pool of client side entities/entvars_t -static entvars_t ev[ 32 ]; -static int num_ents = 0; - -// The entity we'll use to represent the local client -static CBasePlayer player; - -// Local version of game .dll global variables ( time, etc. ) -static globalvars_t Globals; - -static CBasePlayerWeapon *g_pWpns[ 32 ]; - -float g_flApplyVel = 0.0; -int g_irunninggausspred = 0; - -vec3_t previousorigin; - -// HLDM Weapon placeholder entities. -CGlock g_Glock; -CCrowbar g_Crowbar; -CPython g_Python; -CMP5 g_Mp5; -CCrossbow g_Crossbow; -CShotgun g_Shotgun; -CRpg g_Rpg; -CGauss g_Gauss; -CEgon g_Egon; -CHgun g_HGun; -CHandGrenade g_HandGren; -CSatchel g_Satchel; -CTripmine g_Tripmine; -CSqueak g_Snark; - - -/* -====================== -AlertMessage - -Print debug messages to console -====================== -*/ -void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, szFmt); - vsprintf (string, szFmt,argptr); - va_end (argptr); - - gEngfuncs.Con_Printf( "cl: " ); - gEngfuncs.Con_Printf( string ); -} - -//Returns if it's multiplayer. -//Mostly used by the client side weapons. -bool bIsMultiplayer ( void ) -{ - return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; -} -//Just loads a v_ model. -void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) -{ - gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); -} - -/* -===================== -HUD_PrepEntity - -Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then -we set up the m_pPlayer field. -===================== -*/ -void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) -{ - memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); - pEntity->pev = &ev[ num_ents++ ]; - - pEntity->Precache(); - pEntity->Spawn(); - - if ( pWeaponOwner ) - { - ItemInfo info; - - ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; - - ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); - - g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; - } -} - -/* -===================== -CBaseEntity :: Killed - -If weapons code "kills" an entity, just set its effects to EF_NODRAW -===================== -*/ -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->effects |= EF_NODRAW; -} - -/* -===================== -CBasePlayerWeapon :: DefaultReload -===================== -*/ -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(), body ); - - m_fInReload = TRUE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - return TRUE; -} - -/* -===================== -CBasePlayerWeapon :: CanDeploy -===================== -*/ -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; -} - -/* -===================== -CBasePlayerWeapon :: DefaultDeploy - -===================== -*/ -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) -{ - if ( !CanDeploy() ) - return FALSE; - - gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); - - SendWeaponAnim( iAnim, skiplocal, body ); - - g_irunninggausspred = false; - m_pPlayer->m_flNextAttack = 0.5; - m_flTimeWeaponIdle = 1.0; - return TRUE; -} - -/* -===================== -CBasePlayerWeapon :: PlayEmptySound - -===================== -*/ -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if (m_iPlayEmptySound) - { - HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); - m_iPlayEmptySound = 0; - return 0; - } - return 0; -} - -/* -===================== -CBasePlayerWeapon :: ResetEmptySound - -===================== -*/ -void CBasePlayerWeapon :: ResetEmptySound( void ) -{ - m_iPlayEmptySound = 1; -} - -/* -===================== -CBasePlayerWeapon::Holster - -Put away weapon -===================== -*/ -void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE; // cancel any reload in progress. - g_irunninggausspred = false; - m_pPlayer->pev->viewmodel = 0; -} - -/* -===================== -CBasePlayerWeapon::SendWeaponAnim - -Animate weapon model -===================== -*/ -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) -{ - m_pPlayer->pev->weaponanim = iAnim; - - HUD_SendWeaponAnim( iAnim, body, 0 ); -} - -/* -===================== -CBaseEntity::FireBulletsPlayer - -Only produces random numbers to match the server ones. -===================== -*/ -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 ) -{ - float x, y, z; - - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) - { - if ( pevAttacker == NULL ) - { - // get circular gaussian spread - 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); - } - else - { - //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; - } - - } - - return Vector ( x * vecSpread.x, y * vecSpread.y, 0.0 ); -} - -/* -===================== -CBasePlayerWeapon::ItemPostFrame - -Handles weapon firing, reloading, etc. -===================== -*/ -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) - { -#if 0 // FIXME, need ammo on client to make this work right - // 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; -#else - m_iClip += 10; -#endif - m_fInReload = FALSE; - } - - if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) - { - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) - { - m_fFireOnEmpty = TRUE; - } - - SecondaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK2; - } - else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) - { - if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) - { - m_fFireOnEmpty = TRUE; - } - - 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; - - // 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 < 0.0 ) - { - Reload(); - return; - } - - WeaponIdle( ); - return; - } - - // catch all - if ( ShouldWeaponIdle() ) - { - WeaponIdle(); - } -} - -/* -===================== -CBasePlayer::SelectItem - - Switch weapons -===================== -*/ -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) - return; - - CBasePlayerItem *pItem = NULL; - - if (!pItem) - return; - - - if (pItem == m_pActiveItem) - return; - - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - m_pLastItem = m_pActiveItem; - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - } -} - -/* -===================== -CBasePlayer::SelectLastItem - -===================== -*/ -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - return; - } - - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) - { - return; - } - - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - CBasePlayerItem *pTemp = m_pActiveItem; - m_pActiveItem = m_pLastItem; - m_pLastItem = pTemp; - m_pActiveItem->Deploy( ); -} - -/* -===================== -CBasePlayer::Killed - -===================== -*/ -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - - g_irunninggausspred = false; -} - -/* -===================== -CBasePlayer::Spawn - -===================== -*/ -void CBasePlayer::Spawn( void ) -{ - if (m_pActiveItem) - m_pActiveItem->Deploy( ); - - g_irunninggausspred = false; -} - -/* -===================== -UTIL_TraceLine - -Don't actually trace, but act like the trace didn't hit anything. -===================== -*/ -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - memset( ptr, 0, sizeof( *ptr ) ); - ptr->flFraction = 1.0; -} - -/* -===================== -UTIL_ParticleBox - -For debugging, draw a box around a player made out of particles -===================== -*/ -void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) -{ - int i; - vec3_t mmin, mmax; - - for ( i = 0; i < 3; i++ ) - { - mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; - mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; - } - - gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); -} - -/* -===================== -UTIL_ParticleBoxes - -For debugging, draw boxes for other collidable players -===================== -*/ -void UTIL_ParticleBoxes( void ) -{ - int idx; - physent_t *pe; - cl_entity_t *player; - vec3_t mins, maxs; - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - - // Store off the old count - gEngfuncs.pEventAPI->EV_PushPMStates(); - - player = gEngfuncs.GetLocalPlayer(); - // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); - - for ( idx = 1; idx < 100; idx++ ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); - if ( !pe ) - break; - - if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) - { - mins = pe->origin + pe->mins; - maxs = pe->origin + pe->maxs; - - gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); - } - } - - gEngfuncs.pEventAPI->EV_PopPMStates(); -} - -/* -===================== -UTIL_ParticleLine - -For debugging, draw a line made out of particles -===================== -*/ -void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) -{ - gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); -} - -/* -===================== -CBasePlayerWeapon::PrintState - -For debugging, print out state variables to log file -===================== -*/ -void CBasePlayerWeapon::PrintState( void ) -{ - COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); - COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); - COM_Log( "c:\\hl.log", "%i ", m_iClip ); -} - -int RandomLong( int a, int b ) -{ - return gEngfuncs.pfnRandomLong(a, b); -} - - -/* -===================== -HUD_InitClientWeapons - -Set up weapons, player and functions needed to run weapons code client-side. -===================== -*/ -void HUD_InitClientWeapons( void ) -{ - static int initialized = 0; - if ( initialized ) - return; - - initialized = 1; - - // Set up pointer ( dummy object ) - gpGlobals = &Globals; - - // Fill in current time ( probably not needed ) - gpGlobals->time = gEngfuncs.GetClientTime(); - - // Fake functions - g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; - g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; - g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; - g_engfuncs.pfnNameForFunction = stub_NameForFunction; - g_engfuncs.pfnSetModel = stub_SetModel; - g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; - - // Handled locally - g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; - g_engfuncs.pfnAlertMessage = AlertMessage; - - // Pass through to engine - g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; - g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; - g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; - - // Allocate a slot for the local player - HUD_PrepEntity( &player , NULL ); - - // Allocate slot(s) for each weapon that we are going to be predicting - HUD_PrepEntity( &g_Glock , &player ); - HUD_PrepEntity( &g_Crowbar , &player ); - HUD_PrepEntity( &g_Python , &player ); - HUD_PrepEntity( &g_Mp5 , &player ); - HUD_PrepEntity( &g_Crossbow , &player ); - HUD_PrepEntity( &g_Shotgun , &player ); - HUD_PrepEntity( &g_Rpg , &player ); - HUD_PrepEntity( &g_Gauss , &player ); - HUD_PrepEntity( &g_Egon , &player ); - HUD_PrepEntity( &g_HGun , &player ); - HUD_PrepEntity( &g_HandGren , &player ); - HUD_PrepEntity( &g_Satchel , &player ); - HUD_PrepEntity( &g_Tripmine , &player ); - HUD_PrepEntity( &g_Snark , &player ); -} - -/* -===================== -HUD_GetLastOrg - -Retruns the last position that we stored for egon beam endpoint. -===================== -*/ -void HUD_GetLastOrg( float *org ) -{ - int i; - - // Return last origin - for ( i = 0; i < 3; i++ ) - { - org[i] = previousorigin[i]; - } -} - -/* -===================== -HUD_SetLastOrg - -Remember our exact predicted origin so we can draw the egon to the right position. -===================== -*/ -void HUD_SetLastOrg( void ) -{ - int i; - - // Offset final origin by view_offset - for ( i = 0; i < 3; i++ ) - { - previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; - } -} - -/* -===================== -HUD_WeaponsPostThink - -Run Weapon firing code on client -===================== -*/ -void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) -{ - int i; - int buttonsChanged; - CBasePlayerWeapon *pWeapon = NULL; - CBasePlayerWeapon *pCurrent; - weapon_data_t nulldata, *pfrom, *pto; - static int lasthealth; - - memset( &nulldata, 0, sizeof( nulldata ) ); - - HUD_InitClientWeapons(); - - // Get current clock - gpGlobals->time = time; - - // Fill in data based on selected weapon - // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? - switch ( from->client.m_iId ) - { - case WEAPON_CROWBAR: - pWeapon = &g_Crowbar; - break; - - case WEAPON_GLOCK: - pWeapon = &g_Glock; - break; - - case WEAPON_PYTHON: - pWeapon = &g_Python; - break; - - case WEAPON_MP5: - pWeapon = &g_Mp5; - break; - - case WEAPON_CROSSBOW: - pWeapon = &g_Crossbow; - break; - - case WEAPON_SHOTGUN: - pWeapon = &g_Shotgun; - break; - - case WEAPON_RPG: - pWeapon = &g_Rpg; - break; - - case WEAPON_GAUSS: - pWeapon = &g_Gauss; - break; - - case WEAPON_EGON: - pWeapon = &g_Egon; - break; - - case WEAPON_HORNETGUN: - pWeapon = &g_HGun; - break; - - case WEAPON_HANDGRENADE: - pWeapon = &g_HandGren; - break; - - case WEAPON_SATCHEL: - pWeapon = &g_Satchel; - break; - - case WEAPON_TRIPMINE: - pWeapon = &g_Tripmine; - break; - - case WEAPON_SNARK: - pWeapon = &g_Snark; - break; - } - - // Store pointer to our destination entity_state_t so we can get our origin, etc. from it - // for setting up events on the client - g_finalstate = to; - - // If we are running events/etc. go ahead and see if we - // managed to die between last frame and this one - // If so, run the appropriate player killed or spawn function - if ( g_runfuncs ) - { - if ( to->client.health <= 0 && lasthealth > 0 ) - { - player.Killed( NULL, 0 ); - - } - else if ( to->client.health > 0 && lasthealth <= 0 ) - { - player.Spawn(); - } - - lasthealth = to->client.health; - } - - // We are not predicting the current weapon, just bow out here. - if ( !pWeapon ) - return; - - for ( i = 0; i < 32; i++ ) - { - pCurrent = g_pWpns[ i ]; - if ( !pCurrent ) - { - continue; - } - - pfrom = &from->weapondata[ i ]; - - pCurrent->m_fInReload = pfrom->m_fInReload; - pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; -// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; - pCurrent->m_iClip = pfrom->m_iClip; - pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; - pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; - pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; - pCurrent->pev->fuser1 = pfrom->fuser1; - pCurrent->m_flStartThrow = pfrom->fuser2; - pCurrent->m_flReleaseThrow = pfrom->fuser3; - pCurrent->m_chargeReady = pfrom->iuser1; - pCurrent->m_fInAttack = pfrom->iuser2; - pCurrent->m_fireState = pfrom->iuser3; - - pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; - pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; - player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; - player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; - } - - // For random weapon events, use this seed to seed random # generator - player.random_seed = random_seed; - - // Get old buttons from previous state. - player.m_afButtonLast = from->playerstate.oldbuttons; - - // Which buttsons chave changed - buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // The changed ones still down are "pressed" - player.m_afButtonPressed = buttonsChanged & cmd->buttons; - // The ones not down are "released" - player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); - - // Set player variables that weapons code might check/alter - player.pev->button = cmd->buttons; - - player.pev->velocity = from->client.velocity; - player.pev->flags = from->client.flags; - - player.pev->deadflag = from->client.deadflag; - player.pev->waterlevel = from->client.waterlevel; - player.pev->maxspeed = from->client.maxspeed; - player.pev->fov = from->client.fov; - player.pev->weaponanim = from->client.weaponanim; - player.pev->viewmodel = from->client.viewmodel; - player.m_flNextAttack = from->client.m_flNextAttack; - player.m_flNextAmmoBurn = from->client.fuser2; - player.m_flAmmoStartCharge = from->client.fuser3; - - //Stores all our ammo info, so the client side weapons can use them. - player.ammo_9mm = (int)from->client.vuser1[0]; - player.ammo_357 = (int)from->client.vuser1[1]; - player.ammo_argrens = (int)from->client.vuser1[2]; - player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... - player.ammo_buckshot = (int)from->client.ammo_shells; - player.ammo_uranium = (int)from->client.ammo_cells; - player.ammo_hornets = (int)from->client.vuser2[0]; - player.ammo_rockets = (int)from->client.ammo_rockets; - - - // Point to current weapon object - if ( from->client.m_iId ) - { - player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; - } - - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) - { - ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; - ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; - } - - // Don't go firing anything if we have died. - // Or if we don't have a weapon model deployed - if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && - !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) - { - if ( player.m_flNextAttack <= 0 ) - { - pWeapon->ItemPostFrame(); - } - } - - // Assume that we are not going to switch weapons - to->client.m_iId = from->client.m_iId; - - // Now see if we issued a changeweapon command ( and we're not dead ) - if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) - { - // Switched to a different weapon? - if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) - { - CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; - if ( pNew && ( pNew != pWeapon ) ) - { - // Put away old weapon - if (player.m_pActiveItem) - player.m_pActiveItem->Holster( ); - - player.m_pLastItem = player.m_pActiveItem; - player.m_pActiveItem = pNew; - - // Deploy new weapon - if (player.m_pActiveItem) - { - player.m_pActiveItem->Deploy( ); - } - - // Update weapon id so we can predict things correctly. - to->client.m_iId = cmd->weaponselect; - } - } - } - - // Copy in results of prediction code - to->client.viewmodel = player.pev->viewmodel; - to->client.fov = player.pev->fov; - to->client.weaponanim = player.pev->weaponanim; - to->client.m_flNextAttack = player.m_flNextAttack; - to->client.fuser2 = player.m_flNextAmmoBurn; - to->client.fuser3 = player.m_flAmmoStartCharge; - to->client.maxspeed = player.pev->maxspeed; - - //HL Weapons - to->client.vuser1[0] = player.ammo_9mm; - to->client.vuser1[1] = player.ammo_357; - to->client.vuser1[2] = player.ammo_argrens; - - to->client.ammo_nails = player.ammo_bolts; - to->client.ammo_shells = player.ammo_buckshot; - to->client.ammo_cells = player.ammo_uranium; - to->client.vuser2[0] = player.ammo_hornets; - to->client.ammo_rockets = player.ammo_rockets; - - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) - { - from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; - from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; - } - - // Make sure that weapon animation matches what the game .dll is telling us - // over the wire ( fixes some animation glitches ) - if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) - { - int body = 2; - - //Pop the model to body 0. - if ( pWeapon == &g_Tripmine ) - body = 0; - - //Show laser sight/scope combo - if ( pWeapon == &g_Python && bIsMultiplayer() ) - body = 1; - - // Force a fixed anim down to viewmodel - HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); - } - - for ( i = 0; i < 32; i++ ) - { - pCurrent = g_pWpns[ i ]; - - pto = &to->weapondata[ i ]; - - if ( !pCurrent ) - { - memset( pto, 0, sizeof( weapon_data_t ) ); - continue; - } - - pto->m_fInReload = pCurrent->m_fInReload; - pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; -// pto->m_flPumpTime = pCurrent->m_flPumpTime; - pto->m_iClip = pCurrent->m_iClip; - pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; - pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; - pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; - pto->fuser1 = pCurrent->pev->fuser1; - pto->fuser2 = pCurrent->m_flStartThrow; - pto->fuser3 = pCurrent->m_flReleaseThrow; - pto->iuser1 = pCurrent->m_chargeReady; - pto->iuser2 = pCurrent->m_fInAttack; - pto->iuser3 = pCurrent->m_fireState; - - // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) - pto->m_flNextReload -= cmd->msec / 1000.0; - pto->m_fNextAimBonus -= cmd->msec / 1000.0; - pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; - pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; - pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; - pto->fuser1 -= cmd->msec / 1000.0; - - to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; - to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; - to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; - to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; - -/* if ( pto->m_flPumpTime != -9999 ) - { - pto->m_flPumpTime -= cmd->msec / 1000.0; - if ( pto->m_flPumpTime < -0.001 ) - pto->m_flPumpTime = -0.001; - }*/ - - if ( pto->m_fNextAimBonus < -1.0 ) - { - pto->m_fNextAimBonus = -1.0; - } - - if ( pto->m_flNextPrimaryAttack < -1.0 ) - { - pto->m_flNextPrimaryAttack = -1.0; - } - - if ( pto->m_flNextSecondaryAttack < -0.001 ) - { - pto->m_flNextSecondaryAttack = -0.001; - } - - if ( pto->m_flTimeWeaponIdle < -0.001 ) - { - pto->m_flTimeWeaponIdle = -0.001; - } - - if ( pto->m_flNextReload < -0.001 ) - { - pto->m_flNextReload = -0.001; - } - - if ( pto->fuser1 < -0.001 ) - { - pto->fuser1 = -0.001; - } - } - - // m_flNextAttack is now part of the weapons, but is part of the player instead - to->client.m_flNextAttack -= cmd->msec / 1000.0; - if ( to->client.m_flNextAttack < -0.001 ) - { - to->client.m_flNextAttack = -0.001; - } - - to->client.fuser2 -= cmd->msec / 1000.0; - if ( to->client.fuser2 < -0.001 ) - { - to->client.fuser2 = -0.001; - } - - to->client.fuser3 -= cmd->msec / 1000.0; - if ( to->client.fuser3 < -0.001 ) - { - to->client.fuser3 = -0.001; - } - - // Store off the last position from the predicted state. - HUD_SetLastOrg(); - - // Wipe it so we can't use it after this frame - g_finalstate = NULL; -} - -/* -===================== -HUD_PostRunCmd - -Client calls this during prediction, after it has moved the player and updated any info changed into to-> -time is the current client clock based on prediction -cmd is the command that caused the movement, etc -runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should -be ignored -===================== -*/ -void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) -{ - g_runfuncs = runfuncs; - -#if defined( CLIENT_WEAPONS ) - if ( cl_lw && cl_lw->value ) - { - HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); - } - else -#endif - { - to->client.fov = g_lastFOV; - } - - if ( g_irunninggausspred == 1 ) - { - Vector forward; - gEngfuncs.pfnAngleVectors( v_angles, forward, NULL, NULL ); - to->client.velocity = to->client.velocity - forward * g_flApplyVel * 5; - g_irunninggausspred = false; - } - - // All games can use FOV state - g_lastFOV = to->client.fov; -} +/*** +* +* 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 "usercmd.h" +#include "entity_state.h" +#include "demo_api.h" +#include "pm_defs.h" +#include "event_api.h" +#include "r_efx.h" + +#include "../hud_iface.h" +#include "../com_weapons.h" +#include "../demo.h" + +extern globalvars_t *gpGlobals; +extern int g_iUser1; + +// Pool of client side entities/entvars_t +static entvars_t ev[ 32 ]; +static int num_ents = 0; + +// The entity we'll use to represent the local client +static CBasePlayer player; + +// Local version of game .dll global variables ( time, etc. ) +static globalvars_t Globals; + +static CBasePlayerWeapon *g_pWpns[ 32 ]; + +float g_flApplyVel = 0.0; +int g_irunninggausspred = 0; + +vec3_t previousorigin; + +// HLDM Weapon placeholder entities. +CGlock g_Glock; +CCrowbar g_Crowbar; +CPython g_Python; +CMP5 g_Mp5; +CCrossbow g_Crossbow; +CShotgun g_Shotgun; +CRpg g_Rpg; +CGauss g_Gauss; +CEgon g_Egon; +CHgun g_HGun; +CHandGrenade g_HandGren; +CSatchel g_Satchel; +CTripmine g_Tripmine; +CSqueak g_Snark; + + +/* +====================== +AlertMessage + +Print debug messages to console +====================== +*/ +void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, szFmt); + vsprintf (string, szFmt,argptr); + va_end (argptr); + + gEngfuncs.Con_Printf( "cl: " ); + gEngfuncs.Con_Printf( string ); +} + +//Returns if it's multiplayer. +//Mostly used by the client side weapons. +bool bIsMultiplayer ( void ) +{ + return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; +} +//Just loads a v_ model. +void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) +{ + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); +} + +/* +===================== +HUD_PrepEntity + +Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then +we set up the m_pPlayer field. +===================== +*/ +void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) +{ + memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); + pEntity->pev = &ev[ num_ents++ ]; + + pEntity->Precache(); + pEntity->Spawn(); + + if ( pWeaponOwner ) + { + ItemInfo info; + + ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; + + ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); + + g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; + } +} + +/* +===================== +CBaseEntity :: Killed + +If weapons code "kills" an entity, just set its effects to EF_NODRAW +===================== +*/ +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->effects |= EF_NODRAW; +} + +/* +===================== +CBasePlayerWeapon :: DefaultReload +===================== +*/ +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(), body ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: CanDeploy +===================== +*/ +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; +} + +/* +===================== +CBasePlayerWeapon :: DefaultDeploy + +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +{ + if ( !CanDeploy() ) + return FALSE; + + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); + + SendWeaponAnim( iAnim, skiplocal, body ); + + g_irunninggausspred = false; + m_pPlayer->m_flNextAttack = 0.5; + m_flTimeWeaponIdle = 1.0; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: PlayEmptySound + +===================== +*/ +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { + HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +/* +===================== +CBasePlayerWeapon :: ResetEmptySound + +===================== +*/ +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +/* +===================== +CBasePlayerWeapon::Holster + +Put away weapon +===================== +*/ +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + g_irunninggausspred = false; + m_pPlayer->pev->viewmodel = 0; +} + +/* +===================== +CBasePlayerWeapon::SendWeaponAnim + +Animate weapon model +===================== +*/ +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) +{ + m_pPlayer->pev->weaponanim = iAnim; + + HUD_SendWeaponAnim( iAnim, body, 0 ); +} + +/* +===================== +CBaseEntity::FireBulletsPlayer + +Only produces random numbers to match the server ones. +===================== +*/ +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 ) +{ + float x, y, z; + + for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + { + if ( pevAttacker == NULL ) + { + // get circular gaussian spread + 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); + } + else + { + //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; + } + + } + + return Vector ( x * vecSpread.x, y * vecSpread.y, 0.0 ); +} + +/* +===================== +CBasePlayerWeapon::ItemPostFrame + +Handles weapon firing, reloading, etc. +===================== +*/ +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + { +#if 0 // FIXME, need ammo on client to make this work right + // 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; +#else + m_iClip += 10; +#endif + m_fInReload = FALSE; + } + + if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) + { + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + { + m_fFireOnEmpty = TRUE; + } + + SecondaryAttack(); + m_pPlayer->pev->button &= ~IN_ATTACK2; + } + else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) + { + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + 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; + + // 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 < 0.0 ) + { + Reload(); + return; + } + + WeaponIdle( ); + return; + } + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +/* +===================== +CBasePlayer::SelectItem + + Switch weapons +===================== +*/ +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + if (!pItem) + return; + + + if (pItem == m_pActiveItem) + return; + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + } +} + +/* +===================== +CBasePlayer::SelectLastItem + +===================== +*/ +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + return; + } + + if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + { + return; + } + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + CBasePlayerItem *pTemp = m_pActiveItem; + m_pActiveItem = m_pLastItem; + m_pLastItem = pTemp; + m_pActiveItem->Deploy( ); +} + +/* +===================== +CBasePlayer::Killed + +===================== +*/ +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); + + g_irunninggausspred = false; +} + +/* +===================== +CBasePlayer::Spawn + +===================== +*/ +void CBasePlayer::Spawn( void ) +{ + if (m_pActiveItem) + m_pActiveItem->Deploy( ); + + g_irunninggausspred = false; +} + +/* +===================== +UTIL_TraceLine + +Don't actually trace, but act like the trace didn't hit anything. +===================== +*/ +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + memset( ptr, 0, sizeof( *ptr ) ); + ptr->flFraction = 1.0; +} + +/* +===================== +UTIL_ParticleBox + +For debugging, draw a box around a player made out of particles +===================== +*/ +void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + int i; + vec3_t mmin, mmax; + + for ( i = 0; i < 3; i++ ) + { + mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; + mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + } + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); +} + +/* +===================== +UTIL_ParticleBoxes + +For debugging, draw boxes for other collidable players +===================== +*/ +void UTIL_ParticleBoxes( void ) +{ + int idx; + physent_t *pe; + cl_entity_t *player; + vec3_t mins, maxs; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + player = gEngfuncs.GetLocalPlayer(); + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); + + for ( idx = 1; idx < 100; idx++ ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); + if ( !pe ) + break; + + if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + { + mins = pe->origin + pe->mins; + maxs = pe->origin + pe->maxs; + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +===================== +UTIL_ParticleLine + +For debugging, draw a line made out of particles +===================== +*/ +void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); +} + +/* +===================== +CBasePlayerWeapon::PrintState + +For debugging, print out state variables to log file +===================== +*/ +void CBasePlayerWeapon::PrintState( void ) +{ + COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); + COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%i ", m_iClip ); +} + +int RandomLong( int a, int b ) +{ + return gEngfuncs.pfnRandomLong(a, b); +} + + +/* +===================== +HUD_InitClientWeapons + +Set up weapons, player and functions needed to run weapons code client-side. +===================== +*/ +void HUD_InitClientWeapons( void ) +{ + static int initialized = 0; + if ( initialized ) + return; + + initialized = 1; + + // Set up pointer ( dummy object ) + gpGlobals = &Globals; + + // Fill in current time ( probably not needed ) + gpGlobals->time = gEngfuncs.GetClientTime(); + + // Fake functions + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; + + // Handled locally + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; + + // Pass through to engine + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + + // Allocate a slot for the local player + HUD_PrepEntity( &player , NULL ); + + // Allocate slot(s) for each weapon that we are going to be predicting + HUD_PrepEntity( &g_Glock , &player ); + HUD_PrepEntity( &g_Crowbar , &player ); + HUD_PrepEntity( &g_Python , &player ); + HUD_PrepEntity( &g_Mp5 , &player ); + HUD_PrepEntity( &g_Crossbow , &player ); + HUD_PrepEntity( &g_Shotgun , &player ); + HUD_PrepEntity( &g_Rpg , &player ); + HUD_PrepEntity( &g_Gauss , &player ); + HUD_PrepEntity( &g_Egon , &player ); + HUD_PrepEntity( &g_HGun , &player ); + HUD_PrepEntity( &g_HandGren , &player ); + HUD_PrepEntity( &g_Satchel , &player ); + HUD_PrepEntity( &g_Tripmine , &player ); + HUD_PrepEntity( &g_Snark , &player ); +} + +/* +===================== +HUD_GetLastOrg + +Retruns the last position that we stored for egon beam endpoint. +===================== +*/ +void HUD_GetLastOrg( float *org ) +{ + int i; + + // Return last origin + for ( i = 0; i < 3; i++ ) + { + org[i] = previousorigin[i]; + } +} + +/* +===================== +HUD_SetLastOrg + +Remember our exact predicted origin so we can draw the egon to the right position. +===================== +*/ +void HUD_SetLastOrg( void ) +{ + int i; + + // Offset final origin by view_offset + for ( i = 0; i < 3; i++ ) + { + previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; + } +} + +/* +===================== +HUD_WeaponsPostThink + +Run Weapon firing code on client +===================== +*/ +void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) +{ + int i; + int buttonsChanged; + CBasePlayerWeapon *pWeapon = NULL; + CBasePlayerWeapon *pCurrent; + weapon_data_t nulldata, *pfrom, *pto; + static int lasthealth; + + memset( &nulldata, 0, sizeof( nulldata ) ); + + HUD_InitClientWeapons(); + + // Get current clock + gpGlobals->time = time; + + // Fill in data based on selected weapon + // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? + switch ( from->client.m_iId ) + { + case WEAPON_CROWBAR: + pWeapon = &g_Crowbar; + break; + + case WEAPON_GLOCK: + pWeapon = &g_Glock; + break; + + case WEAPON_PYTHON: + pWeapon = &g_Python; + break; + + case WEAPON_MP5: + pWeapon = &g_Mp5; + break; + + case WEAPON_CROSSBOW: + pWeapon = &g_Crossbow; + break; + + case WEAPON_SHOTGUN: + pWeapon = &g_Shotgun; + break; + + case WEAPON_RPG: + pWeapon = &g_Rpg; + break; + + case WEAPON_GAUSS: + pWeapon = &g_Gauss; + break; + + case WEAPON_EGON: + pWeapon = &g_Egon; + break; + + case WEAPON_HORNETGUN: + pWeapon = &g_HGun; + break; + + case WEAPON_HANDGRENADE: + pWeapon = &g_HandGren; + break; + + case WEAPON_SATCHEL: + pWeapon = &g_Satchel; + break; + + case WEAPON_TRIPMINE: + pWeapon = &g_Tripmine; + break; + + case WEAPON_SNARK: + pWeapon = &g_Snark; + break; + } + + // Store pointer to our destination entity_state_t so we can get our origin, etc. from it + // for setting up events on the client + g_finalstate = to; + + // If we are running events/etc. go ahead and see if we + // managed to die between last frame and this one + // If so, run the appropriate player killed or spawn function + if ( g_runfuncs ) + { + if ( to->client.health <= 0 && lasthealth > 0 ) + { + player.Killed( NULL, 0 ); + + } + else if ( to->client.health > 0 && lasthealth <= 0 ) + { + player.Spawn(); + } + + lasthealth = to->client.health; + } + + // We are not predicting the current weapon, just bow out here. + if ( !pWeapon ) + return; + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + if ( !pCurrent ) + { + continue; + } + + pfrom = &from->weapondata[ i ]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; +// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; + pCurrent->m_iClip = pfrom->m_iClip; + pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; + pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + pCurrent->pev->fuser1 = pfrom->fuser1; + pCurrent->m_flStartThrow = pfrom->fuser2; + pCurrent->m_flReleaseThrow = pfrom->fuser3; + pCurrent->m_chargeReady = pfrom->iuser1; + pCurrent->m_fInAttack = pfrom->iuser2; + pCurrent->m_fireState = pfrom->iuser3; + + pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; + pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; + player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; + player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; + } + + // For random weapon events, use this seed to seed random # generator + player.random_seed = random_seed; + + // Get old buttons from previous state. + player.m_afButtonLast = from->playerstate.oldbuttons; + + // Which buttsons chave changed + buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // The changed ones still down are "pressed" + player.m_afButtonPressed = buttonsChanged & cmd->buttons; + // The ones not down are "released" + player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + + // Set player variables that weapons code might check/alter + player.pev->button = cmd->buttons; + + player.pev->velocity = from->client.velocity; + player.pev->flags = from->client.flags; + + player.pev->deadflag = from->client.deadflag; + player.pev->waterlevel = from->client.waterlevel; + player.pev->maxspeed = from->client.maxspeed; + player.pev->fov = from->client.fov; + player.pev->weaponanim = from->client.weaponanim; + player.pev->viewmodel = from->client.viewmodel; + player.m_flNextAttack = from->client.m_flNextAttack; + player.m_flNextAmmoBurn = from->client.fuser2; + player.m_flAmmoStartCharge = from->client.fuser3; + + //Stores all our ammo info, so the client side weapons can use them. + player.ammo_9mm = (int)from->client.vuser1[0]; + player.ammo_357 = (int)from->client.vuser1[1]; + player.ammo_argrens = (int)from->client.vuser1[2]; + player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... + player.ammo_buckshot = (int)from->client.ammo_shells; + player.ammo_uranium = (int)from->client.ammo_cells; + player.ammo_hornets = (int)from->client.vuser2[0]; + player.ammo_rockets = (int)from->client.ammo_rockets; + + + // Point to current weapon object + if ( from->client.m_iId ) + { + player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + } + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; + ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; + } + + // Don't go firing anything if we have died. + // Or if we don't have a weapon model deployed + if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && + !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) + { + if ( player.m_flNextAttack <= 0 ) + { + pWeapon->ItemPostFrame(); + } + } + + // Assume that we are not going to switch weapons + to->client.m_iId = from->client.m_iId; + + // Now see if we issued a changeweapon command ( and we're not dead ) + if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + { + // Switched to a different weapon? + if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + { + CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; + if ( pNew && ( pNew != pWeapon ) ) + { + // Put away old weapon + if (player.m_pActiveItem) + player.m_pActiveItem->Holster( ); + + player.m_pLastItem = player.m_pActiveItem; + player.m_pActiveItem = pNew; + + // Deploy new weapon + if (player.m_pActiveItem) + { + player.m_pActiveItem->Deploy( ); + } + + // Update weapon id so we can predict things correctly. + to->client.m_iId = cmd->weaponselect; + } + } + } + + // Copy in results of prediction code + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + to->client.fuser2 = player.m_flNextAmmoBurn; + to->client.fuser3 = player.m_flAmmoStartCharge; + to->client.maxspeed = player.pev->maxspeed; + + //HL Weapons + to->client.vuser1[0] = player.ammo_9mm; + to->client.vuser1[1] = player.ammo_357; + to->client.vuser1[2] = player.ammo_argrens; + + to->client.ammo_nails = player.ammo_bolts; + to->client.ammo_shells = player.ammo_buckshot; + to->client.ammo_cells = player.ammo_uranium; + to->client.vuser2[0] = player.ammo_hornets; + to->client.ammo_rockets = player.ammo_rockets; + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; + from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; + } + + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) + { + int body = 2; + + //Pop the model to body 0. + if ( pWeapon == &g_Tripmine ) + body = 0; + + //Show laser sight/scope combo + if ( pWeapon == &g_Python && bIsMultiplayer() ) + body = 1; + + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); + } + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + + pto = &to->weapondata[ i ]; + + if ( !pCurrent ) + { + memset( pto, 0, sizeof( weapon_data_t ) ); + continue; + } + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; +// pto->m_flPumpTime = pCurrent->m_flPumpTime; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; + pto->fuser1 = pCurrent->pev->fuser1; + pto->fuser2 = pCurrent->m_flStartThrow; + pto->fuser3 = pCurrent->m_flReleaseThrow; + pto->iuser1 = pCurrent->m_chargeReady; + pto->iuser2 = pCurrent->m_fInAttack; + pto->iuser3 = pCurrent->m_fireState; + + // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + pto->fuser1 -= cmd->msec / 1000.0; + + to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; + to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; + to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; + to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; + +/* if ( pto->m_flPumpTime != -9999 ) + { + pto->m_flPumpTime -= cmd->msec / 1000.0; + if ( pto->m_flPumpTime < -0.001 ) + pto->m_flPumpTime = -0.001; + }*/ + + if ( pto->m_fNextAimBonus < -1.0 ) + { + pto->m_fNextAimBonus = -1.0; + } + + if ( pto->m_flNextPrimaryAttack < -1.0 ) + { + pto->m_flNextPrimaryAttack = -1.0; + } + + if ( pto->m_flNextSecondaryAttack < -0.001 ) + { + pto->m_flNextSecondaryAttack = -0.001; + } + + if ( pto->m_flTimeWeaponIdle < -0.001 ) + { + pto->m_flTimeWeaponIdle = -0.001; + } + + if ( pto->m_flNextReload < -0.001 ) + { + pto->m_flNextReload = -0.001; + } + + if ( pto->fuser1 < -0.001 ) + { + pto->fuser1 = -0.001; + } + } + + // m_flNextAttack is now part of the weapons, but is part of the player instead + to->client.m_flNextAttack -= cmd->msec / 1000.0; + if ( to->client.m_flNextAttack < -0.001 ) + { + to->client.m_flNextAttack = -0.001; + } + + to->client.fuser2 -= cmd->msec / 1000.0; + if ( to->client.fuser2 < -0.001 ) + { + to->client.fuser2 = -0.001; + } + + to->client.fuser3 -= cmd->msec / 1000.0; + if ( to->client.fuser3 < -0.001 ) + { + to->client.fuser3 = -0.001; + } + + // Store off the last position from the predicted state. + HUD_SetLastOrg(); + + // Wipe it so we can't use it after this frame + g_finalstate = NULL; +} + +/* +===================== +HUD_PostRunCmd + +Client calls this during prediction, after it has moved the player and updated any info changed into to-> +time is the current client clock based on prediction +cmd is the command that caused the movement, etc +runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should +be ignored +===================== +*/ +void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) +{ + g_runfuncs = runfuncs; + +#if defined( CLIENT_WEAPONS ) + if ( cl_lw && cl_lw->value ) + { + HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); + } + else +#endif + { + to->client.fov = g_lastFOV; + } + + if ( g_irunninggausspred == 1 ) + { + Vector forward; + gEngfuncs.pfnAngleVectors( v_angles, forward, NULL, NULL ); + to->client.velocity = to->client.velocity - forward * g_flApplyVel * 5; + g_irunninggausspred = false; + } + + // All games can use FOV state + g_lastFOV = to->client.fov; +} diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index d99ce6bb..8fdc3992 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -1,589 +1,589 @@ -/*** -* -* 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. -* -****/ -// -// hud.cpp -// -// implementation of CHud class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "parsemsg.h" -#include "hud_servers.h" - - -#include "demo.h" -#include "demo_api.h" - -cvar_t *hud_textmode; -float g_hud_text_color[3]; - - -extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); - -extern cvar_t *sensitivity; -cvar_t *cl_lw = NULL; - -void ShutdownInput (void); - -//DECLARE_MESSAGE(m_Logo, Logo) -int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_Logo(pszName, iSize, pbuf ); -} - -//DECLARE_MESSAGE(m_Logo, Logo) -int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); -} - -int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) -{ - gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); - return 1; -} - -int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) -{ - gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); - return 1; -} - -int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); -} - -int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf) -{ - return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); -} - -int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) -{ - return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); -} - -// TFFree Command Menu -void __CmdFunc_OpenCommandMenu(void) -{ -} - -// TFC "special" command -void __CmdFunc_InputPlayerSpecial(void) -{ -} - -void __CmdFunc_CloseCommandMenu(void) -{ -} - -void __CmdFunc_ForceCloseCommandMenu( void ) -{ -} - -void __CmdFunc_ToggleServerBrowser( void ) -{ -} - -// TFFree Command Menu Message Handlers -int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - - -int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) -{ - return 0; -} - -// This is called every time the DLL is loaded -void CHud :: Init( void ) -{ - HOOK_MESSAGE( Logo ); - HOOK_MESSAGE( ResetHUD ); - HOOK_MESSAGE( GameMode ); - HOOK_MESSAGE( InitHUD ); - HOOK_MESSAGE( ViewMode ); - HOOK_MESSAGE( SetFOV ); - HOOK_MESSAGE( Concuss ); - - // TFFree CommandMenu - HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); - HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); - HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); - HOOK_COMMAND( "special", InputPlayerSpecial ); - HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); - - HOOK_MESSAGE( ValClass ); - HOOK_MESSAGE( TeamNames ); - HOOK_MESSAGE( Feign ); - HOOK_MESSAGE( Detpack ); - HOOK_MESSAGE( BuildSt ); - HOOK_MESSAGE( RandomPC ); - HOOK_MESSAGE( ServerName ); - - HOOK_MESSAGE( Spectator ); - HOOK_MESSAGE( AllowSpec ); - - // VGUI Menus - HOOK_MESSAGE( VGUIMenu ); - - CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch - CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round - hud_textmode = CVAR_CREATE ( "hud_textmode", "0", FCVAR_ARCHIVE ); - - m_iLogo = 0; - m_iFOV = 0; - - CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); - default_fov = CVAR_CREATE( "default_fov", "90", 0 ); - m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); - m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); - cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); - - m_pSpriteList = NULL; - - // Clear any old HUD list - if ( m_pHudList ) - { - HUDLIST *pList; - while ( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - // In case we get messages before the first update -- time will be valid - m_flTime = 1.0; - - m_Ammo.Init(); - m_Health.Init(); - m_SayText.Init(); - m_Spectator.Init(); - m_Geiger.Init(); - m_Train.Init(); - m_Battery.Init(); - m_Flash.Init(); - m_Message.Init(); - m_StatusBar.Init(); - m_DeathNotice.Init(); - m_AmmoSecondary.Init(); - m_TextMessage.Init(); - m_StatusIcons.Init(); - m_MOTD.Init(); - m_Scoreboard.Init(); - - m_Menu.Init(); - - - MsgFunc_ResetHUD(0, 0, NULL ); -} - -// CHud destructor -// cleans up memory allocated for m_rg* arrays -CHud :: ~CHud() -{ - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; - - if ( m_pHudList ) - { - HUDLIST *pList; - while ( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - -} - -// GetSpriteIndex() -// searches through the sprite list loaded from hud.txt for a name matching SpriteName -// returns an index into the gHUD.m_rghSprites[] array -// returns 0 if sprite not found -int CHud :: GetSpriteIndex( const char *SpriteName ) -{ - // look through the loaded sprite name list for SpriteName - for ( int i = 0; i < m_iSpriteCount; i++ ) - { - if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) - return i; - } - - return -1; // invalid sprite -} - -void CHud :: VidInit( void ) -{ +/*** +* +* 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. +* +****/ +// +// hud.cpp +// +// implementation of CHud class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "hud_servers.h" + + +#include "demo.h" +#include "demo_api.h" + +cvar_t *hud_textmode; +float g_hud_text_color[3]; + + +extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +extern cvar_t *sensitivity; +cvar_t *cl_lw = NULL; + +void ShutdownInput (void); + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Logo(pszName, iSize, pbuf ); +} + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); +} + +int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); +} + +int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); +} + +int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); +} + +// TFFree Command Menu +void __CmdFunc_OpenCommandMenu(void) +{ +} + +// TFC "special" command +void __CmdFunc_InputPlayerSpecial(void) +{ +} + +void __CmdFunc_CloseCommandMenu(void) +{ +} + +void __CmdFunc_ForceCloseCommandMenu( void ) +{ +} + +void __CmdFunc_ToggleServerBrowser( void ) +{ +} + +// TFFree Command Menu Message Handlers +int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + + +int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) +{ + return 0; +} + +// This is called every time the DLL is loaded +void CHud :: Init( void ) +{ + HOOK_MESSAGE( Logo ); + HOOK_MESSAGE( ResetHUD ); + HOOK_MESSAGE( GameMode ); + HOOK_MESSAGE( InitHUD ); + HOOK_MESSAGE( ViewMode ); + HOOK_MESSAGE( SetFOV ); + HOOK_MESSAGE( Concuss ); + + // TFFree CommandMenu + HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); + HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); + HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); + HOOK_COMMAND( "special", InputPlayerSpecial ); + HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); + + HOOK_MESSAGE( ValClass ); + HOOK_MESSAGE( TeamNames ); + HOOK_MESSAGE( Feign ); + HOOK_MESSAGE( Detpack ); + HOOK_MESSAGE( BuildSt ); + HOOK_MESSAGE( RandomPC ); + HOOK_MESSAGE( ServerName ); + + HOOK_MESSAGE( Spectator ); + HOOK_MESSAGE( AllowSpec ); + + // VGUI Menus + HOOK_MESSAGE( VGUIMenu ); + + CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch + CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round + hud_textmode = CVAR_CREATE ( "hud_textmode", "0", FCVAR_ARCHIVE ); + + m_iLogo = 0; + m_iFOV = 0; + + CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); + default_fov = CVAR_CREATE( "default_fov", "90", 0 ); + m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); + m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); + cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); + + m_pSpriteList = NULL; + + // Clear any old HUD list + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + // In case we get messages before the first update -- time will be valid + m_flTime = 1.0; + + m_Ammo.Init(); + m_Health.Init(); + m_SayText.Init(); + m_Spectator.Init(); + m_Geiger.Init(); + m_Train.Init(); + m_Battery.Init(); + m_Flash.Init(); + m_Message.Init(); + m_StatusBar.Init(); + m_DeathNotice.Init(); + m_AmmoSecondary.Init(); + m_TextMessage.Init(); + m_StatusIcons.Init(); + m_MOTD.Init(); + m_Scoreboard.Init(); + + m_Menu.Init(); + + + MsgFunc_ResetHUD(0, 0, NULL ); +} + +// CHud destructor +// cleans up memory allocated for m_rg* arrays +CHud :: ~CHud() +{ + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + +} + +// GetSpriteIndex() +// searches through the sprite list loaded from hud.txt for a name matching SpriteName +// returns an index into the gHUD.m_rghSprites[] array +// returns 0 if sprite not found +int CHud :: GetSpriteIndex( const char *SpriteName ) +{ + // look through the loaded sprite name list for SpriteName + for ( int i = 0; i < m_iSpriteCount; i++ ) + { + if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) + return i; + } + + return -1; // invalid sprite +} + +void CHud :: VidInit( void ) +{ int j; - m_scrinfo.iSize = sizeof(m_scrinfo); - GetScreenInfo(&m_scrinfo); - - // ---------- - // Load Sprites - // --------- -// m_hsprFont = LoadSprite("sprites/%d_font.spr"); - - m_hsprLogo = 0; - m_hsprCursor = 0; - - if (ScreenWidth < 640) - m_iRes = 320; - else - m_iRes = 640; - - // Only load this once - if ( !m_pSpriteList ) - { - // we need to load the hud.txt, and all sprites within - m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); - - if (m_pSpriteList) - { - // count the number of sprites of the appropriate res - m_iSpriteCount = 0; - client_sprite_t *p = m_pSpriteList; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - m_iSpriteCount++; - p++; - } - - // allocated memory for sprite handle arrays - m_rghSprites = new HSPRITE[m_iSpriteCount]; - m_rgrcRects = new wrect_t[m_iSpriteCount]; - m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; - - p = m_pSpriteList; - int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf(sz, "sprites/%s.spr", p->szSprite); - m_rghSprites[index] = SPR_Load(sz); - m_rgrcRects[index] = p->rc; - strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); - - index++; - } - - p++; - } - } - } - else - { - // we have already have loaded the sprite reference from hud.txt, but - // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) - client_sprite_t *p = m_pSpriteList; - - // count the number of sprites of the appropriate res - m_iSpriteCount = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - m_iSpriteCount++; - p++; - } - - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; - - // allocated memory for sprite handle arrays - m_rghSprites = new HSPRITE[m_iSpriteCount]; - m_rgrcRects = new wrect_t[m_iSpriteCount]; - m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; - - p = m_pSpriteList; - int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf( sz, "sprites/%s.spr", p->szSprite ); - m_rghSprites[index] = SPR_Load(sz); - m_rgrcRects[index] = p->rc; - strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); - - index++; - } - - p++; - } - } - - // assumption: number_1, number_2, etc, are all listed and loaded sequentially - m_HUD_number_0 = GetSpriteIndex( "number_0" ); - - m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; - - m_Ammo.VidInit(); - m_Health.VidInit(); - m_Spectator.VidInit(); - m_Geiger.VidInit(); - m_Train.VidInit(); - m_Battery.VidInit(); - m_Flash.VidInit(); - m_Message.VidInit(); - m_StatusBar.VidInit(); - m_DeathNotice.VidInit(); - m_SayText.VidInit(); - m_Menu.VidInit(); - m_AmmoSecondary.VidInit(); - m_TextMessage.VidInit(); - m_StatusIcons.VidInit(); - m_Scoreboard.VidInit(); - m_MOTD.VidInit(); - -} - -int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - // update Train data - m_iLogo = READ_BYTE(); - - return 1; -} - -float g_lastFOV = 0.0; - -/* -============ -COM_FileBase -============ -*/ -// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) -void COM_FileBase ( const char *in, char *out) -{ - int len, start, end; - - len = strlen( in ); - - // scan backward for '.' - end = len - 1; - while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) - end--; - - if ( in[end] != '.' ) // no '.', copy to end - end = len-1; - else - end--; // Found ',', copy to left of '.' - - - // Scan backward for '/' - start = len-1; - while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) - start--; - - if ( in[start] != '/' && in[start] != '\\' ) - start = 0; - else - start++; - - // Length of new sting - len = end - start + 1; - - // Copy partial string - strncpy( out, &in[start], len ); - // Terminate it - out[len] = 0; -} - -/* -================= -HUD_IsGame - -================= -*/ -int HUD_IsGame( const char *game ) -{ - const char *gamedir; - char gd[ 1024 ]; - - gamedir = gEngfuncs.pfnGetGameDirectory(); - if ( gamedir && gamedir[0] ) - { - COM_FileBase( gamedir, gd ); - if ( !stricmp( gd, game ) ) - return 1; - } - return 0; -} - -/* -===================== -HUD_GetFOV - -Returns last FOV -===================== -*/ -float HUD_GetFOV( void ) -{ - if ( gEngfuncs.pDemoAPI->IsRecording() ) - { - // Write it - int i = 0; - unsigned char buf[ 100 ]; - - // Active - *( float * )&buf[ i ] = g_lastFOV; - i += sizeof( float ); - - Demo_WriteBuffer( TYPE_ZOOM, i, buf ); - } - - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) - { - g_lastFOV = g_demozoom; - } - return g_lastFOV; -} - -int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - int newfov = READ_BYTE(); - int def_fov = CVAR_GET_FLOAT( "default_fov" ); - - //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). - if ( cl_lw && cl_lw->value ) - return 1; - - g_lastFOV = newfov; - - if ( newfov == 0 ) - { - m_iFOV = def_fov; - } - else - { - m_iFOV = newfov; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == def_fov ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); - } - - return 1; -} - - -void CHud::AddHudElem(CHudBase *phudelem) -{ - HUDLIST *pdl, *ptemp; - -//phudelem->Think(); - - if (!phudelem) - return; - - pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); - if (!pdl) - return; - - memset(pdl, 0, sizeof(HUDLIST)); - pdl->p = phudelem; - - if (!m_pHudList) - { - m_pHudList = pdl; - return; - } - - ptemp = m_pHudList; - - while (ptemp->pNext) - ptemp = ptemp->pNext; - - ptemp->pNext = pdl; -} - -float CHud::GetSensitivity( void ) -{ - return m_flMouseSensitivity; -} - - + m_scrinfo.iSize = sizeof(m_scrinfo); + GetScreenInfo(&m_scrinfo); + + // ---------- + // Load Sprites + // --------- +// m_hsprFont = LoadSprite("sprites/%d_font.spr"); + + m_hsprLogo = 0; + m_hsprCursor = 0; + + if (ScreenWidth < 640) + m_iRes = 320; + else + m_iRes = 640; + + // Only load this once + if ( !m_pSpriteList ) + { + // we need to load the hud.txt, and all sprites within + m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); + + if (m_pSpriteList) + { + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + client_sprite_t *p = m_pSpriteList; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf(sz, "sprites/%s.spr", p->szSprite); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + } + else + { + // we have already have loaded the sprite reference from hud.txt, but + // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) + client_sprite_t *p = m_pSpriteList; + + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + + // assumption: number_1, number_2, etc, are all listed and loaded sequentially + m_HUD_number_0 = GetSpriteIndex( "number_0" ); + + m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; + + m_Ammo.VidInit(); + m_Health.VidInit(); + m_Spectator.VidInit(); + m_Geiger.VidInit(); + m_Train.VidInit(); + m_Battery.VidInit(); + m_Flash.VidInit(); + m_Message.VidInit(); + m_StatusBar.VidInit(); + m_DeathNotice.VidInit(); + m_SayText.VidInit(); + m_Menu.VidInit(); + m_AmmoSecondary.VidInit(); + m_TextMessage.VidInit(); + m_StatusIcons.VidInit(); + m_Scoreboard.VidInit(); + m_MOTD.VidInit(); + +} + +int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update Train data + m_iLogo = READ_BYTE(); + + return 1; +} + +float g_lastFOV = 0.0; + +/* +============ +COM_FileBase +============ +*/ +// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) +void COM_FileBase ( const char *in, char *out) +{ + int len, start, end; + + len = strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + end--; + + if ( in[end] != '.' ) // no '.', copy to end + end = len-1; + else + end--; // Found ',', copy to left of '.' + + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start--; + + if ( in[start] != '/' && in[start] != '\\' ) + start = 0; + else + start++; + + // Length of new sting + len = end - start + 1; + + // Copy partial string + strncpy( out, &in[start], len ); + // Terminate it + out[len] = 0; +} + +/* +================= +HUD_IsGame + +================= +*/ +int HUD_IsGame( const char *game ) +{ + const char *gamedir; + char gd[ 1024 ]; + + gamedir = gEngfuncs.pfnGetGameDirectory(); + if ( gamedir && gamedir[0] ) + { + COM_FileBase( gamedir, gd ); + if ( !stricmp( gd, game ) ) + return 1; + } + return 0; +} + +/* +===================== +HUD_GetFOV + +Returns last FOV +===================== +*/ +float HUD_GetFOV( void ) +{ + if ( gEngfuncs.pDemoAPI->IsRecording() ) + { + // Write it + int i = 0; + unsigned char buf[ 100 ]; + + // Active + *( float * )&buf[ i ] = g_lastFOV; + i += sizeof( float ); + + Demo_WriteBuffer( TYPE_ZOOM, i, buf ); + } + + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + { + g_lastFOV = g_demozoom; + } + return g_lastFOV; +} + +int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int newfov = READ_BYTE(); + int def_fov = CVAR_GET_FLOAT( "default_fov" ); + + //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). + if ( cl_lw && cl_lw->value ) + return 1; + + g_lastFOV = newfov; + + if ( newfov == 0 ) + { + m_iFOV = def_fov; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == def_fov ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + return 1; +} + + +void CHud::AddHudElem(CHudBase *phudelem) +{ + HUDLIST *pdl, *ptemp; + +//phudelem->Think(); + + if (!phudelem) + return; + + pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); + if (!pdl) + return; + + memset(pdl, 0, sizeof(HUDLIST)); + pdl->p = phudelem; + + if (!m_pHudList) + { + m_pHudList = pdl; + return; + } + + ptemp = m_pHudList; + + while (ptemp->pNext) + ptemp = ptemp->pNext; + + ptemp->pNext = pdl; +} + +float CHud::GetSensitivity( void ) +{ + return m_flMouseSensitivity; +} + + diff --git a/cl_dll/hud.h b/cl_dll/hud.h index e2d56f26..aa535d80 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -1,702 +1,702 @@ -/*** -* -* 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. -* -****/ -// -// hud.h -// -// class CHud declaration -// -// CHud handles the message, calculation, and drawing the HUD -// - - -#define RGB_YELLOWISH 0x00FFA000 //255,160,0 -#define RGB_REDISH 0x00FF1010 //255,160,0 -#define RGB_GREENISH 0x0000A000 //0,160,0 - -#include "wrect.h" -#include "cl_dll.h" -#include "ammo.h" - -#define DHN_DRAWZERO 1 -#define DHN_2DIGITS 2 -#define DHN_3DIGITS 4 -#define MIN_ALPHA 100 - -#define HUDELEM_ACTIVE 1 - -typedef struct { - int x, y; -} POSITION; - -enum -{ - MAX_PLAYERS = 64, - MAX_TEAMS = 64, - MAX_TEAM_NAME = 16, -}; - -typedef struct { - unsigned char r,g,b,a; -} RGBA; - -typedef struct cvar_s cvar_t; - - -#define HUD_ACTIVE 1 -#define HUD_INTERMISSION 2 - -#define MAX_PLAYER_NAME_LENGTH 32 - -#define MAX_MOTD_LENGTH 1536 - -// -//----------------------------------------------------- -// -class CHudBase -{ -public: - POSITION m_pos; - int m_type; - int m_iFlags; // active, moving, - virtual ~CHudBase() {} - virtual int Init( void ) {return 0;} - virtual int VidInit( void ) {return 0;} - virtual int Draw(float flTime) {return 0;} - virtual void Think(void) {return;} - virtual void Reset(void) {return;} - virtual void InitHUDData( void ) {} // called every time a server is connected to - -}; - -struct HUDLIST { - CHudBase *p; - HUDLIST *pNext; -}; - - - -// -//----------------------------------------------------- -#include "hud_spectator.h" - - -// -//----------------------------------------------------- -// -class CHudAmmo: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - void Think(void); - void Reset(void); - int DrawWList(float flTime); - int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); - int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); - int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); - int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); - - void SlotInput( int iSlot ); - void _cdecl UserCmd_Slot1( void ); - void _cdecl UserCmd_Slot2( void ); - void _cdecl UserCmd_Slot3( void ); - void _cdecl UserCmd_Slot4( void ); - void _cdecl UserCmd_Slot5( void ); - void _cdecl UserCmd_Slot6( void ); - void _cdecl UserCmd_Slot7( void ); - void _cdecl UserCmd_Slot8( void ); - void _cdecl UserCmd_Slot9( void ); - void _cdecl UserCmd_Slot10( void ); - void _cdecl UserCmd_Close( void ); - void _cdecl UserCmd_NextWeapon( void ); - void _cdecl UserCmd_PrevWeapon( void ); - -private: - float m_fFade; - RGBA m_rgba; - WEAPON *m_pWeapon; - int m_HUD_bucket0; - int m_HUD_selection; - -}; - -// -//----------------------------------------------------- -// - -class CHudAmmoSecondary: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - void Reset( void ); - int Draw(float flTime); - - int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); - -private: - enum { - MAX_SEC_AMMO_VALUES = 4 - }; - - int m_HUD_ammoicon; // sprite indices - int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; - float m_fFade; -}; - - -#include "health.h" - - -#define FADE_TIME 100 - - -// -//----------------------------------------------------- -// -class CHudGeiger: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); - -private: - int m_iGeigerRange; - -}; - -// -//----------------------------------------------------- -// -class CHudTrain: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); - -private: - HSPRITE m_hSprite; - int m_iPos; - -}; - -// -//----------------------------------------------------- -// -// REMOVED: Vgui has replaced this. -// - -class CHudMOTD : public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw( float flTime ); - void Reset( void ); - - int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); - void Scroll( int dir ); - void Scroll( float amount ); - float scroll; - bool m_bShow; - -protected: - static int MOTD_DISPLAY_TIME; - char m_szMOTD[ MAX_MOTD_LENGTH ]; - - int m_iLines; - int m_iMaxLength; -}; - - -class CHudScoreboard: public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing - void UserCmd_ShowScores( void ); - void UserCmd_HideScores( void ); - int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScores( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamNames( const char *pszName, int iSize, void *pbuf ); - void DeathMsg( int killer, int victim ); - - int m_iNumTeams; - - int m_iLastKilledBy; - int m_fLastKillTime; - int m_iPlayerNum; - int m_iShowscoresHeld; - - void GetAllPlayersInfo( void ); -}; - - -// -//----------------------------------------------------- -// -class CHudStatusBar : public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw( float flTime ); - void Reset( void ); - void ParseStatusString( int line_num ); - - int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); - -protected: - enum { - MAX_STATUSTEXT_LENGTH = 128, - MAX_STATUSBAR_VALUES = 8, - MAX_STATUSBAR_LINES = 2, - }; - - char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn - char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn - int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar - - int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated - - // an array of colors...one color for each line - float *m_pflNameColors[MAX_STATUSBAR_LINES]; -}; - -// -//----------------------------------------------------- -// -// REMOVED: Vgui has replaced this. -// -/* -class CHudScoreboard: public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing - void UserCmd_ShowScores( void ); - void UserCmd_HideScores( void ); - int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); - void DeathMsg( int killer, int victim ); - - int m_iNumTeams; - - int m_iLastKilledBy; - int m_fLastKillTime; - int m_iPlayerNum; - int m_iShowscoresHeld; - - void GetAllPlayersInfo( void ); -private: - struct cvar_s *cl_showpacketloss; - -}; -*/ - -struct extra_player_info_t -{ - short frags; - short deaths; - short playerclass; - short teamnumber; - char teamname[MAX_TEAM_NAME]; -}; - -struct team_info_t -{ - char name[MAX_TEAM_NAME]; - short frags; - short deaths; - short ping; - short packetloss; - short ownteam; - short players; - int already_drawn; - int scores_overriden; - int teamnumber; -}; - -extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -extern team_info_t g_TeamInfo[MAX_TEAMS+1]; -extern int g_IsSpectator[MAX_PLAYERS+1]; - - -// -//----------------------------------------------------- -// -class CHudDeathNotice : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ); - -private: - int m_HUD_d_skull; // sprite index of skull icon -}; - -// -//----------------------------------------------------- -// -class CHudMenu : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - void Reset( void ); - int Draw( float flTime ); - int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ); - - void SelectMenuItem( int menu_item ); - - int m_fMenuDisplayed; - int m_bitsValidSlots; - float m_flShutoffTime; - int m_fWaitingForMore; -}; - -// -//----------------------------------------------------- -// -class CHudSayText : public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); - void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); - void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); -friend class CHudSpectator; - -private: - - struct cvar_s * m_HUD_saytext; - struct cvar_s * m_HUD_saytext_time; -}; - -// -//----------------------------------------------------- -// -class CHudBattery: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); - -private: - HSPRITE m_hSprite1; - HSPRITE m_hSprite2; - wrect_t *m_prc1; - wrect_t *m_prc2; - int m_iBat; - float m_fFade; - int m_iHeight; // width of the battery innards -}; - - -// -//----------------------------------------------------- -// -class CHudFlashlight: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - void Reset( void ); - int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); - int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); - -private: - HSPRITE m_hSprite1; - HSPRITE m_hSprite2; - HSPRITE m_hBeam; - wrect_t *m_prc1; - wrect_t *m_prc2; - wrect_t *m_prcBeam; - float m_flBat; - int m_iBat; - int m_fOn; - float m_fFade; - int m_iWidth; // width of the battery innards -}; - -// -//----------------------------------------------------- -// -const int maxHUDMessages = 16; -struct message_parms_t -{ - client_textmessage_t *pMessage; - float time; - int x, y; - int totalWidth, totalHeight; - int width; - int lines; - int lineLength; - int length; - int r, g, b; - int text; - int fadeBlend; - float charTime; - float fadeTime; -}; - -// -//----------------------------------------------------- -// - -class CHudTextMessage: public CHudBase -{ -public: - int Init( void ); - static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); - static char *BufferedLocaliseTextString( const char *msg ); - char *LookupString( const char *msg_name, int *msg_dest = NULL ); - int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); -}; - -// -//----------------------------------------------------- -// - -class CHudMessage: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - int Draw(float flTime); - int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); - int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); - - float FadeBlend( float fadein, float fadeout, float hold, float localTime ); - int XPosition( float x, int width, int lineWidth ); - int YPosition( float y, int height ); - - void MessageAdd( const char *pName, float time ); - void MessageAdd(client_textmessage_t * newMessage ); - void MessageDrawScan( client_textmessage_t *pMessage, float time ); - void MessageScanStart( void ); - void MessageScanNextChar( void ); - void Reset( void ); - -private: - client_textmessage_t *m_pMessages[maxHUDMessages]; - float m_startTime[maxHUDMessages]; - message_parms_t m_parms; - float m_gameTitleTime; - client_textmessage_t *m_pGameTitle; - - int m_HUD_title_life; - int m_HUD_title_half; -}; - -// -//----------------------------------------------------- -// -#define MAX_SPRITE_NAME_LENGTH 24 - -class CHudStatusIcons: public CHudBase -{ -public: - int Init( void ); - int VidInit( void ); - void Reset( void ); - int Draw(float flTime); - int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf); - - enum { - MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, - MAX_ICONSPRITES = 4, - }; - - - //had to make these public so CHud could access them (to enable concussion icon) - //could use a friend declaration instead... - void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); - void DisableIcon( char *pszIconName ); - -private: - - typedef struct - { - char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; - HSPRITE spr; - wrect_t rc; - unsigned char r, g, b; - } icon_sprite_t; - - icon_sprite_t m_IconList[MAX_ICONSPRITES]; - -}; - -// -//----------------------------------------------------- -// - - - -class CHud -{ -private: - HUDLIST *m_pHudList; - HSPRITE m_hsprLogo; - int m_iLogo; - client_sprite_t *m_pSpriteList; - int m_iSpriteCount; - int m_iSpriteCountAllRes; - float m_flMouseSensitivity; - int m_iConcussionEffect; - -public: - - HSPRITE m_hsprCursor; - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - double m_flTimeDelta; // the difference between flTime and fOldTime - Vector m_vecOrigin; - Vector m_vecAngles; - int m_iKeyBits; - int m_iHideHUDDisplay; - int m_iFOV; - int m_Teamplay; - int m_iRes; - cvar_t *m_pCvarStealMouse; - cvar_t *m_pCvarDraw; - - int m_iFontHeight; - int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); - int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b ); - int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); - int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); - int GetNumWidth(int iNumber, int iFlags); - int DrawHudStringLen( char *szIt ); - void DrawDarkRectangle( int x, int y, int wide, int tall); - -private: - // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. - // freed in ~CHud() - HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt - wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ - char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ - - struct cvar_s *default_fov; -public: - HSPRITE GetSprite( int index ) - { - return (index < 0) ? 0 : m_rghSprites[index]; - } - - wrect_t& GetSpriteRect( int index ) - { - return m_rgrcRects[index]; - } - - - int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array - - CHudAmmo m_Ammo; - CHudHealth m_Health; - CHudSpectator m_Spectator; - CHudGeiger m_Geiger; - CHudBattery m_Battery; - CHudTrain m_Train; - CHudFlashlight m_Flash; - CHudMessage m_Message; - CHudStatusBar m_StatusBar; - CHudDeathNotice m_DeathNotice; - CHudSayText m_SayText; - CHudMenu m_Menu; - CHudAmmoSecondary m_AmmoSecondary; - CHudTextMessage m_TextMessage; - CHudStatusIcons m_StatusIcons; - CHudScoreboard m_Scoreboard; - CHudMOTD m_MOTD; - - - void Init( void ); - void VidInit( void ); - void Think(void); - int Redraw( float flTime, int intermission ); - int UpdateClientData( client_data_t *cdata, float time ); - - CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} - ~CHud(); // destructor, frees allocated memory - - // user messages - int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf); - int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); - void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); - void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); - int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); - - // Screen information - SCREENINFO m_scrinfo; - - int m_iWeaponBits; - int m_fPlayerDead; - int m_iIntermission; - - // sprite indexes - int m_HUD_number_0; - - int m_iNoConsolePrint; - - void AddHudElem(CHudBase *p); - - float GetSensitivity(); - -}; - - -extern CHud gHUD; - -extern int g_iPlayerClass; -extern int g_iTeamNumber; -extern int g_iUser1; -extern int g_iUser2; -extern int g_iUser3; - +/*** +* +* 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. +* +****/ +// +// hud.h +// +// class CHud declaration +// +// CHud handles the message, calculation, and drawing the HUD +// + + +#define RGB_YELLOWISH 0x00FFA000 //255,160,0 +#define RGB_REDISH 0x00FF1010 //255,160,0 +#define RGB_GREENISH 0x0000A000 //0,160,0 + +#include "wrect.h" +#include "cl_dll.h" +#include "ammo.h" + +#define DHN_DRAWZERO 1 +#define DHN_2DIGITS 2 +#define DHN_3DIGITS 4 +#define MIN_ALPHA 100 + +#define HUDELEM_ACTIVE 1 + +typedef struct { + int x, y; +} POSITION; + +enum +{ + MAX_PLAYERS = 64, + MAX_TEAMS = 64, + MAX_TEAM_NAME = 16, +}; + +typedef struct { + unsigned char r,g,b,a; +} RGBA; + +typedef struct cvar_s cvar_t; + + +#define HUD_ACTIVE 1 +#define HUD_INTERMISSION 2 + +#define MAX_PLAYER_NAME_LENGTH 32 + +#define MAX_MOTD_LENGTH 1536 + +// +//----------------------------------------------------- +// +class CHudBase +{ +public: + POSITION m_pos; + int m_type; + int m_iFlags; // active, moving, + virtual ~CHudBase() {} + virtual int Init( void ) {return 0;} + virtual int VidInit( void ) {return 0;} + virtual int Draw(float flTime) {return 0;} + virtual void Think(void) {return;} + virtual void Reset(void) {return;} + virtual void InitHUDData( void ) {} // called every time a server is connected to + +}; + +struct HUDLIST { + CHudBase *p; + HUDLIST *pNext; +}; + + + +// +//----------------------------------------------------- +#include "hud_spectator.h" + + +// +//----------------------------------------------------- +// +class CHudAmmo: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Think(void); + void Reset(void); + int DrawWList(float flTime); + int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); + int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); + + void SlotInput( int iSlot ); + void _cdecl UserCmd_Slot1( void ); + void _cdecl UserCmd_Slot2( void ); + void _cdecl UserCmd_Slot3( void ); + void _cdecl UserCmd_Slot4( void ); + void _cdecl UserCmd_Slot5( void ); + void _cdecl UserCmd_Slot6( void ); + void _cdecl UserCmd_Slot7( void ); + void _cdecl UserCmd_Slot8( void ); + void _cdecl UserCmd_Slot9( void ); + void _cdecl UserCmd_Slot10( void ); + void _cdecl UserCmd_Close( void ); + void _cdecl UserCmd_NextWeapon( void ); + void _cdecl UserCmd_PrevWeapon( void ); + +private: + float m_fFade; + RGBA m_rgba; + WEAPON *m_pWeapon; + int m_HUD_bucket0; + int m_HUD_selection; + +}; + +// +//----------------------------------------------------- +// + +class CHudAmmoSecondary: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + + int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); + +private: + enum { + MAX_SEC_AMMO_VALUES = 4 + }; + + int m_HUD_ammoicon; // sprite indices + int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; + float m_fFade; +}; + + +#include "health.h" + + +#define FADE_TIME 100 + + +// +//----------------------------------------------------- +// +class CHudGeiger: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); + +private: + int m_iGeigerRange; + +}; + +// +//----------------------------------------------------- +// +class CHudTrain: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); + +private: + HSPRITE m_hSprite; + int m_iPos; + +}; + +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// + +class CHudMOTD : public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw( float flTime ); + void Reset( void ); + + int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); + void Scroll( int dir ); + void Scroll( float amount ); + float scroll; + bool m_bShow; + +protected: + static int MOTD_DISPLAY_TIME; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + + int m_iLines; + int m_iMaxLength; +}; + + +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScores( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamNames( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +}; + + +// +//----------------------------------------------------- +// +class CHudStatusBar : public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw( float flTime ); + void Reset( void ); + void ParseStatusString( int line_num ); + + int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); + +protected: + enum { + MAX_STATUSTEXT_LENGTH = 128, + MAX_STATUSBAR_VALUES = 8, + MAX_STATUSBAR_LINES = 2, + }; + + char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn + char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn + int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar + + int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated + + // an array of colors...one color for each line + float *m_pflNameColors[MAX_STATUSBAR_LINES]; +}; + +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// +/* +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +private: + struct cvar_s *cl_showpacketloss; + +}; +*/ + +struct extra_player_info_t +{ + short frags; + short deaths; + short playerclass; + short teamnumber; + char teamname[MAX_TEAM_NAME]; +}; + +struct team_info_t +{ + char name[MAX_TEAM_NAME]; + short frags; + short deaths; + short ping; + short packetloss; + short ownteam; + short players; + int already_drawn; + int scores_overriden; + int teamnumber; +}; + +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS+1]; +extern int g_IsSpectator[MAX_PLAYERS+1]; + + +// +//----------------------------------------------------- +// +class CHudDeathNotice : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ); + +private: + int m_HUD_d_skull; // sprite index of skull icon +}; + +// +//----------------------------------------------------- +// +class CHudMenu : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + void Reset( void ); + int Draw( float flTime ); + int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ); + + void SelectMenuItem( int menu_item ); + + int m_fMenuDisplayed; + int m_bitsValidSlots; + float m_flShutoffTime; + int m_fWaitingForMore; +}; + +// +//----------------------------------------------------- +// +class CHudSayText : public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); + void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); + void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); +friend class CHudSpectator; + +private: + + struct cvar_s * m_HUD_saytext; + struct cvar_s * m_HUD_saytext_time; +}; + +// +//----------------------------------------------------- +// +class CHudBattery: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + wrect_t *m_prc1; + wrect_t *m_prc2; + int m_iBat; + float m_fFade; + int m_iHeight; // width of the battery innards +}; + + +// +//----------------------------------------------------- +// +class CHudFlashlight: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + void Reset( void ); + int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); + +private: + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + HSPRITE m_hBeam; + wrect_t *m_prc1; + wrect_t *m_prc2; + wrect_t *m_prcBeam; + float m_flBat; + int m_iBat; + int m_fOn; + float m_fFade; + int m_iWidth; // width of the battery innards +}; + +// +//----------------------------------------------------- +// +const int maxHUDMessages = 16; +struct message_parms_t +{ + client_textmessage_t *pMessage; + float time; + int x, y; + int totalWidth, totalHeight; + int width; + int lines; + int lineLength; + int length; + int r, g, b; + int text; + int fadeBlend; + float charTime; + float fadeTime; +}; + +// +//----------------------------------------------------- +// + +class CHudTextMessage: public CHudBase +{ +public: + int Init( void ); + static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); + static char *BufferedLocaliseTextString( const char *msg ); + char *LookupString( const char *msg_name, int *msg_dest = NULL ); + int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); +}; + +// +//----------------------------------------------------- +// + +class CHudMessage: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + int Draw(float flTime); + int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); + int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); + + float FadeBlend( float fadein, float fadeout, float hold, float localTime ); + int XPosition( float x, int width, int lineWidth ); + int YPosition( float y, int height ); + + void MessageAdd( const char *pName, float time ); + void MessageAdd(client_textmessage_t * newMessage ); + void MessageDrawScan( client_textmessage_t *pMessage, float time ); + void MessageScanStart( void ); + void MessageScanNextChar( void ); + void Reset( void ); + +private: + client_textmessage_t *m_pMessages[maxHUDMessages]; + float m_startTime[maxHUDMessages]; + message_parms_t m_parms; + float m_gameTitleTime; + client_textmessage_t *m_pGameTitle; + + int m_HUD_title_life; + int m_HUD_title_half; +}; + +// +//----------------------------------------------------- +// +#define MAX_SPRITE_NAME_LENGTH 24 + +class CHudStatusIcons: public CHudBase +{ +public: + int Init( void ); + int VidInit( void ); + void Reset( void ); + int Draw(float flTime); + int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf); + + enum { + MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, + MAX_ICONSPRITES = 4, + }; + + + //had to make these public so CHud could access them (to enable concussion icon) + //could use a friend declaration instead... + void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); + void DisableIcon( char *pszIconName ); + +private: + + typedef struct + { + char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; + HSPRITE spr; + wrect_t rc; + unsigned char r, g, b; + } icon_sprite_t; + + icon_sprite_t m_IconList[MAX_ICONSPRITES]; + +}; + +// +//----------------------------------------------------- +// + + + +class CHud +{ +private: + HUDLIST *m_pHudList; + HSPRITE m_hsprLogo; + int m_iLogo; + client_sprite_t *m_pSpriteList; + int m_iSpriteCount; + int m_iSpriteCountAllRes; + float m_flMouseSensitivity; + int m_iConcussionEffect; + +public: + + HSPRITE m_hsprCursor; + float m_flTime; // the current client time + float m_fOldTime; // the time at which the HUD was last redrawn + double m_flTimeDelta; // the difference between flTime and fOldTime + Vector m_vecOrigin; + Vector m_vecAngles; + int m_iKeyBits; + int m_iHideHUDDisplay; + int m_iFOV; + int m_Teamplay; + int m_iRes; + cvar_t *m_pCvarStealMouse; + cvar_t *m_pCvarDraw; + + int m_iFontHeight; + int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); + int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b ); + int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); + int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); + int GetNumWidth(int iNumber, int iFlags); + int DrawHudStringLen( char *szIt ); + void DrawDarkRectangle( int x, int y, int wide, int tall); + +private: + // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. + // freed in ~CHud() + HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt + wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ + char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ + + struct cvar_s *default_fov; +public: + HSPRITE GetSprite( int index ) + { + return (index < 0) ? 0 : m_rghSprites[index]; + } + + wrect_t& GetSpriteRect( int index ) + { + return m_rgrcRects[index]; + } + + + int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array + + CHudAmmo m_Ammo; + CHudHealth m_Health; + CHudSpectator m_Spectator; + CHudGeiger m_Geiger; + CHudBattery m_Battery; + CHudTrain m_Train; + CHudFlashlight m_Flash; + CHudMessage m_Message; + CHudStatusBar m_StatusBar; + CHudDeathNotice m_DeathNotice; + CHudSayText m_SayText; + CHudMenu m_Menu; + CHudAmmoSecondary m_AmmoSecondary; + CHudTextMessage m_TextMessage; + CHudStatusIcons m_StatusIcons; + CHudScoreboard m_Scoreboard; + CHudMOTD m_MOTD; + + + void Init( void ); + void VidInit( void ); + void Think(void); + int Redraw( float flTime, int intermission ); + int UpdateClientData( client_data_t *cdata, float time ); + + CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} + ~CHud(); // destructor, frees allocated memory + + // user messages + int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); + void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); + void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); + + // Screen information + SCREENINFO m_scrinfo; + + int m_iWeaponBits; + int m_fPlayerDead; + int m_iIntermission; + + // sprite indexes + int m_HUD_number_0; + + int m_iNoConsolePrint; + + void AddHudElem(CHudBase *p); + + float GetSensitivity(); + +}; + + +extern CHud gHUD; + +extern int g_iPlayerClass; +extern int g_iTeamNumber; +extern int g_iUser1; +extern int g_iUser2; +extern int g_iUser3; + diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h index 3f6dd599..9b7e189a 100644 --- a/cl_dll/hud_iface.h +++ b/cl_dll/hud_iface.h @@ -1,19 +1,19 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( HUD_IFACEH ) -#define HUD_IFACEH -#pragma once - -#include "exportdef.h" - -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); -#include "wrect.h" -#include "../engine/cdll_int.h" -extern cl_enginefunc_t gEngfuncs; - -#endif +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_IFACEH ) +#define HUD_IFACEH +#pragma once + +#include "exportdef.h" + +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +#include "wrect.h" +#include "../engine/cdll_int.h" +extern cl_enginefunc_t gEngfuncs; + +#endif diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index 0505d172..4051b401 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -1,120 +1,120 @@ -/*** -* -* 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. -* -****/ -// -// hud_msg.cpp -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" -#include "r_efx.h" - -#define MAX_CLIENTS 32 - -extern BEAM *pBeam; -extern BEAM *pBeam2; - -/// USER-DEFINED SERVER MESSAGE HANDLERS - -int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) -{ - ASSERT( iSize == 0 ); - - // clear all hud data - HUDLIST *pList = m_pHudList; - - while ( pList ) - { - if ( pList->p ) - pList->p->Reset(); - pList = pList->pNext; - } - - // reset sensitivity - m_flMouseSensitivity = 0; - - // reset concussion effect - m_iConcussionEffect = 0; - - return 1; -} - -void CAM_ToFirstPerson(void); - -void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) -{ - CAM_ToFirstPerson(); -} - -void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) -{ - // prepare all hud data - HUDLIST *pList = m_pHudList; - - while (pList) - { - if ( pList->p ) - pList->p->InitHUDData(); - pList = pList->pNext; - } - - //Probably not a good place to put this. - pBeam = pBeam2 = NULL; -} - - -int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - m_Teamplay = READ_BYTE(); - - return 1; -} - - -int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) -{ - int armor, blood; - Vector from; - int i; - float count; - - BEGIN_READ( pbuf, iSize ); - armor = READ_BYTE(); - blood = READ_BYTE(); - - for (i=0 ; i<3 ; i++) - from[i] = READ_COORD(); - - count = (blood * 0.5) + (armor * 0.5); - - if (count < 10) - count = 10; - - // TODO: kick viewangles, show damage visually - - return 1; -} - -int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - m_iConcussionEffect = READ_BYTE(); - if (m_iConcussionEffect) - this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0); - else - this->m_StatusIcons.DisableIcon("dmg_concuss"); - return 1; -} +/*** +* +* 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. +* +****/ +// +// hud_msg.cpp +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "r_efx.h" + +#define MAX_CLIENTS 32 + +extern BEAM *pBeam; +extern BEAM *pBeam2; + +/// USER-DEFINED SERVER MESSAGE HANDLERS + +int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) +{ + ASSERT( iSize == 0 ); + + // clear all hud data + HUDLIST *pList = m_pHudList; + + while ( pList ) + { + if ( pList->p ) + pList->p->Reset(); + pList = pList->pNext; + } + + // reset sensitivity + m_flMouseSensitivity = 0; + + // reset concussion effect + m_iConcussionEffect = 0; + + return 1; +} + +void CAM_ToFirstPerson(void); + +void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) +{ + CAM_ToFirstPerson(); +} + +void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) +{ + // prepare all hud data + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( pList->p ) + pList->p->InitHUDData(); + pList = pList->pNext; + } + + //Probably not a good place to put this. + pBeam = pBeam2 = NULL; +} + + +int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_Teamplay = READ_BYTE(); + + return 1; +} + + +int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + int armor, blood; + Vector from; + int i; + float count; + + BEGIN_READ( pbuf, iSize ); + armor = READ_BYTE(); + blood = READ_BYTE(); + + for (i=0 ; i<3 ; i++) + from[i] = READ_COORD(); + + count = (blood * 0.5) + (armor * 0.5); + + if (count < 10) + count = 10; + + // TODO: kick viewangles, show damage visually + + return 1; +} + +int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_iConcussionEffect = READ_BYTE(); + if (m_iConcussionEffect) + this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0); + else + this->m_StatusIcons.DisableIcon("dmg_concuss"); + return 1; +} diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index f58ffd39..bacd4026 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -1,365 +1,365 @@ -/*** -* -* 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. -* -****/ -// -// hud_redraw.cpp -// -#include -#include "hud.h" -#include "cl_util.h" -//#include "triangleapi.h" - - -#define MAX_LOGO_FRAMES 56 - -int grgLogoFrame[MAX_LOGO_FRAMES] = -{ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, - 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 -}; - - -extern int g_iVisibleMouse; - -float HUD_GetFOV( void ); - -extern cvar_t *sensitivity; - -// Think -void CHud::Think(void) -{ - int newfov; - HUDLIST *pList = m_pHudList; - - while (pList) - { - if (pList->p->m_iFlags & HUD_ACTIVE) - pList->p->Think(); - pList = pList->pNext; - } - - newfov = HUD_GetFOV(); - if ( newfov == 0 ) - { - m_iFOV = default_fov->value; - } - else - { - m_iFOV = newfov; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == default_fov->value ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); - } - - // think about default fov - if ( m_iFOV == 0 ) - { // only let players adjust up in fov, and only if they are not overriden by something else - m_iFOV = max( default_fov->value, 90 ); - } -} - -// Redraw -// step through the local data, placing the appropriate graphics & text as appropriate -// returns 1 if they've changed, 0 otherwise -int CHud :: Redraw( float flTime, int intermission ) -{ - m_fOldTime = m_flTime; // save time of previous redraw - m_flTime = flTime; - m_flTimeDelta = (double)m_flTime - m_fOldTime; - static float m_flShotTime = 0; - - // Clock was reset, reset delta - if ( m_flTimeDelta < 0 ) - m_flTimeDelta = 0; - - - if (m_flShotTime && m_flShotTime < flTime) - { - gEngfuncs.pfnClientCmd("snapshot\n"); - m_flShotTime = 0; - } - - m_iIntermission = intermission; - - // if no redrawing is necessary - // return 0; - - if ( m_pCvarDraw->value ) - { - HUDLIST *pList = m_pHudList; - - while (pList) - { - if ( !intermission ) - { - if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) - pList->p->Draw(flTime); - } - else - { // it's an intermission, so only draw hud elements that are set to draw during intermissions - if ( pList->p->m_iFlags & HUD_INTERMISSION ) - pList->p->Draw( flTime ); - } - - pList = pList->pNext; - } - } - - // are we in demo mode? do we need to draw the logo in the top corner? - if (m_iLogo) - { - int x, y, i; - - if (m_hsprLogo == 0) - m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); - - SPR_Set(m_hsprLogo, 250, 250, 250 ); - - x = SPR_Width(m_hsprLogo, 0); - x = ScreenWidth - x; - y = SPR_Height(m_hsprLogo, 0)/2; - - // Draw the logo at 20 fps - int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; - i = grgLogoFrame[iFrame] - 1; - - SPR_DrawAdditive(i, x, y, NULL); - } - - /* - if ( g_iVisibleMouse ) - { - void IN_GetMousePos( int *mx, int *my ); - int mx, my; - - IN_GetMousePos( &mx, &my ); - - if (m_hsprCursor == 0) - { - char sz[256]; - sprintf( sz, "sprites/cursor.spr" ); - m_hsprCursor = SPR_Load( sz ); - } - - SPR_Set(m_hsprCursor, 250, 250, 250 ); - - // Draw the logo at 20 fps - SPR_DrawAdditive( 0, mx, my, NULL ); - } - */ - - return 1; -} - -void ScaleColors( int &r, int &g, int &b, int a ) -{ - float x = (float)a / 255; - r = (int)(r * x); - g = (int)(g * x); - b = (int)(b * x); -} - -const unsigned char colors[8][3] = -{ -{127, 127, 127}, // additive cannot be black -{255, 0, 0}, -{ 0, 255, 0}, -{255, 255, 0}, -{ 0, 0, 255}, -{ 0, 255, 255}, -{255, 0, 255}, -{240, 180, 24} -}; - -int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) -{ - if( hud_textmode->value == 2 ) - { - gEngfuncs.pfnDrawSetTextColor( r/255.0, g/255.0, b/255.0 ); - return gEngfuncs.pfnDrawConsoleString( xpos, ypos, (char*) szIt ); - } - - // xash3d: reset unicode state - TextMessageDrawChar( 0, 0, 0, 0, 0, 0 ); - - // draw the string until we hit the null character or a newline character - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) - { - int w = gHUD.m_scrinfo.charWidths[ 'M' ]; - if ( xpos + w > iMaxX ) - return xpos; - if( (*szIt == '^') && (*(szIt + 1) >= '0') && (*(szIt + 1) <= '7') ) - { - szIt++; - r = colors[ *szIt - '0' ][0]; - g = colors[ *szIt - '0' ][1]; - b = colors[ *szIt - '0' ][2]; - if( !*(++szIt)) - return xpos; - } - int c = (unsigned int)(unsigned char)*szIt; - - xpos += TextMessageDrawChar( xpos, ypos, c, r, g, b ); - } - - return xpos; -} - -int CHud :: DrawHudStringLen( char *szIt ) -{ - int l = 0; - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) - { - l += gHUD.m_scrinfo.charWidths[ (unsigned char)*szIt ]; - } - return l; -} - - -int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) -{ - char szString[32]; - sprintf( szString, "%d", iNumber ); - return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); - -} - -// draws a string from right to left (right-aligned) -int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) -{ - // find the end of the string - for( char *szIt = szString; *szIt != 0; szIt++ ) - xpos -= gHUD.m_scrinfo.charWidths[ (unsigned char) *szIt ]; - if( xpos < iMinX ) - xpos = iMinX; - DrawHudString( xpos, ypos, gHUD.m_scrinfo.iWidth, szString, r, g, b ); - return xpos; -} - -int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) -{ - int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; - int k; - - if (iNumber > 0) - { - // SPR_Draw 100's - if (iNumber >= 100) - { - k = iNumber/100; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & (DHN_3DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw 10's - if (iNumber >= 10) - { - k = (iNumber % 100)/10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw ones - k = iNumber % 10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if (iFlags & DHN_DRAWZERO) - { - SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); - - // SPR_Draw 100's - if (iFlags & (DHN_3DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) - { - //SPR_DrawAdditive( 0, x, y, &rc ); - x += iWidth; - } - - // SPR_Draw ones - - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); - x += iWidth; - } - - return x; -} - - -int CHud::GetNumWidth( int iNumber, int iFlags ) -{ - if (iFlags & (DHN_3DIGITS)) - return 3; - - if (iFlags & (DHN_2DIGITS)) - return 2; - - if (iNumber <= 0) - { - if (iFlags & (DHN_DRAWZERO)) - return 1; - else - return 0; - } - - if (iNumber < 10) - return 1; - - if (iNumber < 100) - return 2; - - return 3; - -} - - -void CHud::DrawDarkRectangle( int x, int y, int wide, int tall ) -{ - //gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pfnFillRGBABlend( x, y, wide, tall, 0, 0, 0, 255 * 0.6 ); - FillRGBA( x+1, y, wide-1, 1, 255, 140, 0, 255 ); - FillRGBA( x, y, 1, tall-1, 255, 140, 0, 255 ); - FillRGBA( x+wide-1, y+1, 1, tall-1, 255, 140, 0, 255 ); - FillRGBA( x, y+tall-1, wide-1, 1, 255, 140, 0, 255 ); -} +/*** +* +* 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. +* +****/ +// +// hud_redraw.cpp +// +#include +#include "hud.h" +#include "cl_util.h" +//#include "triangleapi.h" + + +#define MAX_LOGO_FRAMES 56 + +int grgLogoFrame[MAX_LOGO_FRAMES] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, + 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 +}; + + +extern int g_iVisibleMouse; + +float HUD_GetFOV( void ); + +extern cvar_t *sensitivity; + +// Think +void CHud::Think(void) +{ + int newfov; + HUDLIST *pList = m_pHudList; + + while (pList) + { + if (pList->p->m_iFlags & HUD_ACTIVE) + pList->p->Think(); + pList = pList->pNext; + } + + newfov = HUD_GetFOV(); + if ( newfov == 0 ) + { + m_iFOV = default_fov->value; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == default_fov->value ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + // think about default fov + if ( m_iFOV == 0 ) + { // only let players adjust up in fov, and only if they are not overriden by something else + m_iFOV = max( default_fov->value, 90 ); + } +} + +// Redraw +// step through the local data, placing the appropriate graphics & text as appropriate +// returns 1 if they've changed, 0 otherwise +int CHud :: Redraw( float flTime, int intermission ) +{ + m_fOldTime = m_flTime; // save time of previous redraw + m_flTime = flTime; + m_flTimeDelta = (double)m_flTime - m_fOldTime; + static float m_flShotTime = 0; + + // Clock was reset, reset delta + if ( m_flTimeDelta < 0 ) + m_flTimeDelta = 0; + + + if (m_flShotTime && m_flShotTime < flTime) + { + gEngfuncs.pfnClientCmd("snapshot\n"); + m_flShotTime = 0; + } + + m_iIntermission = intermission; + + // if no redrawing is necessary + // return 0; + + if ( m_pCvarDraw->value ) + { + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( !intermission ) + { + if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) + pList->p->Draw(flTime); + } + else + { // it's an intermission, so only draw hud elements that are set to draw during intermissions + if ( pList->p->m_iFlags & HUD_INTERMISSION ) + pList->p->Draw( flTime ); + } + + pList = pList->pNext; + } + } + + // are we in demo mode? do we need to draw the logo in the top corner? + if (m_iLogo) + { + int x, y, i; + + if (m_hsprLogo == 0) + m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + + SPR_Set(m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width(m_hsprLogo, 0); + x = ScreenWidth - x; + y = SPR_Height(m_hsprLogo, 0)/2; + + // Draw the logo at 20 fps + int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + i = grgLogoFrame[iFrame] - 1; + + SPR_DrawAdditive(i, x, y, NULL); + } + + /* + if ( g_iVisibleMouse ) + { + void IN_GetMousePos( int *mx, int *my ); + int mx, my; + + IN_GetMousePos( &mx, &my ); + + if (m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + m_hsprCursor = SPR_Load( sz ); + } + + SPR_Set(m_hsprCursor, 250, 250, 250 ); + + // Draw the logo at 20 fps + SPR_DrawAdditive( 0, mx, my, NULL ); + } + */ + + return 1; +} + +void ScaleColors( int &r, int &g, int &b, int a ) +{ + float x = (float)a / 255; + r = (int)(r * x); + g = (int)(g * x); + b = (int)(b * x); +} + +const unsigned char colors[8][3] = +{ +{127, 127, 127}, // additive cannot be black +{255, 0, 0}, +{ 0, 255, 0}, +{255, 255, 0}, +{ 0, 0, 255}, +{ 0, 255, 255}, +{255, 0, 255}, +{240, 180, 24} +}; + +int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +{ + if( hud_textmode->value == 2 ) + { + gEngfuncs.pfnDrawSetTextColor( r/255.0, g/255.0, b/255.0 ); + return gEngfuncs.pfnDrawConsoleString( xpos, ypos, (char*) szIt ); + } + + // xash3d: reset unicode state + TextMessageDrawChar( 0, 0, 0, 0, 0, 0 ); + + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int w = gHUD.m_scrinfo.charWidths[ 'M' ]; + if ( xpos + w > iMaxX ) + return xpos; + if( (*szIt == '^') && (*(szIt + 1) >= '0') && (*(szIt + 1) <= '7') ) + { + szIt++; + r = colors[ *szIt - '0' ][0]; + g = colors[ *szIt - '0' ][1]; + b = colors[ *szIt - '0' ][2]; + if( !*(++szIt)) + return xpos; + } + int c = (unsigned int)(unsigned char)*szIt; + + xpos += TextMessageDrawChar( xpos, ypos, c, r, g, b ); + } + + return xpos; +} + +int CHud :: DrawHudStringLen( char *szIt ) +{ + int l = 0; + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + l += gHUD.m_scrinfo.charWidths[ (unsigned char)*szIt ]; + } + return l; +} + + +int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) +{ + char szString[32]; + sprintf( szString, "%d", iNumber ); + return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); + +} + +// draws a string from right to left (right-aligned) +int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +{ + // find the end of the string + for( char *szIt = szString; *szIt != 0; szIt++ ) + xpos -= gHUD.m_scrinfo.charWidths[ (unsigned char) *szIt ]; + if( xpos < iMinX ) + xpos = iMinX; + DrawHudString( xpos, ypos, gHUD.m_scrinfo.iWidth, szString, r, g, b ); + return xpos; +} + +int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) +{ + int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; + int k; + + if (iNumber > 0) + { + // SPR_Draw 100's + if (iNumber >= 100) + { + k = iNumber/100; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw 10's + if (iNumber >= 10) + { + k = (iNumber % 100)/10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + k = iNumber % 10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & DHN_DRAWZERO) + { + SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); + + // SPR_Draw 100's + if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); + x += iWidth; + } + + return x; +} + + +int CHud::GetNumWidth( int iNumber, int iFlags ) +{ + if (iFlags & (DHN_3DIGITS)) + return 3; + + if (iFlags & (DHN_2DIGITS)) + return 2; + + if (iNumber <= 0) + { + if (iFlags & (DHN_DRAWZERO)) + return 1; + else + return 0; + } + + if (iNumber < 10) + return 1; + + if (iNumber < 100) + return 2; + + return 3; + +} + + +void CHud::DrawDarkRectangle( int x, int y, int wide, int tall ) +{ + //gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pfnFillRGBABlend( x, y, wide, tall, 0, 0, 0, 255 * 0.6 ); + FillRGBA( x+1, y, wide-1, 1, 255, 140, 0, 255 ); + FillRGBA( x, y, 1, tall-1, 255, 140, 0, 255 ); + FillRGBA( x+wide-1, y+1, 1, tall-1, 255, 140, 0, 255 ); + FillRGBA( x, y+tall-1, wide-1, 1, 255, 140, 0, 255 ); +} diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp index 8bd42d33..7a5a1475 100644 --- a/cl_dll/hud_servers.cpp +++ b/cl_dll/hud_servers.cpp @@ -1,1230 +1,1230 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// hud_servers.cpp -#include "hud.h" -#include "cl_util.h" -#include "hud_servers_priv.h" -#include "hud_servers.h" -#include "net_api.h" -#include -#include - -static int context_id; - -// Default master server address in case we can't read any from woncomm.lst file -#define VALVE_MASTER_ADDRESS "half-life.east.won.net" -#define PORT_MASTER 27010 -#define PORT_SERVER 27015 - -// File where we really should look for master servers -#define MASTER_PARSE_FILE "woncomm.lst" - -#define MAX_QUERIES 20 - -#define NET_API gEngfuncs.pNetAPI - -static CHudServers *g_pServers = NULL; - -/* -=================== -ListResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK ListResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->ListResponse( response ); - } -} - -/* -=================== -ServerResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK ServerResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->ServerResponse( response ); - } -} - -/* -=================== -PingResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK PingResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->PingResponse( response ); - } -} - -/* -=================== -RulesResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK RulesResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->RulesResponse( response ); - } -} -/* -=================== -PlayersResponse - -Callback from engine -=================== -*/ -void NET_CALLBACK PlayersResponse( struct net_response_s *response ) -{ - if ( g_pServers ) - { - g_pServers->PlayersResponse( response ); - } -} -/* -=================== -ListResponse - -=================== -*/ -void CHudServers::ListResponse( struct net_response_s *response ) -{ - request_t *list; - request_t *p; - int c = 0; - - if ( !( response->error == NET_SUCCESS ) ) - return; - - if ( response->type != NETAPI_REQUEST_SERVERLIST ) - return; - - if ( response->response ) - { - list = ( request_t * ) response->response; - while ( list ) - { - c++; - - //if ( c < 40 ) - { - // Copy from parsed stuff - p = new request_t; - p->context = -1; - p->remote_address = list->remote_address; - p->next = m_pServerList; - m_pServerList = p; - } - - // Move on - list = list->next; - } - } - - gEngfuncs.Con_Printf( "got list\n" ); - - m_nQuerying = 1; - m_nActiveQueries = 0; -} - -/* -=================== -ServerResponse - -=================== -*/ -void CHudServers::ServerResponse( struct net_response_s *response ) -{ - char *szresponse; - request_t *p; - server_t *browser; - int len; - char sz[ 32 ]; - - // Remove from active list - p = FindRequest( response->context, m_pActiveList ); - if ( p ) - { - RemoveServerFromList( &m_pActiveList, p ); - m_nActiveQueries--; - } - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_DETAILS: - if ( response->response ) - { - szresponse = (char *)response->response; - len = strlen( szresponse ) + 100 + 1; - sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); - - browser = new server_t; - browser->remote_address = response->remote_address; - browser->info = new char[ len ]; - browser->ping = (int)( 1000.0 * response->ping ); - strcpy( browser->info, szresponse ); - - NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); - NET_API->SetValueForKey( browser->info, "ping", sz, len ); - - AddServer( &m_pServers, browser ); - } - break; - default: - break; - } -} - -/* -=================== -PingResponse - -=================== -*/ -void CHudServers::PingResponse( struct net_response_s *response ) -{ - char sz[ 32 ]; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_PING: - sprintf( sz, "%.2f", 1000.0 * response->ping ); - - gEngfuncs.Con_Printf( "ping == %s\n", sz ); - break; - default: - break; - } -} - -/* -=================== -RulesResponse - -=================== -*/ -void CHudServers::RulesResponse( struct net_response_s *response ) -{ - char *szresponse; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_RULES: - if ( response->response ) - { - szresponse = (char *)response->response; - - gEngfuncs.Con_Printf( "rules %s\n", szresponse ); - } - break; - default: - break; - } -} - -/* -=================== -PlayersResponse - -=================== -*/ -void CHudServers::PlayersResponse( struct net_response_s *response ) -{ - char *szresponse; - - if ( response->error != NET_SUCCESS ) - return; - - switch ( response->type ) - { - case NETAPI_REQUEST_PLAYERS: - if ( response->response ) - { - szresponse = (char *)response->response; - - gEngfuncs.Con_Printf( "players %s\n", szresponse ); - } - break; - default: - break; - } -} - -/* -=================== -CompareServers - -Return 1 if p1 is "less than" p2, 0 otherwise -=================== -*/ -int CHudServers::CompareServers( server_t *p1, server_t *p2 ) -{ - const char *n1, *n2; - - if ( p1->ping < p2->ping ) - return 1; - - if ( p1->ping == p2->ping ) - { - // Pings equal, sort by second key: hostname - if ( p1->info && p2->info ) - { - n1 = NET_API->ValueForKey( p1->info, "hostname" ); - n2 = NET_API->ValueForKey( p2->info, "hostname" ); - - if ( n1 && n2 ) - { - if ( stricmp( n1, n2 ) < 0 ) - return 1; - } - } - } - - return 0; -} - -/* -=================== -AddServer - -=================== -*/ -void CHudServers::AddServer( server_t **ppList, server_t *p ) -{ -server_t *list; - - if ( !ppList || ! p ) - return; - - m_nServerCount++; - - // What sort key? Ping? - list = *ppList; - - // Head of list? - if ( !list ) - { - p->next = NULL; - *ppList = p; - return; - } - - // Put on head of list - if ( CompareServers( p, list ) ) - { - p->next = *ppList; - *ppList = p; - } - else - { - while ( list->next ) - { - // Insert before list next - if ( CompareServers( p, list->next ) ) - { - p->next = list->next->next; - list->next = p; - return; - } - - list = list->next; - } - - // Just add at end - p->next = NULL; - list->next = p; - } -} - -/* -=================== -Think - -=================== -*/ -void CHudServers::Think( double time ) -{ - m_fElapsed += time; - - if ( !m_nRequesting ) - return; - - if ( !m_nQuerying ) - return; - - QueryThink(); - - if ( ServerListSize() > 0 ) - return; - - m_dStarted = 0.0; - m_nRequesting = 0; - m_nDone = 0; - m_nQuerying = 0; - m_nActiveQueries = 0; -} - -/* -=================== -QueryThink - -=================== -*/ -void CHudServers::QueryThink( void ) -{ - request_t *p; - - if ( !m_nRequesting || m_nDone ) - return; - - if ( !m_nQuerying ) - return; - - if ( m_nActiveQueries > MAX_QUERIES ) - return; - - // Nothing left - if ( !m_pServerList ) - return; - - while ( 1 ) - { - p = m_pServerList; - - // No more in list? - if ( !p ) - break; - - // Move to next - m_pServerList = m_pServerList->next; - - // Setup context_id - p->context = context_id; - - // Start up query on this one - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); - - // Increment active list - m_nActiveQueries++; - - // Add to active list - p->next = m_pActiveList; - m_pActiveList = p; - - // Too many active? - if ( m_nActiveQueries > MAX_QUERIES ) - break; - } -} - -/* -================== -ServerListSize - -# of servers in active query and in pending to be queried lists -================== -*/ -int CHudServers::ServerListSize( void ) -{ - int c = 0; - request_t *p; - - p = m_pServerList; - while ( p ) - { - c++; - p = p->next; - } - - p = m_pActiveList; - while ( p ) - { - c++; - p = p->next; - } - - return c; -} - -/* -=================== -FindRequest - -Look up a request by context id -=================== -*/ -CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) -{ - request_t *p; - p = pList; - while ( p ) - { - if ( context == p->context ) - return p; - - p = p->next; - } - return NULL; -} - -/* -=================== -RemoveServerFromList - -Remote, but don't delete, item from *ppList -=================== -*/ -void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) -{ - request_t *p, *n; - request_t *newlist = NULL; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - if ( p != item ) - { - p->next = newlist; - newlist = p; - } - p = n; - } - *ppList = newlist; -} - -/* -=================== -ClearRequestList - -=================== -*/ -void CHudServers::ClearRequestList( request_t **ppList ) -{ - request_t *p, *n; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - delete p; - p = n; - } - *ppList = NULL; -} - -/* -=================== -ClearServerList - -=================== -*/ -void CHudServers::ClearServerList( server_t **ppList ) -{ - server_t *p, *n; - - if ( !ppList ) - return; - - p = *ppList; - while ( p ) - { - n = p->next; - delete[] p->info; - delete p; - p = n; - } - *ppList = NULL; -} - -int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) -{ - const char *sz1, *sz2; - float fv1, fv2; - - sz1 = NET_API->ValueForKey( p1->info, fieldname ); - sz2 = NET_API->ValueForKey( p2->info, fieldname ); - - fv1 = atof( sz1 ); - fv2 = atof( sz2 ); - - if ( fv1 && fv2 ) - { - if ( fv1 > fv2 ) - return iSortOrder; - else if ( fv1 < fv2 ) - return -iSortOrder; - else - return 0; - } - - // String compare - return stricmp( sz1, sz2 ); -} - -int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) -{ - if (!p1 || !p2) // No meaningful comparison - return 0; - - int iSortOrder = 1; - - int retval = 0; - - retval = CompareField( p1, p2, fieldname, iSortOrder ); - - return retval; -} - -static char g_fieldname[ 256 ]; -int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) -{ - CHudServers::server_t *list1, *list2; - - list1 = *(CHudServers::server_t **)elem1; - list2 = *(CHudServers::server_t **)elem2; - - return ServerListCompareFunc( list1, list2, g_fieldname ); -} - -void CHudServers::SortServers( const char *fieldname ) -{ - server_t *p; - // Create a list - if ( !m_pServers ) - return; - - strcpy( g_fieldname, fieldname ); - - int i; - int c = 0; - - p = m_pServers; - while ( p ) - { - c++; - p = p->next; - } - - server_t **pSortArray; - - pSortArray = new server_t *[ c ]; - memset( pSortArray, 0, c * sizeof( server_t * ) ); - - // Now copy the list into the pSortArray: - p = m_pServers; - i = 0; - while ( p ) - { - pSortArray[ i++ ] = p; - p = p->next; - } - - // Now do that actual sorting. - size_t nCount = c; - size_t nSize = sizeof( server_t * ); - - qsort( - pSortArray, - (size_t)nCount, - (size_t)nSize, - FnServerCompare - ); - - // Now rebuild the list. - m_pServers = pSortArray[0]; - for ( i = 0; i < c - 1; i++ ) - { - pSortArray[ i ]->next = pSortArray[ i + 1 ]; - } - pSortArray[ c - 1 ]->next = NULL; - - // Clean Up. - delete[] pSortArray; -} - -/* -=================== -GetServer - -Return particular server -=================== -*/ -CHudServers::server_t *CHudServers::GetServer( int server ) -{ - int c = 0; - server_t *p; - - p = m_pServers; - while ( p ) - { - if ( c == server ) - return p; - - c++; - p = p->next; - } - return NULL; -} - -/* -=================== -GetServerInfo - -Return info ( key/value ) string for particular server -=================== -*/ -char *CHudServers::GetServerInfo( int server ) -{ - server_t *p = GetServer( server ); - if ( p ) - { - return p->info; - } - return NULL; -} - -/* -=================== -CancelRequest - -Kill all pending requests in engine -=================== -*/ -void CHudServers::CancelRequest( void ) -{ - m_nRequesting = 0; - m_nQuerying = 0; - m_nDone = 1; - - NET_API->CancelAllRequests(); -} - -/* -================== -LoadMasterAddresses - -Loads the master server addresses from file and into the passed in array -================== -*/ -int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) -{ - int i; - char szMaster[ 256 ]; - char szMasterFile[256]; - char *pbuffer = NULL; - char *pstart = NULL ; - netadr_t adr; - char szAdr[64]; - int nPort; - int nCount = 0; - bool bIgnore; - int nDefaultPort; - - // Assume default master and master file - strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string - strcpy( szMasterFile, MASTER_PARSE_FILE ); - - // See if there is a command line override - i = gEngfuncs.CheckParm( "-comm", &pstart ); - if ( i && pstart ) - { - strcpy (szMasterFile, pstart ); - } - - // Read them in from proper file - pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc - if ( !pbuffer ) - { - goto finish_master; - } - - pstart = pbuffer; - - while ( nCount < maxservers ) - { - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if ( strlen(m_szToken) <= 0) - break; - - bIgnore = true; - - if ( !stricmp( m_szToken, "Master" ) ) - { - nDefaultPort = PORT_MASTER; - bIgnore = FALSE; - } - - // Now parse all addresses between { } - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if ( strlen(m_szToken) <= 0 ) - break; - - if ( stricmp ( m_szToken, "{" ) ) - break; - - // Parse addresses until we get to "}" - while ( nCount < maxservers ) - { - char base[256]; - - // Now parse all addresses between { } - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - if ( !stricmp ( m_szToken, "}" ) ) - break; - - sprintf( base, "%s", m_szToken ); - - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - if ( stricmp( m_szToken, ":" ) ) - break; - - pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) - break; - - nPort = atoi ( m_szToken ); - if ( !nPort ) - nPort = nDefaultPort; - - sprintf( szAdr, "%s:%i", base, nPort ); - - // Can we resolve it any better - if ( !NET_API->StringToAdr( szAdr, &adr ) ) - bIgnore = true; - - if ( !bIgnore ) - { - padr[ nCount++ ] = adr; - } - } - } - -finish_master: - if ( !nCount ) - { - sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string - - // Convert to netadr_t - if ( NET_API->StringToAdr ( szMaster, &adr ) ) - { - - padr[ nCount++ ] = adr; - } - } - - *count = nCount; - - if ( pbuffer ) - { - gEngfuncs.COM_FreeFile( pbuffer ); - } - - return ( nCount > 0 ) ? 1 : 0; -} - -/* -=================== -RequestList - -Request list of game servers from master -=================== -*/ -void CHudServers::RequestList( void ) -{ - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; - - int count = 0; - netadr_t adr; - - if ( !LoadMasterAddresses( 1, &count, &adr ) ) - { - gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); - return; - } - - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Kill off left overs if any - NET_API->CancelAllRequests(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); -} - -void CHudServers::RequestBroadcastList( int clearpending ) -{ - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; - - netadr_t adr; - memset( &adr, 0, sizeof( adr ) ); - - if ( clearpending ) - { - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - } - - // Make sure to byte swap server if necessary ( using "host" to "net" conversion - adr.port = htons( PORT_SERVER ); - - // Make sure networking system has started. - NET_API->InitNetworking(); - - if ( clearpending ) - { - // Kill off left overs if any - NET_API->CancelAllRequests(); - } - - adr.type = NA_BROADCAST; - - // Request Servers from LAN via IP - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); - - adr.type = NA_BROADCAST_IPX; - - // Request Servers from LAN via IPX ( if supported ) - NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); -} - -void CHudServers::ServerPing( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); -} - -void CHudServers::ServerRules( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); -} - -void CHudServers::ServerPlayers( int server ) -{ - server_t *p; - - p = GetServer( server ); - if ( !p ) - return; - - // Make sure networking system has started. - NET_API->InitNetworking(); - - // Request Server List from master - NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); -} - -int CHudServers::isQuerying() -{ - return m_nRequesting ? 1 : 0; -} - - -/* -=================== -GetServerCount - -Return number of servers in browser list -=================== -*/ -int CHudServers::GetServerCount( void ) -{ - return m_nServerCount; -} - -/* -=================== -CHudServers - -=================== -*/ -CHudServers::CHudServers( void ) -{ - m_nRequesting = 0; - m_dStarted = 0.0; - m_nDone = 0; - m_pServerList = NULL; - m_pServers = NULL; - m_pActiveList = NULL; - m_nQuerying = 0; - m_nActiveQueries = 0; - - m_fElapsed = 0.0; - - - m_pPingRequest = NULL; - m_pRulesRequest = NULL; - m_pPlayersRequest = NULL; -} - -/* -=================== -~CHudServers - -=================== -*/ -CHudServers::~CHudServers( void ) -{ - ClearRequestList( &m_pActiveList ); - ClearRequestList( &m_pServerList ); - ClearServerList( &m_pServers ); - - m_nServerCount = 0; - - if ( m_pPingRequest ) - { - delete m_pPingRequest; - m_pPingRequest = NULL; - - } - - if ( m_pRulesRequest ) - { - delete m_pRulesRequest; - m_pRulesRequest = NULL; - } - - if ( m_pPlayersRequest ) - { - delete m_pPlayersRequest; - m_pPlayersRequest = NULL; - } -} - -/////////////////////////////// -// -// PUBLIC APIs -// -/////////////////////////////// - -/* -=================== -ServersGetCount - -=================== -*/ -int ServersGetCount( void ) -{ - if ( g_pServers ) - { - return g_pServers->GetServerCount(); - } - return 0; -} - -int ServersIsQuerying( void ) -{ - if ( g_pServers ) - { - return g_pServers->isQuerying(); - } - return 0; -} - -/* -=================== -ServersGetInfo - -=================== -*/ -const char *ServersGetInfo( int server ) -{ - if ( g_pServers ) - { - return g_pServers->GetServerInfo( server ); - } - - return NULL; -} - -void SortServers( const char *fieldname ) -{ - if ( g_pServers ) - { - g_pServers->SortServers( fieldname ); - } -} - -/* -=================== -ServersShutdown - -=================== -*/ -void ServersShutdown( void ) -{ - if ( g_pServers ) - { - delete g_pServers; - g_pServers = NULL; - } -} - -/* -=================== -ServersInit - -=================== -*/ -void ServersInit( void ) -{ - // Kill any previous instance - ServersShutdown(); - - g_pServers = new CHudServers(); -} - -/* -=================== -ServersThink - -=================== -*/ -void ServersThink( double time ) -{ - if ( g_pServers ) - { - g_pServers->Think( time ); - } -} - -/* -=================== -ServersCancel - -=================== -*/ -void ServersCancel( void ) -{ - if ( g_pServers ) - { - g_pServers->CancelRequest(); - } -} - -// Requests -/* -=================== -ServersList - -=================== -*/ -void ServersList( void ) -{ - if ( g_pServers ) - { - g_pServers->RequestList(); - } -} - -void BroadcastServersList( int clearpending ) -{ - if ( g_pServers ) - { - g_pServers->RequestBroadcastList( clearpending ); - } -} - -void ServerPing( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerPing( server ); - } -} - -void ServerRules( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerRules( server ); - } -} - -void ServerPlayers( int server ) -{ - if ( g_pServers ) - { - g_pServers->ServerPlayers( server ); - } +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// hud_servers.cpp +#include "hud.h" +#include "cl_util.h" +#include "hud_servers_priv.h" +#include "hud_servers.h" +#include "net_api.h" +#include +#include + +static int context_id; + +// Default master server address in case we can't read any from woncomm.lst file +#define VALVE_MASTER_ADDRESS "half-life.east.won.net" +#define PORT_MASTER 27010 +#define PORT_SERVER 27015 + +// File where we really should look for master servers +#define MASTER_PARSE_FILE "woncomm.lst" + +#define MAX_QUERIES 20 + +#define NET_API gEngfuncs.pNetAPI + +static CHudServers *g_pServers = NULL; + +/* +=================== +ListResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ListResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ListResponse( response ); + } +} + +/* +=================== +ServerResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ServerResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ServerResponse( response ); + } +} + +/* +=================== +PingResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PingResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PingResponse( response ); + } +} + +/* +=================== +RulesResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK RulesResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->RulesResponse( response ); + } +} +/* +=================== +PlayersResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PlayersResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PlayersResponse( response ); + } +} +/* +=================== +ListResponse + +=================== +*/ +void CHudServers::ListResponse( struct net_response_s *response ) +{ + request_t *list; + request_t *p; + int c = 0; + + if ( !( response->error == NET_SUCCESS ) ) + return; + + if ( response->type != NETAPI_REQUEST_SERVERLIST ) + return; + + if ( response->response ) + { + list = ( request_t * ) response->response; + while ( list ) + { + c++; + + //if ( c < 40 ) + { + // Copy from parsed stuff + p = new request_t; + p->context = -1; + p->remote_address = list->remote_address; + p->next = m_pServerList; + m_pServerList = p; + } + + // Move on + list = list->next; + } + } + + gEngfuncs.Con_Printf( "got list\n" ); + + m_nQuerying = 1; + m_nActiveQueries = 0; +} + +/* +=================== +ServerResponse + +=================== +*/ +void CHudServers::ServerResponse( struct net_response_s *response ) +{ + char *szresponse; + request_t *p; + server_t *browser; + int len; + char sz[ 32 ]; + + // Remove from active list + p = FindRequest( response->context, m_pActiveList ); + if ( p ) + { + RemoveServerFromList( &m_pActiveList, p ); + m_nActiveQueries--; + } + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_DETAILS: + if ( response->response ) + { + szresponse = (char *)response->response; + len = strlen( szresponse ) + 100 + 1; + sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); + + browser = new server_t; + browser->remote_address = response->remote_address; + browser->info = new char[ len ]; + browser->ping = (int)( 1000.0 * response->ping ); + strcpy( browser->info, szresponse ); + + NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); + NET_API->SetValueForKey( browser->info, "ping", sz, len ); + + AddServer( &m_pServers, browser ); + } + break; + default: + break; + } +} + +/* +=================== +PingResponse + +=================== +*/ +void CHudServers::PingResponse( struct net_response_s *response ) +{ + char sz[ 32 ]; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PING: + sprintf( sz, "%.2f", 1000.0 * response->ping ); + + gEngfuncs.Con_Printf( "ping == %s\n", sz ); + break; + default: + break; + } +} + +/* +=================== +RulesResponse + +=================== +*/ +void CHudServers::RulesResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_RULES: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "rules %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +PlayersResponse + +=================== +*/ +void CHudServers::PlayersResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PLAYERS: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "players %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +CompareServers + +Return 1 if p1 is "less than" p2, 0 otherwise +=================== +*/ +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +{ + const char *n1, *n2; + + if ( p1->ping < p2->ping ) + return 1; + + if ( p1->ping == p2->ping ) + { + // Pings equal, sort by second key: hostname + if ( p1->info && p2->info ) + { + n1 = NET_API->ValueForKey( p1->info, "hostname" ); + n2 = NET_API->ValueForKey( p2->info, "hostname" ); + + if ( n1 && n2 ) + { + if ( stricmp( n1, n2 ) < 0 ) + return 1; + } + } + } + + return 0; +} + +/* +=================== +AddServer + +=================== +*/ +void CHudServers::AddServer( server_t **ppList, server_t *p ) +{ +server_t *list; + + if ( !ppList || ! p ) + return; + + m_nServerCount++; + + // What sort key? Ping? + list = *ppList; + + // Head of list? + if ( !list ) + { + p->next = NULL; + *ppList = p; + return; + } + + // Put on head of list + if ( CompareServers( p, list ) ) + { + p->next = *ppList; + *ppList = p; + } + else + { + while ( list->next ) + { + // Insert before list next + if ( CompareServers( p, list->next ) ) + { + p->next = list->next->next; + list->next = p; + return; + } + + list = list->next; + } + + // Just add at end + p->next = NULL; + list->next = p; + } +} + +/* +=================== +Think + +=================== +*/ +void CHudServers::Think( double time ) +{ + m_fElapsed += time; + + if ( !m_nRequesting ) + return; + + if ( !m_nQuerying ) + return; + + QueryThink(); + + if ( ServerListSize() > 0 ) + return; + + m_dStarted = 0.0; + m_nRequesting = 0; + m_nDone = 0; + m_nQuerying = 0; + m_nActiveQueries = 0; +} + +/* +=================== +QueryThink + +=================== +*/ +void CHudServers::QueryThink( void ) +{ + request_t *p; + + if ( !m_nRequesting || m_nDone ) + return; + + if ( !m_nQuerying ) + return; + + if ( m_nActiveQueries > MAX_QUERIES ) + return; + + // Nothing left + if ( !m_pServerList ) + return; + + while ( 1 ) + { + p = m_pServerList; + + // No more in list? + if ( !p ) + break; + + // Move to next + m_pServerList = m_pServerList->next; + + // Setup context_id + p->context = context_id; + + // Start up query on this one + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); + + // Increment active list + m_nActiveQueries++; + + // Add to active list + p->next = m_pActiveList; + m_pActiveList = p; + + // Too many active? + if ( m_nActiveQueries > MAX_QUERIES ) + break; + } +} + +/* +================== +ServerListSize + +# of servers in active query and in pending to be queried lists +================== +*/ +int CHudServers::ServerListSize( void ) +{ + int c = 0; + request_t *p; + + p = m_pServerList; + while ( p ) + { + c++; + p = p->next; + } + + p = m_pActiveList; + while ( p ) + { + c++; + p = p->next; + } + + return c; +} + +/* +=================== +FindRequest + +Look up a request by context id +=================== +*/ +CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) +{ + request_t *p; + p = pList; + while ( p ) + { + if ( context == p->context ) + return p; + + p = p->next; + } + return NULL; +} + +/* +=================== +RemoveServerFromList + +Remote, but don't delete, item from *ppList +=================== +*/ +void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) +{ + request_t *p, *n; + request_t *newlist = NULL; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + if ( p != item ) + { + p->next = newlist; + newlist = p; + } + p = n; + } + *ppList = newlist; +} + +/* +=================== +ClearRequestList + +=================== +*/ +void CHudServers::ClearRequestList( request_t **ppList ) +{ + request_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete p; + p = n; + } + *ppList = NULL; +} + +/* +=================== +ClearServerList + +=================== +*/ +void CHudServers::ClearServerList( server_t **ppList ) +{ + server_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete[] p->info; + delete p; + p = n; + } + *ppList = NULL; +} + +int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) +{ + const char *sz1, *sz2; + float fv1, fv2; + + sz1 = NET_API->ValueForKey( p1->info, fieldname ); + sz2 = NET_API->ValueForKey( p2->info, fieldname ); + + fv1 = atof( sz1 ); + fv2 = atof( sz2 ); + + if ( fv1 && fv2 ) + { + if ( fv1 > fv2 ) + return iSortOrder; + else if ( fv1 < fv2 ) + return -iSortOrder; + else + return 0; + } + + // String compare + return stricmp( sz1, sz2 ); +} + +int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) +{ + if (!p1 || !p2) // No meaningful comparison + return 0; + + int iSortOrder = 1; + + int retval = 0; + + retval = CompareField( p1, p2, fieldname, iSortOrder ); + + return retval; +} + +static char g_fieldname[ 256 ]; +int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +{ + CHudServers::server_t *list1, *list2; + + list1 = *(CHudServers::server_t **)elem1; + list2 = *(CHudServers::server_t **)elem2; + + return ServerListCompareFunc( list1, list2, g_fieldname ); +} + +void CHudServers::SortServers( const char *fieldname ) +{ + server_t *p; + // Create a list + if ( !m_pServers ) + return; + + strcpy( g_fieldname, fieldname ); + + int i; + int c = 0; + + p = m_pServers; + while ( p ) + { + c++; + p = p->next; + } + + server_t **pSortArray; + + pSortArray = new server_t *[ c ]; + memset( pSortArray, 0, c * sizeof( server_t * ) ); + + // Now copy the list into the pSortArray: + p = m_pServers; + i = 0; + while ( p ) + { + pSortArray[ i++ ] = p; + p = p->next; + } + + // Now do that actual sorting. + size_t nCount = c; + size_t nSize = sizeof( server_t * ); + + qsort( + pSortArray, + (size_t)nCount, + (size_t)nSize, + FnServerCompare + ); + + // Now rebuild the list. + m_pServers = pSortArray[0]; + for ( i = 0; i < c - 1; i++ ) + { + pSortArray[ i ]->next = pSortArray[ i + 1 ]; + } + pSortArray[ c - 1 ]->next = NULL; + + // Clean Up. + delete[] pSortArray; +} + +/* +=================== +GetServer + +Return particular server +=================== +*/ +CHudServers::server_t *CHudServers::GetServer( int server ) +{ + int c = 0; + server_t *p; + + p = m_pServers; + while ( p ) + { + if ( c == server ) + return p; + + c++; + p = p->next; + } + return NULL; +} + +/* +=================== +GetServerInfo + +Return info ( key/value ) string for particular server +=================== +*/ +char *CHudServers::GetServerInfo( int server ) +{ + server_t *p = GetServer( server ); + if ( p ) + { + return p->info; + } + return NULL; +} + +/* +=================== +CancelRequest + +Kill all pending requests in engine +=================== +*/ +void CHudServers::CancelRequest( void ) +{ + m_nRequesting = 0; + m_nQuerying = 0; + m_nDone = 1; + + NET_API->CancelAllRequests(); +} + +/* +================== +LoadMasterAddresses + +Loads the master server addresses from file and into the passed in array +================== +*/ +int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) +{ + int i; + char szMaster[ 256 ]; + char szMasterFile[256]; + char *pbuffer = NULL; + char *pstart = NULL ; + netadr_t adr; + char szAdr[64]; + int nPort; + int nCount = 0; + bool bIgnore; + int nDefaultPort; + + // Assume default master and master file + strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + strcpy( szMasterFile, MASTER_PARSE_FILE ); + + // See if there is a command line override + i = gEngfuncs.CheckParm( "-comm", &pstart ); + if ( i && pstart ) + { + strcpy (szMasterFile, pstart ); + } + + // Read them in from proper file + pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc + if ( !pbuffer ) + { + goto finish_master; + } + + pstart = pbuffer; + + while ( nCount < maxservers ) + { + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if ( strlen(m_szToken) <= 0) + break; + + bIgnore = true; + + if ( !stricmp( m_szToken, "Master" ) ) + { + nDefaultPort = PORT_MASTER; + bIgnore = FALSE; + } + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + if ( strlen(m_szToken) <= 0 ) + break; + + if ( stricmp ( m_szToken, "{" ) ) + break; + + // Parse addresses until we get to "}" + while ( nCount < maxservers ) + { + char base[256]; + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( !stricmp ( m_szToken, "}" ) ) + break; + + sprintf( base, "%s", m_szToken ); + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( stricmp( m_szToken, ":" ) ) + break; + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + nPort = atoi ( m_szToken ); + if ( !nPort ) + nPort = nDefaultPort; + + sprintf( szAdr, "%s:%i", base, nPort ); + + // Can we resolve it any better + if ( !NET_API->StringToAdr( szAdr, &adr ) ) + bIgnore = true; + + if ( !bIgnore ) + { + padr[ nCount++ ] = adr; + } + } + } + +finish_master: + if ( !nCount ) + { + sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + + // Convert to netadr_t + if ( NET_API->StringToAdr ( szMaster, &adr ) ) + { + + padr[ nCount++ ] = adr; + } + } + + *count = nCount; + + if ( pbuffer ) + { + gEngfuncs.COM_FreeFile( pbuffer ); + } + + return ( nCount > 0 ) ? 1 : 0; +} + +/* +=================== +RequestList + +Request list of game servers from master +=================== +*/ +void CHudServers::RequestList( void ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + int count = 0; + netadr_t adr; + + if ( !LoadMasterAddresses( 1, &count, &adr ) ) + { + gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); + return; + } + + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Kill off left overs if any + NET_API->CancelAllRequests(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); +} + +void CHudServers::RequestBroadcastList( int clearpending ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + netadr_t adr; + memset( &adr, 0, sizeof( adr ) ); + + if ( clearpending ) + { + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + } + + // Make sure to byte swap server if necessary ( using "host" to "net" conversion + adr.port = htons( PORT_SERVER ); + + // Make sure networking system has started. + NET_API->InitNetworking(); + + if ( clearpending ) + { + // Kill off left overs if any + NET_API->CancelAllRequests(); + } + + adr.type = NA_BROADCAST; + + // Request Servers from LAN via IP + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); + + adr.type = NA_BROADCAST_IPX; + + // Request Servers from LAN via IPX ( if supported ) + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); +} + +void CHudServers::ServerPing( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); +} + +void CHudServers::ServerRules( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); +} + +void CHudServers::ServerPlayers( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); +} + +int CHudServers::isQuerying() +{ + return m_nRequesting ? 1 : 0; +} + + +/* +=================== +GetServerCount + +Return number of servers in browser list +=================== +*/ +int CHudServers::GetServerCount( void ) +{ + return m_nServerCount; +} + +/* +=================== +CHudServers + +=================== +*/ +CHudServers::CHudServers( void ) +{ + m_nRequesting = 0; + m_dStarted = 0.0; + m_nDone = 0; + m_pServerList = NULL; + m_pServers = NULL; + m_pActiveList = NULL; + m_nQuerying = 0; + m_nActiveQueries = 0; + + m_fElapsed = 0.0; + + + m_pPingRequest = NULL; + m_pRulesRequest = NULL; + m_pPlayersRequest = NULL; +} + +/* +=================== +~CHudServers + +=================== +*/ +CHudServers::~CHudServers( void ) +{ + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + if ( m_pPingRequest ) + { + delete m_pPingRequest; + m_pPingRequest = NULL; + + } + + if ( m_pRulesRequest ) + { + delete m_pRulesRequest; + m_pRulesRequest = NULL; + } + + if ( m_pPlayersRequest ) + { + delete m_pPlayersRequest; + m_pPlayersRequest = NULL; + } +} + +/////////////////////////////// +// +// PUBLIC APIs +// +/////////////////////////////// + +/* +=================== +ServersGetCount + +=================== +*/ +int ServersGetCount( void ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerCount(); + } + return 0; +} + +int ServersIsQuerying( void ) +{ + if ( g_pServers ) + { + return g_pServers->isQuerying(); + } + return 0; +} + +/* +=================== +ServersGetInfo + +=================== +*/ +const char *ServersGetInfo( int server ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerInfo( server ); + } + + return NULL; +} + +void SortServers( const char *fieldname ) +{ + if ( g_pServers ) + { + g_pServers->SortServers( fieldname ); + } +} + +/* +=================== +ServersShutdown + +=================== +*/ +void ServersShutdown( void ) +{ + if ( g_pServers ) + { + delete g_pServers; + g_pServers = NULL; + } +} + +/* +=================== +ServersInit + +=================== +*/ +void ServersInit( void ) +{ + // Kill any previous instance + ServersShutdown(); + + g_pServers = new CHudServers(); +} + +/* +=================== +ServersThink + +=================== +*/ +void ServersThink( double time ) +{ + if ( g_pServers ) + { + g_pServers->Think( time ); + } +} + +/* +=================== +ServersCancel + +=================== +*/ +void ServersCancel( void ) +{ + if ( g_pServers ) + { + g_pServers->CancelRequest(); + } +} + +// Requests +/* +=================== +ServersList + +=================== +*/ +void ServersList( void ) +{ + if ( g_pServers ) + { + g_pServers->RequestList(); + } +} + +void BroadcastServersList( int clearpending ) +{ + if ( g_pServers ) + { + g_pServers->RequestBroadcastList( clearpending ); + } +} + +void ServerPing( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPing( server ); + } +} + +void ServerRules( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerRules( server ); + } +} + +void ServerPlayers( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPlayers( server ); + } } \ No newline at end of file diff --git a/cl_dll/hud_servers.h b/cl_dll/hud_servers.h index 02bc8555..01e94425 100644 --- a/cl_dll/hud_servers.h +++ b/cl_dll/hud_servers.h @@ -1,41 +1,41 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( HUD_SERVERSH ) -#define HUD_SERVERSH -#pragma once - -#define NET_CALLBACK /* */ - -// Dispatchers -void NET_CALLBACK ListResponse( struct net_response_s *response ); -void NET_CALLBACK ServerResponse( struct net_response_s *response ); -void NET_CALLBACK PingResponse( struct net_response_s *response ); -void NET_CALLBACK RulesResponse( struct net_response_s *response ); -void NET_CALLBACK PlayersResponse( struct net_response_s *response ); - -void ServersInit( void ); -void ServersShutdown( void ); -void ServersThink( double time ); -void ServersCancel( void ); - -// Get list and get server info from each -void ServersList( void ); - -// Query for IP / IPX LAN servers -void BroadcastServersList( int clearpending ); - -void ServerPing( int server ); -void ServerRules( int server ); -void ServerPlayers( int server ); - -int ServersGetCount( void ); -const char *ServersGetInfo( int server ); -int ServersIsQuerying( void ); -void SortServers( const char *fieldname ); - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERSH ) +#define HUD_SERVERSH +#pragma once + +#define NET_CALLBACK /* */ + +// Dispatchers +void NET_CALLBACK ListResponse( struct net_response_s *response ); +void NET_CALLBACK ServerResponse( struct net_response_s *response ); +void NET_CALLBACK PingResponse( struct net_response_s *response ); +void NET_CALLBACK RulesResponse( struct net_response_s *response ); +void NET_CALLBACK PlayersResponse( struct net_response_s *response ); + +void ServersInit( void ); +void ServersShutdown( void ); +void ServersThink( double time ); +void ServersCancel( void ); + +// Get list and get server info from each +void ServersList( void ); + +// Query for IP / IPX LAN servers +void BroadcastServersList( int clearpending ); + +void ServerPing( int server ); +void ServerRules( int server ); +void ServerPlayers( int server ); + +int ServersGetCount( void ); +const char *ServersGetInfo( int server ); +int ServersIsQuerying( void ); +void SortServers( const char *fieldname ); + #endif // HUD_SERVERSH \ No newline at end of file diff --git a/cl_dll/hud_servers_priv.h b/cl_dll/hud_servers_priv.h index 1919a0a7..73692f46 100644 --- a/cl_dll/hud_servers_priv.h +++ b/cl_dll/hud_servers_priv.h @@ -1,98 +1,98 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( HUD_SERVERS_PRIVH ) -#define HUD_SERVERS_PRIVH -#pragma once - -#include "netadr.h" - -class CHudServers -{ -public: - typedef struct request_s - { - struct request_s *next; - netadr_t remote_address; - int context; - } request_t; - - typedef struct server_s - { - struct server_s *next; - netadr_t remote_address; - char *info; - int ping; - } server_t; - - CHudServers(); - ~CHudServers(); - - void Think( double time ); - void QueryThink( void ); - int isQuerying( void ); - - int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); - - void RequestList( void ); - void RequestBroadcastList( int clearpending ); - - void ServerPing( int server ); - void ServerRules( int server ); - void ServerPlayers( int server ); - - void CancelRequest( void ); - - int CompareServers( server_t *p1, server_t *p2 ); - - void ClearServerList( server_t **ppList ); - void ClearRequestList( request_t **ppList ); - - void AddServer( server_t **ppList, server_t *p ); - - void RemoveServerFromList( request_t **ppList, request_t *item ); - - request_t *FindRequest( int context, request_t *pList ); - - int ServerListSize( void ); - char *GetServerInfo( int server ); - int GetServerCount( void ); - void SortServers( const char *fieldname ); - - void ListResponse( struct net_response_s *response ); - void ServerResponse( struct net_response_s *response ); - void PingResponse( struct net_response_s *response ); - void RulesResponse( struct net_response_s *response ); - void PlayersResponse( struct net_response_s *response ); -private: - - server_t *GetServer( int server ); - - // - char m_szToken[ 1024 ]; - int m_nRequesting; - int m_nDone; - - double m_dStarted; - - request_t *m_pServerList; - request_t *m_pActiveList; - - server_t *m_pServers; - - int m_nServerCount; - - int m_nActiveQueries; - int m_nQuerying; - double m_fElapsed; - - request_t *m_pPingRequest; - request_t *m_pRulesRequest; - request_t *m_pPlayersRequest; -}; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERS_PRIVH ) +#define HUD_SERVERS_PRIVH +#pragma once + +#include "netadr.h" + +class CHudServers +{ +public: + typedef struct request_s + { + struct request_s *next; + netadr_t remote_address; + int context; + } request_t; + + typedef struct server_s + { + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; + } server_t; + + CHudServers(); + ~CHudServers(); + + void Think( double time ); + void QueryThink( void ); + int isQuerying( void ); + + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + + void RequestList( void ); + void RequestBroadcastList( int clearpending ); + + void ServerPing( int server ); + void ServerRules( int server ); + void ServerPlayers( int server ); + + void CancelRequest( void ); + + int CompareServers( server_t *p1, server_t *p2 ); + + void ClearServerList( server_t **ppList ); + void ClearRequestList( request_t **ppList ); + + void AddServer( server_t **ppList, server_t *p ); + + void RemoveServerFromList( request_t **ppList, request_t *item ); + + request_t *FindRequest( int context, request_t *pList ); + + int ServerListSize( void ); + char *GetServerInfo( int server ); + int GetServerCount( void ); + void SortServers( const char *fieldname ); + + void ListResponse( struct net_response_s *response ); + void ServerResponse( struct net_response_s *response ); + void PingResponse( struct net_response_s *response ); + void RulesResponse( struct net_response_s *response ); + void PlayersResponse( struct net_response_s *response ); +private: + + server_t *GetServer( int server ); + + // + char m_szToken[ 1024 ]; + int m_nRequesting; + int m_nDone; + + double m_dStarted; + + request_t *m_pServerList; + request_t *m_pActiveList; + + server_t *m_pServers; + + int m_nServerCount; + + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; + + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; +}; + #endif // HUD_SERVERS_PRIVH \ No newline at end of file diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 54d723c5..019c71e9 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -1,1595 +1,1595 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "cl_entity.h" -#include "triangleapi.h" -#include "hltv.h" - -#include "pm_shared.h" -#include "pm_defs.h" -#include "pmtrace.h" -#include "parsemsg.h" -#include "entity_types.h" - -// these are included for the math functions -#include "com_model.h" -#include "demo_api.h" -#include "event_api.h" -#include "studio_util.h" -#include "screenfade.h" - - -#pragma warning(disable: 4244) - -extern "C" int iJumpSpectator; -extern "C" float vJumpOrigin[3]; -extern "C" float vJumpAngles[3]; - - -extern void V_GetInEyePos(int entity, float * origin, float * angles ); -extern void V_ResetChaseCam(); -extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); -extern void VectorAngles( const float *forward, float *angles ); -extern "C" void NormalizeAngles( float *angles ); -extern float * GetClientColor( int clientIndex ); - -extern vec3_t v_origin; // last view origin -extern vec3_t v_angles; // last view angle -extern vec3_t v_cl_angles; // last client/mouse angle -extern vec3_t v_sim_org; // last sim origin - -void SpectatorMode(void) -{ - - - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_mode
[]\n" ); - return; - } - - // SetModes() will decide if command is executed on server or local - if ( gEngfuncs.Cmd_Argc() == 2 ) - gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), -1 ); - else if ( gEngfuncs.Cmd_Argc() == 3 ) - gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); -} - -void SpectatorSpray(void) -{ - vec3_t forward; - char string[128]; - - if ( !gEngfuncs.IsSpectateOnly() ) - return; - - AngleVectors(v_angles,forward,NULL,NULL); - VectorScale(forward, 128, forward); - VectorAdd(forward, v_origin, forward); - pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - if ( trace->fraction != 1.0 ) - { - sprintf(string, "drc_spray %.2f %.2f %.2f %i", - trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); - gEngfuncs.pfnServerCmd(string); - } - -} -void SpectatorHelp(void) -{ - { - char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); - - if ( text ) - { - while ( *text ) - { - if ( *text != 13 ) - gEngfuncs.Con_Printf( "%c", *text ); - text++; - } - } - } -} - -void SpectatorMenu( void ) -{ - if ( gEngfuncs.Cmd_Argc() <= 1 ) - { - gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); - return; - } - -} - -void ToggleScores( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CHudSpectator::Init() -{ - gHUD.AddHudElem(this); - - m_iFlags |= HUD_ACTIVE; - m_flNextObserverInput = 0.0f; - m_zoomDelta = 0.0f; - m_moveDelta = 0.0f; - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); - iJumpSpectator = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - m_lastPrimaryObject = m_lastSecondaryObject = 0; - - gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); - gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); - gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); - gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); - gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); - - m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); - m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); - m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); - m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); - m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); - - if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip) - { - gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); - return 0; - } - - return 1; -} - - -//----------------------------------------------------------------------------- -// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed -//----------------------------------------------------------------------------- - -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++ ) - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - if (j < 2) - { - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - -int UTIL_FindEntityInMap(char * name, float * origin, float * angle) -{ - int n,found = 0; - char keyname[256]; - char token[2048]; - - cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model - - if ( !pEnt ) return 0; - - if ( !pEnt->model ) return 0; - - char * data = pEnt->model->entities; - - while (data) - { - data = gEngfuncs.COM_ParseFile(data, token); - - if ( (token[0] == '}') || (token[0]==0) ) - break; - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - } - - if (token[0] != '{') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); - return 0; - } - - // we parse the first { now parse entities properties - - while ( 1 ) - { - // parse key - data = gEngfuncs.COM_ParseFile(data, token); - if (token[0] == '}') - break; // finish parsing this entity - - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - strcpy (keyname, token); - - // another hack to fix keynames with trailing spaces - n = strlen(keyname); - while (n && keyname[n-1] == ' ') - { - keyname[n-1] = 0; - n--; - } - - // parse value - data = gEngfuncs.COM_ParseFile(data, token); - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - if (token[0] == '}') - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); - return 0; - } - - if (!strcmp(keyname,"classname")) - { - if (!strcmp(token, name )) - { - found = 1; // thats our entity - } - }; - - if( !strcmp( keyname, "angle" ) ) - { - float y = atof( token ); - - if (y >= 0) - { - angle[0] = 0.0f; - angle[1] = y; - } - else if ((int)y == -1) - { - angle[0] = -90.0f; - angle[1] = 0.0f;; - } - else - { - angle[0] = 90.0f; - angle[1] = 0.0f; - } - - angle[2] = 0.0f; - } - - if( !strcmp( keyname, "angles" ) ) - { - UTIL_StringToVector(angle, token); - } - - if (!strcmp(keyname,"origin")) - { - UTIL_StringToVector(origin, token); - - }; - - } // while (1) - - if (found) - return 1; - - } - - return 0; // we search all entities, but didn't found the correct - -} - -//----------------------------------------------------------------------------- -// SetSpectatorStartPosition(): -// Get valid map position and 'beam' spectator to this position -//----------------------------------------------------------------------------- - -void CHudSpectator::SetSpectatorStartPosition() -{ - // search for info_player start - if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - - else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) - iJumpSpectator = 1; - else - { - // jump to 0,0,0 if no better position was found - VectorCopy(vec3_origin, m_cameraOrigin); - VectorCopy(vec3_origin, m_cameraAngles); - } - - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - - iJumpSpectator = 1; // jump anyway -} - -//----------------------------------------------------------------------------- -// Purpose: Loads new icons -//----------------------------------------------------------------------------- -int CHudSpectator::VidInit() -{ - m_hsprPlayer = SPR_Load("sprites/iplayer.spr"); - m_hsprPlayerBlue = SPR_Load("sprites/iplayerblue.spr"); - m_hsprPlayerRed = SPR_Load("sprites/iplayerred.spr"); - m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); - m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); - m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); - m_hsprCamera = SPR_Load("sprites/camera.spr"); - m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flTime - -// intermission - -//----------------------------------------------------------------------------- -int CHudSpectator::Draw(float flTime) -{ - int lx; - - char string[256]; - float * color; - - // draw only in spectator mode - if ( !g_iUser1 ) - return 0; - - // if user pressed zoom, aplly changes - if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) - { - m_mapZoom += m_zoomDelta; - - if ( m_mapZoom > 3.0f ) - m_mapZoom = 3.0f; - - if ( m_mapZoom < 0.5f ) - m_mapZoom = 0.5f; - } - - // if user moves in map mode, change map origin - if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) - { - vec3_t right; - AngleVectors(v_angles, NULL, right, NULL); - VectorNormalize(right); - VectorScale(right, m_moveDelta, right ); - - VectorAdd( m_mapOrigin, right, m_mapOrigin ) - - } - - // Only draw the icon names only if map mode is in Main Mode - if ( g_iUser1 < OBS_MAP_FREE ) - return 1; - - if ( !m_drawnames->value ) - return 1; - - // make sure we have player info - //gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - - - - // loop through all the players and draw additional infos to their sprites on the map - for (int i = 0; i < MAX_PLAYERS; i++) - { - - if ( m_vPlayerPos[i][2]<0 ) // marked as invisible ? - continue; - - // check if name would be in inset window - if ( m_pip->value != INSET_OFF ) - { - if ( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && - m_vPlayerPos[i][1] > YRES( m_OverviewData.insetWindowY ) && - m_vPlayerPos[i][0] < XRES( m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth ) && - m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) - ) continue; - } - - color = GetClientColor( i+1 ); - - // draw the players name and health underneath - sprintf(string, "%s", g_PlayerInfoList[i+1].name ); - - lx = strlen(string)*3; // 3 is avg. character length :) - - DrawSetTextColor( color[0], color[1], color[2] ); - DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); - - } - - return 1; -} - - -void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) -{ - float value; - char * string; - - BEGIN_READ( pbuf, iSize ); - - int cmd = READ_BYTE(); - - switch ( cmd ) // director command byte - { - case DRC_CMD_START : - // now we have to do some things clientside, since the proxy doesn't know our mod - g_iPlayerClass = 0; - g_iTeamNumber = 0; - - // fake a InitHUD & ResetHUD message - gHUD.MsgFunc_InitHUD(NULL,0, NULL); - gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); - - break; - - case DRC_CMD_EVENT : - m_lastPrimaryObject = READ_WORD(); - m_lastSecondaryObject = READ_WORD(); - m_iObserverFlags = READ_LONG(); - - if ( m_autoDirector->value ) - { - if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) - V_ResetChaseCam(); - - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - - // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); - break; - - case DRC_CMD_MODE : - if ( m_autoDirector->value ) - { - SetModes( READ_BYTE(), -1 ); - } - break; - - case DRC_CMD_CAMERA : - if ( m_autoDirector->value ) - { - vJumpOrigin[0] = READ_COORD(); // position - vJumpOrigin[1] = READ_COORD(); - vJumpOrigin[2] = READ_COORD(); - - vJumpAngles[0] = READ_COORD(); // view angle - vJumpAngles[1] = READ_COORD(); - vJumpAngles[2] = READ_COORD(); - - gEngfuncs.SetViewAngles( vJumpAngles ); - - iJumpSpectator = 1; - } - break; - - case DRC_CMD_MESSAGE: - { - client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; - - msg->effect = READ_BYTE(); // effect - - UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color - msg->r2 = msg->r1; - msg->g2 = msg->g1; - msg->b2 = msg->b1; - msg->a2 = msg->a1 = 0xFF; // not transparent - - msg->x = READ_FLOAT(); // x pos - msg->y = READ_FLOAT(); // y pos - - msg->fadein = READ_FLOAT(); // fadein - msg->fadeout = READ_FLOAT(); // fadeout - msg->holdtime = READ_FLOAT(); // holdtime - msg->fxtime = READ_FLOAT(); // fxtime; - - strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); - m_HUDMessageText[m_lastHudMessage][127]=0; // text - - msg->pMessage = m_HUDMessageText[m_lastHudMessage]; - msg->pName = "HUD_MESSAGE"; - - gHUD.m_Message.MessageAdd( msg ); - - m_lastHudMessage++; - m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; - - } - - break; - - case DRC_CMD_SOUND : - string = READ_STRING(); - value = READ_FLOAT(); - - // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); - gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); - - break; - - case DRC_CMD_TIMESCALE : - value = READ_FLOAT(); - break; - - - - case DRC_CMD_STATUS: - READ_LONG(); // total number of spectator slots - m_iSpectatorNumber = READ_LONG(); // total number of spectator - READ_WORD(); // total number of relay proxies - - break; - - case DRC_CMD_BANNER: - // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga - break; - - case DRC_CMD_FADE: - break; - - case DRC_CMD_STUFFTEXT: - ClientCmd( READ_STRING() ); - break; - - default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); - } -} - -void CHudSpectator::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; - cl_entity_t * pEnt = NULL; - - // if we are NOT in HLTV mode, spectator targets are set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - char cmdstring[32]; - // forward command to server - sprintf(cmdstring,"follownext %i",bReverse?1:0); - gEngfuncs.pfnServerCmd(cmdstring); - return; - } - - if ( g_iUser2 ) - iStart = g_iUser2; - else - iStart = 1; - - g_iUser2 = 0; - - int iCurrent = iStart; - - int iDir = bReverse ? -1 : 1; - - // make sure we have player info - //gViewPort->GetAllPlayersInfo(); - gHUD.m_Scoreboard.GetAllPlayersInfo(); - - - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > MAX_PLAYERS) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = MAX_PLAYERS; - - pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); - - if ( !IsActivePlayer( pEnt ) ) - continue; - - // MOD AUTHORS: Add checks on target here. - - g_iUser2 = iCurrent; - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( !g_iUser2 ) - { - gEngfuncs.Con_DPrintf( "No observer targets.\n" ); - // take save camera position - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); - } - else - { - // use new entity position for roaming - VectorCopy ( pEnt->origin, vJumpOrigin ); - VectorCopy ( pEnt->angles, vJumpAngles ); - } - iJumpSpectator = 1; -} - -void CHudSpectator::HandleButtonsDown( int ButtonPressed ) -{ - double time = gEngfuncs.GetClientTime(); - - int newMainMode = g_iUser1; - int newInsetMode = m_pip->value; - - // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); - - //Not in intermission. - if ( gHUD.m_iIntermission ) - return; - - if ( !g_iUser1 ) - return; // dont do anything if not in spectator mode - - // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) - return; - // Slow down mouse clicks. - if ( m_flNextObserverInput > time ) - return; - - // enable spectator screen - //if ( ButtonPressed & IN_DUCK ) - // gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); - - // 'Use' changes inset window mode - if ( ButtonPressed & IN_USE ) - { - newInsetMode = ToggleInset(true); - } - - // if not in HLTV mode, buttons are handled server side - if ( gEngfuncs.IsSpectateOnly() ) - { - // changing target or chase mode not in overviewmode without inset window - - // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) - { - if ( g_iUser1 == OBS_CHASE_LOCKED ) - newMainMode = OBS_CHASE_FREE; - - else if ( g_iUser1 == OBS_CHASE_FREE ) - newMainMode = OBS_IN_EYE; - - else if ( g_iUser1 == OBS_IN_EYE ) - newMainMode = OBS_ROAMING; - - else if ( g_iUser1 == OBS_ROAMING ) - newMainMode = OBS_MAP_FREE; - - else if ( g_iUser1 == OBS_MAP_FREE ) - newMainMode = OBS_MAP_CHASE; - - else - newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore - } - - // Attack moves to the next player - if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) - { - FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); - - if ( g_iUser1 == OBS_ROAMING ) - { - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - - } - // lease directed mode if player want to see another player - m_autoDirector->value = 0.0f; - } - } - - SetModes(newMainMode, newInsetMode); - - if ( g_iUser1 == OBS_MAP_FREE ) - { - if ( ButtonPressed & IN_FORWARD ) - m_zoomDelta = 0.01f; - - if ( ButtonPressed & IN_BACK ) - m_zoomDelta = -0.01f; - - if ( ButtonPressed & IN_MOVELEFT ) - m_moveDelta = -12.0f; - - if ( ButtonPressed & IN_MOVERIGHT ) - m_moveDelta = 12.0f; - } - - m_flNextObserverInput = time + 0.2; -} - -void CHudSpectator::HandleButtonsUp( int ButtonPressed ) -{ - - if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) - m_zoomDelta = 0.0f; - - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) - m_moveDelta = 0.0f; -} - -void CHudSpectator::SetModes(int iNewMainMode, int iNewInsetMode) -{ - // if value == -1 keep old value - if ( iNewMainMode == -1 ) - iNewMainMode = g_iUser1; - - if ( iNewInsetMode == -1 ) - iNewInsetMode = m_pip->value; - - // inset mode is handled only clients side - m_pip->value = iNewInsetMode; - - if ( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) - { - gEngfuncs.Con_Printf("Invalid spectator mode.\n"); - return; - } - - // main modes ettings will override inset window settings - if ( iNewMainMode != g_iUser1 ) - { - // if we are NOT in HLTV mode, main spectator mode is set on server - if ( !gEngfuncs.IsSpectateOnly() ) - { - return; - } - - if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target - { - // choose last Director object if still available - if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) - { - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } - else - FindNextPlayer(false); // find any target - } - - switch ( iNewMainMode ) - { - case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; - break; - - case OBS_CHASE_FREE : g_iUser1 = OBS_CHASE_FREE; - break; - - case OBS_ROAMING : // jump to current vJumpOrigin/angle - g_iUser1 = OBS_ROAMING; - if ( g_iUser2 ) - { - V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - } - break; - - case OBS_IN_EYE : g_iUser1 = OBS_IN_EYE; - break; - - case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - - case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - } - - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - char string[128]; - sprintf(string, "#Spec_Mode%d", g_iUser1 ); - sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); - } - -} - -bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) -{ - return ( ent && - ent->player && - ent->curstate.solid != SOLID_NOT && - ent != gEngfuncs.GetLocalPlayer() && - g_PlayerInfoList[ent->index].name != NULL - ); -} - - -bool CHudSpectator::ParseOverviewFile( ) -{ - char filename[255] = { 0 }; - char levelname[255] = { 0 }; - char token[1024] = { 0 }; - float height; - - char *pfile = NULL; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - - // fill in standrd values - m_OverviewData.insetWindowX = 4; // upper left corner - m_OverviewData.insetWindowY = 4; - m_OverviewData.insetWindowHeight = 180; - m_OverviewData.insetWindowWidth = 240; - m_OverviewData.origin[0] = 0.0f; - m_OverviewData.origin[1] = 0.0f; - m_OverviewData.origin[2] = 0.0f; - m_OverviewData.zoom = 1.0f; - m_OverviewData.layers = 0; - m_OverviewData.layersHeights[0] = 0.0f; - strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); - - if ( strlen( m_OverviewData.map ) == 0 ) - return false; // not active yet - - strcpy(levelname, m_OverviewData.map + 5); - levelname[strlen(levelname)-4] = 0; - - sprintf(filename, "overviews/%s.txt", levelname ); - - pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); - - if (!pfile) - { - gEngfuncs.Con_DPrintf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); - return false; - } - - - while (true) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - - if (!pfile) - break; - - if ( !stricmp( token, "global" ) ) - { - // parse the global data - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "zoom" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.zoom = atof( token ); - } - else if ( !stricmp( token, "origin" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[0] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.origin[1] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile, token); - m_OverviewData.origin[2] = atof( token ); - } - else if ( !stricmp( token, "rotated" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.rotated = atoi( token ); - } - else if ( !stricmp( token, "inset" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.insetWindowX = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.insetWindowY = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.insetWindowWidth = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); - m_OverviewData.insetWindowHeight = atof( token ); - - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - - } - } - else if ( !stricmp( token, "layer" ) ) - { - // parse a layer data - - if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - - if ( stricmp( token, "{" ) ) - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); - - while (stricmp( token, "}") ) - { - if ( !stricmp( token, "image" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); - - - } - else if ( !stricmp( token, "height" ) ) - { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - height = atof(token); - m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; - } - else - { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); - return false; - } - - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - } - - m_OverviewData.layers++; - - } - } - - gEngfuncs.COM_FreeFile( pfile ); - - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - - return true; - -} - -void CHudSpectator::LoadMapSprites() -{ - // right now only support for one map layer - if (m_OverviewData.layers > 0 ) - { - m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); - } - else - m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead -} - -void CHudSpectator::DrawOverviewLayer() -{ - float screenaspect, xs, ys, xStep, yStep, x,y,z; - int ix,iy,i,xTiles,yTiles,frame; - - qboolean hasMapImage = m_MapSprite?TRUE:FALSE; - model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); - - if ( hasMapImage) - { - i = m_MapSprite->numframes / (4*3); - i = sqrt(i); - xTiles = i*4; - yTiles = i*3; - } - else - { - xTiles = 8; - yTiles = 6; - } - - - screenaspect = 4.0f/3.0f; - - - xs = m_OverviewData.origin[0]; - ys = m_OverviewData.origin[1]; - z = ( 90.0f - v_angles[0] ) / 90.0f; - z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; - - // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - - frame = 0; - - - // rotated view ? - if ( m_OverviewData.rotated ) - { - xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); - - for (iy = 0; iy < yTiles; iy++) - { - x = xs - (4096.0f / (m_OverviewData.zoom)); - - for (ix = 0; ix < xTiles; ix++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - x+= xStep; - } - - y+=yStep; - } - } - else - { - xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; - - - x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); - - - - for (ix = 0; ix < yTiles; ix++) - { - - y = ys + (4096.0f / (m_OverviewData.zoom)); - - for (iy = 0; iy < xTiles; iy++) - { - if (hasMapImage) - gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); - else - gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); - gEngfuncs.pTriAPI->End(); - - frame++; - - y+=yStep; - } - - x+= xStep; - - } - } -} - -void CHudSpectator::DrawOverviewEntities() -{ - int i,ir,ig,ib; - struct model_s *hSpriteModel; - vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; - float x,y,z, r,g,b, sizeScale = 4.0f; - cl_entity_t * ent; - float rmatrix[3][4]; // transformation matrix - - float zScale = (90.0f - v_angles[0] ) / 90.0f; - - - z = m_OverviewData.layersHeights[0] * zScale; - // get yellow/brown HUD color - UnpackRGB(ir,ig,ib, RGB_YELLOWISH); - r = (float)ir/255.0f; - g = (float)ig/255.0f; - b = (float)ib/255.0f; - - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - - for (i=0; i < MAX_PLAYERS; i++ ) - m_vPlayerPos[i][2] = -1; // mark as invisible - - // draw all players - for (i=0 ; i < MAX_OVERVIEW_ENTITIES ; i++) - { - if ( !m_OverviewEntities[i].hSprite ) - continue; - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); - ent = m_OverviewEntities[i].entity; - - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - - // see R_DrawSpriteModel - // draws players sprite - - AngleVectors(ent->angles, right, up, NULL ); - - VectorCopy(ent->origin,origin); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (0,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->TexCoord2f (1,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); - point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); - - gEngfuncs.pTriAPI->End (); - - - if ( !ent->player) - continue; - // draw line under player icons - origin[2] *= zScale; - - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); - - // calculate screen position for name and infromation in hud::draw() - if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) - continue; // object is behind viewer - - screen[0] = XPROJECT(screen[0]); - screen[1] = YPROJECT(screen[1]); - screen[2] = 0.0f; - - // calculate some offset under the icon - origin[0]+=32.0f; - origin[1]+=32.0f; - - gEngfuncs.pTriAPI->WorldToScreen(origin,offset); - - offset[0] = XPROJECT(offset[0]); - offset[1] = YPROJECT(offset[1]); - offset[2] = 0.0f; - - VectorSubtract(offset, screen, offset ); - - int playerNum = ent->index - 1; - - m_vPlayerPos[playerNum][0] = screen[0]; - m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); - m_vPlayerPos[playerNum][2] = 1; // mark player as visible - } - - if ( !m_pip->value || !m_drawcone->value ) - return; - - // get current camera position and angle - - if ( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) - { - V_GetInEyePos( g_iUser2, origin, angles ); - } - else if ( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) - { - V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); - } - else if ( g_iUser1 == OBS_ROAMING ) - { - VectorCopy( v_sim_org, origin ); - VectorCopy( v_cl_angles, angles ); - } - else - V_GetChasePos( g_iUser2, NULL, origin, angles ); - - - // draw camera sprite - - x = origin[0]; - y = origin[1]; - z = origin[2]; - - angles[0] = 0; // always show horizontal camera sprite - - hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - - gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); - - AngleVectors(angles, forward, NULL, NULL ); - VectorScale (forward, 512.0f, forward); - - offset[0] = 0.0f; - offset[1] = 45.0f; - offset[2] = 0.0f; - - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , right ); - - offset[1]= -45.0f; - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , left ); - - gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); - gEngfuncs.pTriAPI->End (); - -} - - - -void CHudSpectator::DrawOverview() -{ - // draw only in sepctator mode - if ( !g_iUser1 ) - return; - - // Only draw the overview if Map Mode is selected for this view - if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) - return; - - if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) - return; - - DrawOverviewLayer(); - DrawOverviewEntities(); - CheckOverviewEntities(); -} -void CHudSpectator::CheckOverviewEntities() -{ - double time = gEngfuncs.GetClientTime(); - - // removes old entities from list - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // remove entity from list if it is too old - if ( m_OverviewEntities[i].killTime < time ) - { - memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); - } - } -} - -bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) -{ - HSPRITE hSprite = 0; - double duration = -1.0f; // duration -1 means show it only this frame; - - if ( !ent ) - return false; - - if ( type == ET_PLAYER ) - { - if ( ent->curstate.solid != SOLID_NOT) - { - switch ( g_PlayerExtraInfo[ent->index].teamnumber ) - { - // blue and red teams are swapped in CS and TFC - case 1 : hSprite = m_hsprPlayerBlue; break; - case 2 : hSprite = m_hsprPlayerRed; break; - default : hSprite = m_hsprPlayer; break; - } - } - else - return false; // it's an spectator - } - else if (type == ET_NORMAL) - { - return false; - } - else - return false; - - return AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration ); -} - -void CHudSpectator::DeathMessage(int victim) -{ - // find out where the victim is - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); - - if (pl && pl->player) - AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); -} - -bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) -{ - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) - { - // find empty entity slot - if ( m_OverviewEntities[i].entity == NULL) - { - m_OverviewEntities[i].entity = ent; - m_OverviewEntities[i].hSprite = sprite; - m_OverviewEntities[i].killTime = killTime; - return true; - } - } - - return false; // maximum overview entities reached -} -void CHudSpectator::CheckSettings() -{ - // disallow same inset mode as main mode: - - m_pip->value = (int)m_pip->value; - - if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) - { - // otherwise both would show in World picures - m_pip->value = INSET_MAP_FREE; - } - - if ( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) - { - // both would show map views - m_pip->value = INSET_CHASE_FREE; - } - - // disble in intermission screen - if ( gHUD.m_iIntermission ) - m_pip->value = INSET_OFF; - - // check chat mode - if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) - { - // hud_saytext changed - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); - - if ( gEngfuncs.IsSpectateOnly() ) - { - // tell proxy our new chat mode - char chatcmd[32]; - sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); - gEngfuncs.pfnServerCmd(chatcmd); - } - } - - // HL/TFC has no oberserver corsshair, so set it client side - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) - { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; - m_crosshairRect.bottom = 24; - - SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); - } - else - { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); - SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - - - // if we are a real player on server don't allow inset window - // in First Person mode since this is our resticted forcecamera mode 2 - // team number 3 = SPECTATOR see player.h - - if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) - m_pip->value = INSET_OFF; - - // draw small border around inset view, adjust upper black bar -} - -int CHudSpectator::ToggleInset(bool allowOff) -{ - int newInsetMode = (int)m_pip->value + 1; - - if ( g_iUser1 < OBS_MAP_FREE ) - { - if ( newInsetMode > INSET_MAP_CHASE ) - { - if (allowOff) - newInsetMode = INSET_OFF; - else - newInsetMode = INSET_MAP_FREE; - } - - if ( newInsetMode == INSET_CHASE_FREE ) - newInsetMode = INSET_MAP_FREE; - } - else - { - if ( newInsetMode > INSET_IN_EYE ) - { - if (allowOff) - newInsetMode = INSET_OFF; - else - newInsetMode = INSET_CHASE_FREE; - } - } - - return newInsetMode; -} -void CHudSpectator::Reset() -{ - // Reset HUD - if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) - { - // update level overview if level changed - ParseOverviewFile(); - LoadMapSprites(); - } - - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - SetSpectatorStartPosition(); -} - -void CHudSpectator::InitHUDData() -{ - m_lastPrimaryObject = m_lastSecondaryObject = 0; - m_flNextObserverInput = 0.0f; - m_lastHudMessage = 0; - m_iSpectatorNumber = 0; - iJumpSpectator = 0; - g_iUser1 = g_iUser2 = 0; - - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - - if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) - m_autoDirector->value = 1.0f; - else - m_autoDirector->value = 0.0f; - - Reset(); - - SetModes( OBS_CHASE_FREE, INSET_OFF ); - - g_iUser2 = 0; // fake not target until first camera command - - // reset HUD FOV - gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); -} - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "hltv.h" + +#include "pm_shared.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "parsemsg.h" +#include "entity_types.h" + +// these are included for the math functions +#include "com_model.h" +#include "demo_api.h" +#include "event_api.h" +#include "studio_util.h" +#include "screenfade.h" + + +#pragma warning(disable: 4244) + +extern "C" int iJumpSpectator; +extern "C" float vJumpOrigin[3]; +extern "C" float vJumpAngles[3]; + + +extern void V_GetInEyePos(int entity, float * origin, float * angles ); +extern void V_ResetChaseCam(); +extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); +extern float * GetClientColor( int clientIndex ); + +extern vec3_t v_origin; // last view origin +extern vec3_t v_angles; // last view angle +extern vec3_t v_cl_angles; // last client/mouse angle +extern vec3_t v_sim_org; // last sim origin + +void SpectatorMode(void) +{ + + + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_mode
[]\n" ); + return; + } + + // SetModes() will decide if command is executed on server or local + if ( gEngfuncs.Cmd_Argc() == 2 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), -1 ); + else if ( gEngfuncs.Cmd_Argc() == 3 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); +} + +void SpectatorSpray(void) +{ + vec3_t forward; + char string[128]; + + if ( !gEngfuncs.IsSpectateOnly() ) + return; + + AngleVectors(v_angles,forward,NULL,NULL); + VectorScale(forward, 128, forward); + VectorAdd(forward, v_origin, forward); + pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); + if ( trace->fraction != 1.0 ) + { + sprintf(string, "drc_spray %.2f %.2f %.2f %i", + trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); + gEngfuncs.pfnServerCmd(string); + } + +} +void SpectatorHelp(void) +{ + { + char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + + if ( text ) + { + while ( *text ) + { + if ( *text != 13 ) + gEngfuncs.Con_Printf( "%c", *text ); + text++; + } + } + } +} + +void SpectatorMenu( void ) +{ + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); + return; + } + +} + +void ToggleScores( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudSpectator::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + m_flNextObserverInput = 0.0f; + m_zoomDelta = 0.0f; + m_moveDelta = 0.0f; + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + iJumpSpectator = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + + gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); + gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); + gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); + gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); + gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); + + m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); + m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); + m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); + m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); + m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); + + if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip) + { + gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); + return 0; + } + + return 1; +} + + +//----------------------------------------------------------------------------- +// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed +//----------------------------------------------------------------------------- + +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++ ) + { + pVector[j] = atof( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + + if (j < 2) + { + for (j = j+1;j < 3; j++) + pVector[j] = 0; + } +} + +int UTIL_FindEntityInMap(char * name, float * origin, float * angle) +{ + int n,found = 0; + char keyname[256]; + char token[2048]; + + cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + + if ( !pEnt ) return 0; + + if ( !pEnt->model ) return 0; + + char * data = pEnt->model->entities; + + while (data) + { + data = gEngfuncs.COM_ParseFile(data, token); + + if ( (token[0] == '}') || (token[0]==0) ) + break; + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + } + + if (token[0] != '{') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); + return 0; + } + + // we parse the first { now parse entities properties + + while ( 1 ) + { + // parse key + data = gEngfuncs.COM_ParseFile(data, token); + if (token[0] == '}') + break; // finish parsing this entity + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + strcpy (keyname, token); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = gEngfuncs.COM_ParseFile(data, token); + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + if (token[0] == '}') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); + return 0; + } + + if (!strcmp(keyname,"classname")) + { + if (!strcmp(token, name )) + { + found = 1; // thats our entity + } + }; + + if( !strcmp( keyname, "angle" ) ) + { + float y = atof( token ); + + if (y >= 0) + { + angle[0] = 0.0f; + angle[1] = y; + } + else if ((int)y == -1) + { + angle[0] = -90.0f; + angle[1] = 0.0f;; + } + else + { + angle[0] = 90.0f; + angle[1] = 0.0f; + } + + angle[2] = 0.0f; + } + + if( !strcmp( keyname, "angles" ) ) + { + UTIL_StringToVector(angle, token); + } + + if (!strcmp(keyname,"origin")) + { + UTIL_StringToVector(origin, token); + + }; + + } // while (1) + + if (found) + return 1; + + } + + return 0; // we search all entities, but didn't found the correct + +} + +//----------------------------------------------------------------------------- +// SetSpectatorStartPosition(): +// Get valid map position and 'beam' spectator to this position +//----------------------------------------------------------------------------- + +void CHudSpectator::SetSpectatorStartPosition() +{ + // search for info_player start + if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else + { + // jump to 0,0,0 if no better position was found + VectorCopy(vec3_origin, m_cameraOrigin); + VectorCopy(vec3_origin, m_cameraAngles); + } + + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + + iJumpSpectator = 1; // jump anyway +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudSpectator::VidInit() +{ + m_hsprPlayer = SPR_Load("sprites/iplayer.spr"); + m_hsprPlayerBlue = SPR_Load("sprites/iplayerblue.spr"); + m_hsprPlayerRed = SPR_Load("sprites/iplayerred.spr"); + m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); + m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); + m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); + m_hsprCamera = SPR_Load("sprites/camera.spr"); + m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudSpectator::Draw(float flTime) +{ + int lx; + + char string[256]; + float * color; + + // draw only in spectator mode + if ( !g_iUser1 ) + return 0; + + // if user pressed zoom, aplly changes + if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) + { + m_mapZoom += m_zoomDelta; + + if ( m_mapZoom > 3.0f ) + m_mapZoom = 3.0f; + + if ( m_mapZoom < 0.5f ) + m_mapZoom = 0.5f; + } + + // if user moves in map mode, change map origin + if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) + { + vec3_t right; + AngleVectors(v_angles, NULL, right, NULL); + VectorNormalize(right); + VectorScale(right, m_moveDelta, right ); + + VectorAdd( m_mapOrigin, right, m_mapOrigin ) + + } + + // Only draw the icon names only if map mode is in Main Mode + if ( g_iUser1 < OBS_MAP_FREE ) + return 1; + + if ( !m_drawnames->value ) + return 1; + + // make sure we have player info + //gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + + // loop through all the players and draw additional infos to their sprites on the map + for (int i = 0; i < MAX_PLAYERS; i++) + { + + if ( m_vPlayerPos[i][2]<0 ) // marked as invisible ? + continue; + + // check if name would be in inset window + if ( m_pip->value != INSET_OFF ) + { + if ( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && + m_vPlayerPos[i][1] > YRES( m_OverviewData.insetWindowY ) && + m_vPlayerPos[i][0] < XRES( m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth ) && + m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) + ) continue; + } + + color = GetClientColor( i+1 ); + + // draw the players name and health underneath + sprintf(string, "%s", g_PlayerInfoList[i+1].name ); + + lx = strlen(string)*3; // 3 is avg. character length :) + + DrawSetTextColor( color[0], color[1], color[2] ); + DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); + + } + + return 1; +} + + +void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) +{ + float value; + char * string; + + BEGIN_READ( pbuf, iSize ); + + int cmd = READ_BYTE(); + + switch ( cmd ) // director command byte + { + case DRC_CMD_START : + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + // fake a InitHUD & ResetHUD message + gHUD.MsgFunc_InitHUD(NULL,0, NULL); + gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); + + break; + + case DRC_CMD_EVENT : + m_lastPrimaryObject = READ_WORD(); + m_lastSecondaryObject = READ_WORD(); + m_iObserverFlags = READ_LONG(); + + if ( m_autoDirector->value ) + { + if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) + V_ResetChaseCam(); + + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + + // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); + break; + + case DRC_CMD_MODE : + if ( m_autoDirector->value ) + { + SetModes( READ_BYTE(), -1 ); + } + break; + + case DRC_CMD_CAMERA : + if ( m_autoDirector->value ) + { + vJumpOrigin[0] = READ_COORD(); // position + vJumpOrigin[1] = READ_COORD(); + vJumpOrigin[2] = READ_COORD(); + + vJumpAngles[0] = READ_COORD(); // view angle + vJumpAngles[1] = READ_COORD(); + vJumpAngles[2] = READ_COORD(); + + gEngfuncs.SetViewAngles( vJumpAngles ); + + iJumpSpectator = 1; + } + break; + + case DRC_CMD_MESSAGE: + { + client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + + msg->effect = READ_BYTE(); // effect + + UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color + msg->r2 = msg->r1; + msg->g2 = msg->g1; + msg->b2 = msg->b1; + msg->a2 = msg->a1 = 0xFF; // not transparent + + msg->x = READ_FLOAT(); // x pos + msg->y = READ_FLOAT(); // y pos + + msg->fadein = READ_FLOAT(); // fadein + msg->fadeout = READ_FLOAT(); // fadeout + msg->holdtime = READ_FLOAT(); // holdtime + msg->fxtime = READ_FLOAT(); // fxtime; + + strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); + m_HUDMessageText[m_lastHudMessage][127]=0; // text + + msg->pMessage = m_HUDMessageText[m_lastHudMessage]; + msg->pName = "HUD_MESSAGE"; + + gHUD.m_Message.MessageAdd( msg ); + + m_lastHudMessage++; + m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; + + } + + break; + + case DRC_CMD_SOUND : + string = READ_STRING(); + value = READ_FLOAT(); + + // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); + gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + + break; + + case DRC_CMD_TIMESCALE : + value = READ_FLOAT(); + break; + + + + case DRC_CMD_STATUS: + READ_LONG(); // total number of spectator slots + m_iSpectatorNumber = READ_LONG(); // total number of spectator + READ_WORD(); // total number of relay proxies + + break; + + case DRC_CMD_BANNER: + // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga + break; + + case DRC_CMD_FADE: + break; + + case DRC_CMD_STUFFTEXT: + ClientCmd( READ_STRING() ); + break; + + default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + } +} + +void CHudSpectator::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; + cl_entity_t * pEnt = NULL; + + // if we are NOT in HLTV mode, spectator targets are set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + char cmdstring[32]; + // forward command to server + sprintf(cmdstring,"follownext %i",bReverse?1:0); + gEngfuncs.pfnServerCmd(cmdstring); + return; + } + + if ( g_iUser2 ) + iStart = g_iUser2; + else + iStart = 1; + + g_iUser2 = 0; + + int iCurrent = iStart; + + int iDir = bReverse ? -1 : 1; + + // make sure we have player info + //gViewPort->GetAllPlayersInfo(); + gHUD.m_Scoreboard.GetAllPlayersInfo(); + + + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > MAX_PLAYERS) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = MAX_PLAYERS; + + pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); + + if ( !IsActivePlayer( pEnt ) ) + continue; + + // MOD AUTHORS: Add checks on target here. + + g_iUser2 = iCurrent; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( !g_iUser2 ) + { + gEngfuncs.Con_DPrintf( "No observer targets.\n" ); + // take save camera position + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + } + else + { + // use new entity position for roaming + VectorCopy ( pEnt->origin, vJumpOrigin ); + VectorCopy ( pEnt->angles, vJumpAngles ); + } + iJumpSpectator = 1; +} + +void CHudSpectator::HandleButtonsDown( int ButtonPressed ) +{ + double time = gEngfuncs.GetClientTime(); + + int newMainMode = g_iUser1; + int newInsetMode = m_pip->value; + + // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + + //Not in intermission. + if ( gHUD.m_iIntermission ) + return; + + if ( !g_iUser1 ) + return; // dont do anything if not in spectator mode + + // don't handle buttons during normal demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + return; + // Slow down mouse clicks. + if ( m_flNextObserverInput > time ) + return; + + // enable spectator screen + //if ( ButtonPressed & IN_DUCK ) + // gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); + + // 'Use' changes inset window mode + if ( ButtonPressed & IN_USE ) + { + newInsetMode = ToggleInset(true); + } + + // if not in HLTV mode, buttons are handled server side + if ( gEngfuncs.IsSpectateOnly() ) + { + // changing target or chase mode not in overviewmode without inset window + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + if ( g_iUser1 == OBS_CHASE_LOCKED ) + newMainMode = OBS_CHASE_FREE; + + else if ( g_iUser1 == OBS_CHASE_FREE ) + newMainMode = OBS_IN_EYE; + + else if ( g_iUser1 == OBS_IN_EYE ) + newMainMode = OBS_ROAMING; + + else if ( g_iUser1 == OBS_ROAMING ) + newMainMode = OBS_MAP_FREE; + + else if ( g_iUser1 == OBS_MAP_FREE ) + newMainMode = OBS_MAP_CHASE; + + else + newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore + } + + // Attack moves to the next player + if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + { + FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + + if ( g_iUser1 == OBS_ROAMING ) + { + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + + } + // lease directed mode if player want to see another player + m_autoDirector->value = 0.0f; + } + } + + SetModes(newMainMode, newInsetMode); + + if ( g_iUser1 == OBS_MAP_FREE ) + { + if ( ButtonPressed & IN_FORWARD ) + m_zoomDelta = 0.01f; + + if ( ButtonPressed & IN_BACK ) + m_zoomDelta = -0.01f; + + if ( ButtonPressed & IN_MOVELEFT ) + m_moveDelta = -12.0f; + + if ( ButtonPressed & IN_MOVERIGHT ) + m_moveDelta = 12.0f; + } + + m_flNextObserverInput = time + 0.2; +} + +void CHudSpectator::HandleButtonsUp( int ButtonPressed ) +{ + + if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) + m_zoomDelta = 0.0f; + + if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + m_moveDelta = 0.0f; +} + +void CHudSpectator::SetModes(int iNewMainMode, int iNewInsetMode) +{ + // if value == -1 keep old value + if ( iNewMainMode == -1 ) + iNewMainMode = g_iUser1; + + if ( iNewInsetMode == -1 ) + iNewInsetMode = m_pip->value; + + // inset mode is handled only clients side + m_pip->value = iNewInsetMode; + + if ( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) + { + gEngfuncs.Con_Printf("Invalid spectator mode.\n"); + return; + } + + // main modes ettings will override inset window settings + if ( iNewMainMode != g_iUser1 ) + { + // if we are NOT in HLTV mode, main spectator mode is set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + return; + } + + if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + { + // choose last Director object if still available + if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + { + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + else + FindNextPlayer(false); // find any target + } + + switch ( iNewMainMode ) + { + case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; + break; + + case OBS_CHASE_FREE : g_iUser1 = OBS_CHASE_FREE; + break; + + case OBS_ROAMING : // jump to current vJumpOrigin/angle + g_iUser1 = OBS_ROAMING; + if ( g_iUser2 ) + { + V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; + + case OBS_IN_EYE : g_iUser1 = OBS_IN_EYE; + break; + + case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + + case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + } + + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + char string[128]; + sprintf(string, "#Spec_Mode%d", g_iUser1 ); + sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + +} + +bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) +{ + return ( ent && + ent->player && + ent->curstate.solid != SOLID_NOT && + ent != gEngfuncs.GetLocalPlayer() && + g_PlayerInfoList[ent->index].name != NULL + ); +} + + +bool CHudSpectator::ParseOverviewFile( ) +{ + char filename[255] = { 0 }; + char levelname[255] = { 0 }; + char token[1024] = { 0 }; + float height; + + char *pfile = NULL; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + + // fill in standrd values + m_OverviewData.insetWindowX = 4; // upper left corner + m_OverviewData.insetWindowY = 4; + m_OverviewData.insetWindowHeight = 180; + m_OverviewData.insetWindowWidth = 240; + m_OverviewData.origin[0] = 0.0f; + m_OverviewData.origin[1] = 0.0f; + m_OverviewData.origin[2] = 0.0f; + m_OverviewData.zoom = 1.0f; + m_OverviewData.layers = 0; + m_OverviewData.layersHeights[0] = 0.0f; + strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); + + if ( strlen( m_OverviewData.map ) == 0 ) + return false; // not active yet + + strcpy(levelname, m_OverviewData.map + 5); + levelname[strlen(levelname)-4] = 0; + + sprintf(filename, "overviews/%s.txt", levelname ); + + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + + if (!pfile) + { + gEngfuncs.Con_DPrintf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + return false; + } + + + while (true) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if (!pfile) + break; + + if ( !stricmp( token, "global" ) ) + { + // parse the global data + pfile = gEngfuncs.COM_ParseFile(pfile, token); + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "zoom" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.zoom = atof( token ); + } + else if ( !stricmp( token, "origin" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[0] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.origin[1] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[2] = atof( token ); + } + else if ( !stricmp( token, "rotated" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.rotated = atoi( token ); + } + else if ( !stricmp( token, "inset" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowX = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowY = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowWidth = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowHeight = atof( token ); + + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + + } + } + else if ( !stricmp( token, "layer" ) ) + { + // parse a layer data + + if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "image" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); + + + } + else if ( !stricmp( token, "height" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + height = atof(token); + m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + } + + m_OverviewData.layers++; + + } + } + + gEngfuncs.COM_FreeFile( pfile ); + + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + + return true; + +} + +void CHudSpectator::LoadMapSprites() +{ + // right now only support for one map layer + if (m_OverviewData.layers > 0 ) + { + m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); + } + else + m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead +} + +void CHudSpectator::DrawOverviewLayer() +{ + float screenaspect, xs, ys, xStep, yStep, x,y,z; + int ix,iy,i,xTiles,yTiles,frame; + + qboolean hasMapImage = m_MapSprite?TRUE:FALSE; + model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); + + if ( hasMapImage) + { + i = m_MapSprite->numframes / (4*3); + i = sqrt(i); + xTiles = i*4; + yTiles = i*3; + } + else + { + xTiles = 8; + yTiles = 6; + } + + + screenaspect = 4.0f/3.0f; + + + xs = m_OverviewData.origin[0]; + ys = m_OverviewData.origin[1]; + z = ( 90.0f - v_angles[0] ) / 90.0f; + z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; + + // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); + + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + frame = 0; + + + // rotated view ? + if ( m_OverviewData.rotated ) + { + xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); + + for (iy = 0; iy < yTiles; iy++) + { + x = xs - (4096.0f / (m_OverviewData.zoom)); + + for (ix = 0; ix < xTiles; ix++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + x+= xStep; + } + + y+=yStep; + } + } + else + { + xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + + x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); + + + + for (ix = 0; ix < yTiles; ix++) + { + + y = ys + (4096.0f / (m_OverviewData.zoom)); + + for (iy = 0; iy < xTiles; iy++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + + y+=yStep; + } + + x+= xStep; + + } + } +} + +void CHudSpectator::DrawOverviewEntities() +{ + int i,ir,ig,ib; + struct model_s *hSpriteModel; + vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; + float x,y,z, r,g,b, sizeScale = 4.0f; + cl_entity_t * ent; + float rmatrix[3][4]; // transformation matrix + + float zScale = (90.0f - v_angles[0] ) / 90.0f; + + + z = m_OverviewData.layersHeights[0] * zScale; + // get yellow/brown HUD color + UnpackRGB(ir,ig,ib, RGB_YELLOWISH); + r = (float)ir/255.0f; + g = (float)ig/255.0f; + b = (float)ib/255.0f; + + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + + for (i=0; i < MAX_PLAYERS; i++ ) + m_vPlayerPos[i][2] = -1; // mark as invisible + + // draw all players + for (i=0 ; i < MAX_OVERVIEW_ENTITIES ; i++) + { + if ( !m_OverviewEntities[i].hSprite ) + continue; + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); + ent = m_OverviewEntities[i].entity; + + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + + // see R_DrawSpriteModel + // draws players sprite + + AngleVectors(ent->angles, right, up, NULL ); + + VectorCopy(ent->origin,origin); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (1,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->End (); + + + if ( !ent->player) + continue; + // draw line under player icons + origin[2] *= zScale; + + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + // calculate screen position for name and infromation in hud::draw() + if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) + continue; // object is behind viewer + + screen[0] = XPROJECT(screen[0]); + screen[1] = YPROJECT(screen[1]); + screen[2] = 0.0f; + + // calculate some offset under the icon + origin[0]+=32.0f; + origin[1]+=32.0f; + + gEngfuncs.pTriAPI->WorldToScreen(origin,offset); + + offset[0] = XPROJECT(offset[0]); + offset[1] = YPROJECT(offset[1]); + offset[2] = 0.0f; + + VectorSubtract(offset, screen, offset ); + + int playerNum = ent->index - 1; + + m_vPlayerPos[playerNum][0] = screen[0]; + m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); + m_vPlayerPos[playerNum][2] = 1; // mark player as visible + } + + if ( !m_pip->value || !m_drawcone->value ) + return; + + // get current camera position and angle + + if ( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) + { + V_GetInEyePos( g_iUser2, origin, angles ); + } + else if ( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) + { + V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); + } + else if ( g_iUser1 == OBS_ROAMING ) + { + VectorCopy( v_sim_org, origin ); + VectorCopy( v_cl_angles, angles ); + } + else + V_GetChasePos( g_iUser2, NULL, origin, angles ); + + + // draw camera sprite + + x = origin[0]; + y = origin[1]; + z = origin[2]; + + angles[0] = 0; // always show horizontal camera sprite + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + + gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); + + AngleVectors(angles, forward, NULL, NULL ); + VectorScale (forward, 512.0f, forward); + + offset[0] = 0.0f; + offset[1] = 45.0f; + offset[2] = 0.0f; + + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , right ); + + offset[1]= -45.0f; + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , left ); + + gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); + gEngfuncs.pTriAPI->End (); + +} + + + +void CHudSpectator::DrawOverview() +{ + // draw only in sepctator mode + if ( !g_iUser1 ) + return; + + // Only draw the overview if Map Mode is selected for this view + if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) + return; + + if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) + return; + + DrawOverviewLayer(); + DrawOverviewEntities(); + CheckOverviewEntities(); +} +void CHudSpectator::CheckOverviewEntities() +{ + double time = gEngfuncs.GetClientTime(); + + // removes old entities from list + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // remove entity from list if it is too old + if ( m_OverviewEntities[i].killTime < time ) + { + memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); + } + } +} + +bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) +{ + HSPRITE hSprite = 0; + double duration = -1.0f; // duration -1 means show it only this frame; + + if ( !ent ) + return false; + + if ( type == ET_PLAYER ) + { + if ( ent->curstate.solid != SOLID_NOT) + { + switch ( g_PlayerExtraInfo[ent->index].teamnumber ) + { + // blue and red teams are swapped in CS and TFC + case 1 : hSprite = m_hsprPlayerBlue; break; + case 2 : hSprite = m_hsprPlayerRed; break; + default : hSprite = m_hsprPlayer; break; + } + } + else + return false; // it's an spectator + } + else if (type == ET_NORMAL) + { + return false; + } + else + return false; + + return AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration ); +} + +void CHudSpectator::DeathMessage(int victim) +{ + // find out where the victim is + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); + + if (pl && pl->player) + AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); +} + +bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) +{ + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // find empty entity slot + if ( m_OverviewEntities[i].entity == NULL) + { + m_OverviewEntities[i].entity = ent; + m_OverviewEntities[i].hSprite = sprite; + m_OverviewEntities[i].killTime = killTime; + return true; + } + } + + return false; // maximum overview entities reached +} +void CHudSpectator::CheckSettings() +{ + // disallow same inset mode as main mode: + + m_pip->value = (int)m_pip->value; + + if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) + { + // otherwise both would show in World picures + m_pip->value = INSET_MAP_FREE; + } + + if ( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) + { + // both would show map views + m_pip->value = INSET_CHASE_FREE; + } + + // disble in intermission screen + if ( gHUD.m_iIntermission ) + m_pip->value = INSET_OFF; + + // check chat mode + if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) + { + // hud_saytext changed + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // tell proxy our new chat mode + char chatcmd[32]; + sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); + gEngfuncs.pfnServerCmd(chatcmd); + } + } + + // HL/TFC has no oberserver corsshair, so set it client side + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + + + // if we are a real player on server don't allow inset window + // in First Person mode since this is our resticted forcecamera mode 2 + // team number 3 = SPECTATOR see player.h + + if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) + m_pip->value = INSET_OFF; + + // draw small border around inset view, adjust upper black bar +} + +int CHudSpectator::ToggleInset(bool allowOff) +{ + int newInsetMode = (int)m_pip->value + 1; + + if ( g_iUser1 < OBS_MAP_FREE ) + { + if ( newInsetMode > INSET_MAP_CHASE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_MAP_FREE; + } + + if ( newInsetMode == INSET_CHASE_FREE ) + newInsetMode = INSET_MAP_FREE; + } + else + { + if ( newInsetMode > INSET_IN_EYE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_CHASE_FREE; + } + } + + return newInsetMode; +} +void CHudSpectator::Reset() +{ + // Reset HUD + if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) + { + // update level overview if level changed + ParseOverviewFile(); + LoadMapSprites(); + } + + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + SetSpectatorStartPosition(); +} + +void CHudSpectator::InitHUDData() +{ + m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + m_lastHudMessage = 0; + m_iSpectatorNumber = 0; + iJumpSpectator = 0; + g_iUser1 = g_iUser2 = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) + m_autoDirector->value = 1.0f; + else + m_autoDirector->value = 0.0f; + + Reset(); + + SetModes( OBS_CHASE_FREE, INSET_OFF ); + + g_iUser2 = 0; // fake not target until first camera command + + // reset HUD FOV + gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); +} + diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 7f1a3610..11c7c34c 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -1,132 +1,132 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef SPECTATOR_H -#define SPECTATOR_H -#pragma once - -#include "cl_entity.h" - - - -#define INSET_OFF 0 -#define INSET_CHASE_FREE 1 -#define INSET_IN_EYE 2 -#define INSET_MAP_FREE 3 -#define INSET_MAP_CHASE 4 - -#define MAX_SPEC_HUD_MESSAGES 8 - - - -#define OVERVIEW_TILE_SIZE 128 // don't change this -#define OVERVIEW_MAX_LAYERS 1 - -//----------------------------------------------------------------------------- -// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) -//----------------------------------------------------------------------------- - -typedef struct overviewInfo_s { - char map[64]; // cl.levelname or empty - vec3_t origin; // center of map - float zoom; // zoom of map images - int layers; // how may layers do we have - float layersHeights[OVERVIEW_MAX_LAYERS]; - char layersImages[OVERVIEW_MAX_LAYERS][255]; - qboolean rotated; // are map images rotated (90 degrees) ? - - int insetWindowX; - int insetWindowY; - int insetWindowHeight; - int insetWindowWidth; -} overviewInfo_t; - -typedef struct overviewEntity_s { - - HSPRITE hSprite; - struct cl_entity_s * entity; - double killTime; -} overviewEntity_t; - -#define MAX_OVERVIEW_ENTITIES 128 - -class CHudSpectator : public CHudBase -{ -public: - void Reset(); - int ToggleInset(bool allowOff); - void CheckSettings(); - void InitHUDData( void ); - bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime); - void DeathMessage(int victim); - bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); - void CheckOverviewEntities(); - void DrawOverview(); - void DrawOverviewEntities(); - void GetMapPosition( float * returnvec ); - void DrawOverviewLayer(); - void LoadMapSprites(); - bool ParseOverviewFile(); - bool IsActivePlayer(cl_entity_t * ent); - void SetModes(int iMainMode, int iInsetMode); - void HandleButtonsDown(int ButtonPressed); - void HandleButtonsUp(int ButtonPressed); - void FindNextPlayer( bool bReverse ); - void DirectorMessage( int iSize, void *pbuf ); - void SetSpectatorStartPosition(); - int Init(); - int VidInit(); - - int Draw(float flTime); - - int m_iDrawCycle; - client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; - char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; - int m_lastHudMessage; - overviewInfo_t m_OverviewData; - overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; - int m_iObserverFlags; - int m_iSpectatorNumber; - - float m_mapZoom; // zoom the user currently uses - vec3_t m_mapOrigin; // origin where user rotates around - cvar_t * m_drawnames; - cvar_t * m_drawcone; - cvar_t * m_drawstatus; - cvar_t * m_autoDirector; - cvar_t * m_pip; - - - qboolean m_chatEnabled; - - vec3_t m_cameraOrigin; // a help camera - vec3_t m_cameraAngles; // and it's angles - - -private: - vec3_t m_vPlayerPos[MAX_PLAYERS]; - HSPRITE m_hsprPlayerBlue; - HSPRITE m_hsprPlayerRed; - HSPRITE m_hsprPlayer; - HSPRITE m_hsprCamera; - HSPRITE m_hsprPlayerDead; - HSPRITE m_hsprViewcone; - HSPRITE m_hsprUnkownMap; - HSPRITE m_hsprBeam; - HSPRITE m_hCrosshair; - - wrect_t m_crosshairRect; - - struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame - float m_flNextObserverInput; - float m_zoomDelta; - float m_moveDelta; - int m_lastPrimaryObject; - int m_lastSecondaryObject; -}; - -#endif // SPECTATOR_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SPECTATOR_H +#define SPECTATOR_H +#pragma once + +#include "cl_entity.h" + + + +#define INSET_OFF 0 +#define INSET_CHASE_FREE 1 +#define INSET_IN_EYE 2 +#define INSET_MAP_FREE 3 +#define INSET_MAP_CHASE 4 + +#define MAX_SPEC_HUD_MESSAGES 8 + + + +#define OVERVIEW_TILE_SIZE 128 // don't change this +#define OVERVIEW_MAX_LAYERS 1 + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) +//----------------------------------------------------------------------------- + +typedef struct overviewInfo_s { + char map[64]; // cl.levelname or empty + vec3_t origin; // center of map + float zoom; // zoom of map images + int layers; // how may layers do we have + float layersHeights[OVERVIEW_MAX_LAYERS]; + char layersImages[OVERVIEW_MAX_LAYERS][255]; + qboolean rotated; // are map images rotated (90 degrees) ? + + int insetWindowX; + int insetWindowY; + int insetWindowHeight; + int insetWindowWidth; +} overviewInfo_t; + +typedef struct overviewEntity_s { + + HSPRITE hSprite; + struct cl_entity_s * entity; + double killTime; +} overviewEntity_t; + +#define MAX_OVERVIEW_ENTITIES 128 + +class CHudSpectator : public CHudBase +{ +public: + void Reset(); + int ToggleInset(bool allowOff); + void CheckSettings(); + void InitHUDData( void ); + bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime); + void DeathMessage(int victim); + bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void CheckOverviewEntities(); + void DrawOverview(); + void DrawOverviewEntities(); + void GetMapPosition( float * returnvec ); + void DrawOverviewLayer(); + void LoadMapSprites(); + bool ParseOverviewFile(); + bool IsActivePlayer(cl_entity_t * ent); + void SetModes(int iMainMode, int iInsetMode); + void HandleButtonsDown(int ButtonPressed); + void HandleButtonsUp(int ButtonPressed); + void FindNextPlayer( bool bReverse ); + void DirectorMessage( int iSize, void *pbuf ); + void SetSpectatorStartPosition(); + int Init(); + int VidInit(); + + int Draw(float flTime); + + int m_iDrawCycle; + client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; + char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; + int m_lastHudMessage; + overviewInfo_t m_OverviewData; + overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; + int m_iObserverFlags; + int m_iSpectatorNumber; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + cvar_t * m_drawnames; + cvar_t * m_drawcone; + cvar_t * m_drawstatus; + cvar_t * m_autoDirector; + cvar_t * m_pip; + + + qboolean m_chatEnabled; + + vec3_t m_cameraOrigin; // a help camera + vec3_t m_cameraAngles; // and it's angles + + +private: + vec3_t m_vPlayerPos[MAX_PLAYERS]; + HSPRITE m_hsprPlayerBlue; + HSPRITE m_hsprPlayerRed; + HSPRITE m_hsprPlayer; + HSPRITE m_hsprCamera; + HSPRITE m_hsprPlayerDead; + HSPRITE m_hsprViewcone; + HSPRITE m_hsprUnkownMap; + HSPRITE m_hsprBeam; + HSPRITE m_hCrosshair; + + wrect_t m_crosshairRect; + + struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame + float m_flNextObserverInput; + float m_zoomDelta; + float m_moveDelta; + int m_lastPrimaryObject; + int m_lastSecondaryObject; +}; + +#endif // SPECTATOR_H diff --git a/cl_dll/hud_update.cpp b/cl_dll/hud_update.cpp index b3da6721..9facc8c7 100644 --- a/cl_dll/hud_update.cpp +++ b/cl_dll/hud_update.cpp @@ -1,54 +1,54 @@ -/*** -* -* 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. -* -****/ -// -// hud_update.cpp -// - -#include -#include "hud.h" -#include "cl_util.h" -#include -#include - -int CL_ButtonBits( int ); -void CL_ResetButtonBits( int bits ); - -extern float v_idlescale; -float in_fov; -extern void HUD_SetCmdBits( int bits ); - -int CHud::UpdateClientData(client_data_t *cdata, float time) -{ - memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); - memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); - - m_iKeyBits = CL_ButtonBits( 0 ); - m_iWeaponBits = cdata->iWeaponBits; - - in_fov = cdata->fov; - - Think(); - - cdata->fov = m_iFOV; - - v_idlescale = m_iConcussionEffect; - - CL_ResetButtonBits( m_iKeyBits ); - - // return 1 if in anything in the client_data struct has been changed, 0 otherwise - return 1; -} - - +/*** +* +* 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. +* +****/ +// +// hud_update.cpp +// + +#include +#include "hud.h" +#include "cl_util.h" +#include +#include + +int CL_ButtonBits( int ); +void CL_ResetButtonBits( int bits ); + +extern float v_idlescale; +float in_fov; +extern void HUD_SetCmdBits( int bits ); + +int CHud::UpdateClientData(client_data_t *cdata, float time) +{ + memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); + memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); + + m_iKeyBits = CL_ButtonBits( 0 ); + m_iWeaponBits = cdata->iWeaponBits; + + in_fov = cdata->fov; + + Think(); + + cdata->fov = m_iFOV; + + v_idlescale = m_iConcussionEffect; + + CL_ResetButtonBits( m_iKeyBits ); + + // return 1 if in anything in the client_data struct has been changed, 0 otherwise + return 1; +} + + diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp index c85631c3..fb6a6735 100644 --- a/cl_dll/in_camera.cpp +++ b/cl_dll/in_camera.cpp @@ -1,620 +1,620 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" -#include "camera.h" -#include "in_defs.h" - - -float CL_KeyState (kbutton_t *key); - -extern "C" -{ - void DLLEXPORT CAM_Think( void ); - int DLLEXPORT CL_IsThirdPerson( void ); - void DLLEXPORT CL_CameraOffset( float *ofs ); -} - -extern cl_enginefunc_t gEngfuncs; - -//-------------------------------------------------- Constants - -#define CAM_DIST_DELTA 1.0 -#define CAM_ANGLE_DELTA 2.5 -#define CAM_ANGLE_SPEED 2.5 -#define CAM_MIN_DIST 30.0 -#define CAM_ANGLE_MOVE .5 -#define MAX_ANGLE_DIFF 10.0 -#define PITCH_MAX 90.0 -#define PITCH_MIN 0 -#define YAW_MAX 135.0 -#define YAW_MIN -135.0 - -enum ECAM_Command -{ - CAM_COMMAND_NONE = 0, - CAM_COMMAND_TOTHIRDPERSON = 1, - CAM_COMMAND_TOFIRSTPERSON = 2 -}; - -//-------------------------------------------------- Global Variables - -cvar_t *cam_command; -cvar_t *cam_snapto; -cvar_t *cam_idealyaw; -cvar_t *cam_idealpitch; -cvar_t *cam_idealdist; -cvar_t *cam_contain; - -cvar_t *c_maxpitch; -cvar_t *c_minpitch; -cvar_t *c_maxyaw; -cvar_t *c_minyaw; -cvar_t *c_maxdistance; -cvar_t *c_mindistance; - -// pitch, yaw, dist -vec3_t cam_ofs; - - -// In third person -int cam_thirdperson; -int cam_mousemove; //true if we are moving the cam with the mouse, False if not -int iMouseInUse=0; -int cam_distancemove; -extern int mouse_x, mouse_y; //used to determine what the current x and y values are -int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement -POINT cam_mouse; -//-------------------------------------------------- Local Variables - -static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; -static kbutton_t cam_in, cam_out, cam_move; - -//-------------------------------------------------- Prototypes - -void CAM_ToThirdPerson(void); -void CAM_ToFirstPerson(void); -void CAM_StartDistance(void); -void CAM_EndDistance(void); - - -//-------------------------------------------------- Local Functions - -float MoveToward( float cur, float goal, float maxspeed ) -{ - if( cur != goal ) - { - if( fabs( cur - goal ) > 180.0 ) - { - if( cur < goal ) - cur += 360.0; - else - cur -= 360.0; - } - - if( cur < goal ) - { - if( cur < goal - 1.0 ) - cur += ( goal - cur ) / 4.0; - else - cur = goal; - } - else - { - if( cur > goal + 1.0 ) - cur -= ( cur - goal ) / 4.0; - else - cur = goal; - } - } - - - // bring cur back into range - if( cur < 0 ) - cur += 360.0; - else if( cur >= 360 ) - cur -= 360; - - return cur; -} - - -//-------------------------------------------------- Gobal Functions - -typedef struct -{ - vec3_t boxmins, boxmaxs;// enclose the test object along entire move - float *mins, *maxs; // size of the moving object - vec3_t mins2, maxs2; // size when clipping against mosnters - float *start, *end; - trace_t trace; - int type; - edict_t *passedict; - qboolean monsterclip; -} moveclip_t; - -extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); - -void DLLEXPORT CAM_Think( void ) -{ - vec3_t origin; - vec3_t ext, pnt, camForward, camRight, camUp; - moveclip_t clip; - float dist; - vec3_t camAngles; - float flSensitivity; -#ifdef LATER - int i; -#endif - vec3_t viewangles; - - switch( (int) cam_command->value ) - { - case CAM_COMMAND_TOTHIRDPERSON: - CAM_ToThirdPerson(); - break; - - case CAM_COMMAND_TOFIRSTPERSON: - CAM_ToFirstPerson(); - break; - - case CAM_COMMAND_NONE: - default: - break; - } - - if( !cam_thirdperson ) - return; - -#ifdef LATER - if ( cam_contain->value ) - { - gEngfuncs.GetClientOrigin( origin ); - ext[0] = ext[1] = ext[2] = 0.0; - } -#endif - - camAngles[ PITCH ] = cam_idealpitch->value; - camAngles[ YAW ] = cam_idealyaw->value; - dist = cam_idealdist->value; - // - //movement of the camera with the mouse - // - if (cam_mousemove) - { - //get windows cursor position - GetCursorPos (&cam_mouse); - //check for X delta values and adjust accordingly - //eventually adjust YAW based on amount of movement - //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera - if (!cam_distancemove) - { - - //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) - if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) - { - //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) - if (camAngles[YAW]value) - { - camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); - } - if (camAngles[YAW]>c_maxyaw->value) - { - - camAngles[YAW]=c_maxyaw->value; - } - } - else if (cam_mouse.x225.0)) - if (camAngles[YAW]>c_minyaw->value) - { - camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); - - } - if (camAngles[YAW]value) - { - camAngles[YAW]=c_minyaw->value; - - } - } - - //check for y delta values and adjust accordingly - //eventually adjust PITCH based on amount of movement - //also make sure camera is within bounds - if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) - { - if(camAngles[PITCH]value) - { - camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); - } - if (camAngles[PITCH]>c_maxpitch->value) - { - camAngles[PITCH]=c_maxpitch->value; - } - } - else if (cam_mouse.yc_minpitch->value) - { - camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); - } - if (camAngles[PITCH]value) - { - camAngles[PITCH]=c_minpitch->value; - } - } - - //set old mouse coordinates to current mouse coordinates - //since we are done with the mouse - - if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) - { - cam_old_mouse_x=cam_mouse.x*flSensitivity; - cam_old_mouse_y=cam_mouse.y*flSensitivity; - } - else - { - cam_old_mouse_x=cam_mouse.x; - cam_old_mouse_y=cam_mouse.y; - } - SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); - } - } - - //Nathan code here - if( CL_KeyState( &cam_pitchup ) ) - camAngles[ PITCH ] += CAM_ANGLE_DELTA; - else if( CL_KeyState( &cam_pitchdown ) ) - camAngles[ PITCH ] -= CAM_ANGLE_DELTA; - - if( CL_KeyState( &cam_yawleft ) ) - camAngles[ YAW ] -= CAM_ANGLE_DELTA; - else if( CL_KeyState( &cam_yawright ) ) - camAngles[ YAW ] += CAM_ANGLE_DELTA; - - if( CL_KeyState( &cam_in ) ) - { - dist -= CAM_DIST_DELTA; - if( dist < CAM_MIN_DIST ) - { - // If we go back into first person, reset the angle - camAngles[ PITCH ] = 0; - camAngles[ YAW ] = 0; - dist = CAM_MIN_DIST; - } - - } - else if( CL_KeyState( &cam_out ) ) - dist += CAM_DIST_DELTA; - - if (cam_distancemove) - { - if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) - { - if(distvalue) - { - dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); - } - if (dist>c_maxdistance->value) - { - dist=c_maxdistance->value; - } - } - else if (cam_mouse.yc_mindistance->value) - { - dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); - } - if (distvalue) - { - dist=c_mindistance->value; - } - } - //set old mouse coordinates to current mouse coordinates - //since we are done with the mouse - cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); - cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); - SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); - } -#ifdef LATER - if( cam_contain->value ) - { - // check new ideal - VectorCopy( origin, pnt ); - AngleVectors( camAngles, camForward, camRight, camUp ); - for (i=0 ; i<3 ; i++) - pnt[i] += -dist*camForward[i]; - - // check line from r_refdef.vieworg to pnt - memset ( &clip, 0, sizeof ( moveclip_t ) ); - clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); - if( clip.trace.fraction == 1.0 ) - { - // update ideal - cam_idealpitch->value = camAngles[ PITCH ]; - cam_idealyaw->value = camAngles[ YAW ]; - cam_idealdist->value = dist; - } - } - else -#endif - { - // update ideal - cam_idealpitch->value = camAngles[ PITCH ]; - cam_idealyaw->value = camAngles[ YAW ]; - cam_idealdist->value = dist; - } - - // Move towards ideal - VectorCopy( cam_ofs, camAngles ); - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - if( cam_snapto->value ) - { - camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; - camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; - camAngles[ 2 ] = cam_idealdist->value; - } - else - { - if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) - camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); - - if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) - camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); - - if( fabs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) - camAngles[ 2 ] = cam_idealdist->value; - else - camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; - } -#ifdef LATER - if( cam_contain->value ) - { - // Test new position - dist = camAngles[ ROLL ]; - camAngles[ ROLL ] = 0; - - VectorCopy( origin, pnt ); - AngleVectors( camAngles, camForward, camRight, camUp ); - for (i=0 ; i<3 ; i++) - pnt[i] += -dist*camForward[i]; - - // check line from r_refdef.vieworg to pnt - memset ( &clip, 0, sizeof ( moveclip_t ) ); - ext[0] = ext[1] = ext[2] = 0.0; - clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); - if( clip.trace.fraction != 1.0 ) - return; - } -#endif - cam_ofs[ 0 ] = camAngles[ 0 ]; - cam_ofs[ 1 ] = camAngles[ 1 ]; - cam_ofs[ 2 ] = dist; -} - -extern void KeyDown (kbutton_t *b); // HACK -extern void KeyUp (kbutton_t *b); // HACK - -void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } -void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } -void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } -void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } -void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } -void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } -void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } -void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } -void CAM_InDown(void) { KeyDown( &cam_in ); } -void CAM_InUp(void) { KeyUp( &cam_in ); } -void CAM_OutDown(void) { KeyDown( &cam_out ); } -void CAM_OutUp(void) { KeyUp( &cam_out ); } - -void CAM_ToThirdPerson(void) -{ - vec3_t viewangles; - -#if !defined( _DEBUG ) - if ( gEngfuncs.GetMaxClients() > 1 ) - { - // no thirdperson in multiplayer. - return; - } -#endif - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - if( !cam_thirdperson ) - { - cam_thirdperson = 1; - - cam_ofs[ YAW ] = viewangles[ YAW ]; - cam_ofs[ PITCH ] = viewangles[ PITCH ]; - cam_ofs[ 2 ] = CAM_MIN_DIST; - } - - gEngfuncs.Cvar_SetValue( "cam_command", 0 ); -} - -void CAM_ToFirstPerson(void) -{ - cam_thirdperson = 0; - - gEngfuncs.Cvar_SetValue( "cam_command", 0 ); -} - -void CAM_ToggleSnapto( void ) -{ - cam_snapto->value = !cam_snapto->value; -} - -void CAM_Init( void ) -{ - gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown ); - gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp ); - gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown ); - gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp ); - gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown ); - gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp ); - gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown ); - gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp ); - gEngfuncs.pfnAddCommand( "+camin", CAM_InDown ); - gEngfuncs.pfnAddCommand( "-camin", CAM_InUp ); - gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown ); - gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp ); - gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson ); - gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson ); - gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove); - gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove); - gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance ); - gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); - gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); - - cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson - cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view - cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw - cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch - cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance - cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world - - c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); - c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); - c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); - c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); - c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); - c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); -} - -void CAM_ClearStates( void ) -{ - vec3_t viewangles; - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - cam_pitchup.state = 0; - cam_pitchdown.state = 0; - cam_yawleft.state = 0; - cam_yawright.state = 0; - cam_in.state = 0; - cam_out.state = 0; - - cam_thirdperson = 0; - cam_command->value = 0; - cam_mousemove=0; - - cam_snapto->value = 0; - cam_distancemove = 0; - - cam_ofs[ 0 ] = 0.0; - cam_ofs[ 1 ] = 0.0; - cam_ofs[ 2 ] = CAM_MIN_DIST; - - cam_idealpitch->value = viewangles[ PITCH ]; - cam_idealyaw->value = viewangles[ YAW ]; - cam_idealdist->value = CAM_MIN_DIST; -} - -void CAM_StartMouseMove(void) -{ - float flSensitivity; - - //only move the cam with mouse if we are in third person. - if (cam_thirdperson) - { - //set appropriate flags and initialize the old mouse position - //variables for mouse camera movement - if (!cam_mousemove) - { - cam_mousemove=1; - iMouseInUse=1; - GetCursorPos (&cam_mouse); - - if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) - { - cam_old_mouse_x=cam_mouse.x*flSensitivity; - cam_old_mouse_y=cam_mouse.y*flSensitivity; - } - else - { - cam_old_mouse_x=cam_mouse.x; - cam_old_mouse_y=cam_mouse.y; - } - } - } - //we are not in 3rd person view..therefore do not allow camera movement - else - { - cam_mousemove=0; - iMouseInUse=0; - } -} - -//the key has been released for camera movement -//tell the engine that mouse camera movement is off -void CAM_EndMouseMove(void) -{ - cam_mousemove=0; - iMouseInUse=0; -} - - -//---------------------------------------------------------- -//routines to start the process of moving the cam in or out -//using the mouse -//---------------------------------------------------------- -void CAM_StartDistance(void) -{ - //only move the cam with mouse if we are in third person. - if (cam_thirdperson) - { - //set appropriate flags and initialize the old mouse position - //variables for mouse camera movement - if (!cam_distancemove) - { - cam_distancemove=1; - cam_mousemove=1; - iMouseInUse=1; - GetCursorPos (&cam_mouse); - cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); - cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); - } - } - //we are not in 3rd person view..therefore do not allow camera movement - else - { - cam_distancemove=0; - cam_mousemove=0; - iMouseInUse=0; - } -} - -//the key has been released for camera movement -//tell the engine that mouse camera movement is off -void CAM_EndDistance(void) -{ - cam_distancemove=0; - cam_mousemove=0; - iMouseInUse=0; -} - -int DLLEXPORT CL_IsThirdPerson( void ) -{ - return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) ); -} - -void DLLEXPORT CL_CameraOffset( float *ofs ) -{ - VectorCopy( cam_ofs, ofs ); -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" + + +float CL_KeyState (kbutton_t *key); + +extern "C" +{ + void DLLEXPORT CAM_Think( void ); + int DLLEXPORT CL_IsThirdPerson( void ); + void DLLEXPORT CL_CameraOffset( float *ofs ); +} + +extern cl_enginefunc_t gEngfuncs; + +//-------------------------------------------------- Constants + +#define CAM_DIST_DELTA 1.0 +#define CAM_ANGLE_DELTA 2.5 +#define CAM_ANGLE_SPEED 2.5 +#define CAM_MIN_DIST 30.0 +#define CAM_ANGLE_MOVE .5 +#define MAX_ANGLE_DIFF 10.0 +#define PITCH_MAX 90.0 +#define PITCH_MIN 0 +#define YAW_MAX 135.0 +#define YAW_MIN -135.0 + +enum ECAM_Command +{ + CAM_COMMAND_NONE = 0, + CAM_COMMAND_TOTHIRDPERSON = 1, + CAM_COMMAND_TOFIRSTPERSON = 2 +}; + +//-------------------------------------------------- Global Variables + +cvar_t *cam_command; +cvar_t *cam_snapto; +cvar_t *cam_idealyaw; +cvar_t *cam_idealpitch; +cvar_t *cam_idealdist; +cvar_t *cam_contain; + +cvar_t *c_maxpitch; +cvar_t *c_minpitch; +cvar_t *c_maxyaw; +cvar_t *c_minyaw; +cvar_t *c_maxdistance; +cvar_t *c_mindistance; + +// pitch, yaw, dist +vec3_t cam_ofs; + + +// In third person +int cam_thirdperson; +int cam_mousemove; //true if we are moving the cam with the mouse, False if not +int iMouseInUse=0; +int cam_distancemove; +extern int mouse_x, mouse_y; //used to determine what the current x and y values are +int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement +POINT cam_mouse; +//-------------------------------------------------- Local Variables + +static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; +static kbutton_t cam_in, cam_out, cam_move; + +//-------------------------------------------------- Prototypes + +void CAM_ToThirdPerson(void); +void CAM_ToFirstPerson(void); +void CAM_StartDistance(void); +void CAM_EndDistance(void); + + +//-------------------------------------------------- Local Functions + +float MoveToward( float cur, float goal, float maxspeed ) +{ + if( cur != goal ) + { + if( fabs( cur - goal ) > 180.0 ) + { + if( cur < goal ) + cur += 360.0; + else + cur -= 360.0; + } + + if( cur < goal ) + { + if( cur < goal - 1.0 ) + cur += ( goal - cur ) / 4.0; + else + cur = goal; + } + else + { + if( cur > goal + 1.0 ) + cur -= ( cur - goal ) / 4.0; + else + cur = goal; + } + } + + + // bring cur back into range + if( cur < 0 ) + cur += 360.0; + else if( cur >= 360 ) + cur -= 360; + + return cur; +} + + +//-------------------------------------------------- Gobal Functions + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; + qboolean monsterclip; +} moveclip_t; + +extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + +void DLLEXPORT CAM_Think( void ) +{ + vec3_t origin; + vec3_t ext, pnt, camForward, camRight, camUp; + moveclip_t clip; + float dist; + vec3_t camAngles; + float flSensitivity; +#ifdef LATER + int i; +#endif + vec3_t viewangles; + + switch( (int) cam_command->value ) + { + case CAM_COMMAND_TOTHIRDPERSON: + CAM_ToThirdPerson(); + break; + + case CAM_COMMAND_TOFIRSTPERSON: + CAM_ToFirstPerson(); + break; + + case CAM_COMMAND_NONE: + default: + break; + } + + if( !cam_thirdperson ) + return; + +#ifdef LATER + if ( cam_contain->value ) + { + gEngfuncs.GetClientOrigin( origin ); + ext[0] = ext[1] = ext[2] = 0.0; + } +#endif + + camAngles[ PITCH ] = cam_idealpitch->value; + camAngles[ YAW ] = cam_idealyaw->value; + dist = cam_idealdist->value; + // + //movement of the camera with the mouse + // + if (cam_mousemove) + { + //get windows cursor position + GetCursorPos (&cam_mouse); + //check for X delta values and adjust accordingly + //eventually adjust YAW based on amount of movement + //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera + if (!cam_distancemove) + { + + //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) + if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) + { + //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) + if (camAngles[YAW]value) + { + camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); + } + if (camAngles[YAW]>c_maxyaw->value) + { + + camAngles[YAW]=c_maxyaw->value; + } + } + else if (cam_mouse.x225.0)) + if (camAngles[YAW]>c_minyaw->value) + { + camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); + + } + if (camAngles[YAW]value) + { + camAngles[YAW]=c_minyaw->value; + + } + } + + //check for y delta values and adjust accordingly + //eventually adjust PITCH based on amount of movement + //also make sure camera is within bounds + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(camAngles[PITCH]value) + { + camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (camAngles[PITCH]>c_maxpitch->value) + { + camAngles[PITCH]=c_maxpitch->value; + } + } + else if (cam_mouse.yc_minpitch->value) + { + camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (camAngles[PITCH]value) + { + camAngles[PITCH]=c_minpitch->value; + } + } + + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } + } + + //Nathan code here + if( CL_KeyState( &cam_pitchup ) ) + camAngles[ PITCH ] += CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_pitchdown ) ) + camAngles[ PITCH ] -= CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_yawleft ) ) + camAngles[ YAW ] -= CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_yawright ) ) + camAngles[ YAW ] += CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_in ) ) + { + dist -= CAM_DIST_DELTA; + if( dist < CAM_MIN_DIST ) + { + // If we go back into first person, reset the angle + camAngles[ PITCH ] = 0; + camAngles[ YAW ] = 0; + dist = CAM_MIN_DIST; + } + + } + else if( CL_KeyState( &cam_out ) ) + dist += CAM_DIST_DELTA; + + if (cam_distancemove) + { + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(distvalue) + { + dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (dist>c_maxdistance->value) + { + dist=c_maxdistance->value; + } + } + else if (cam_mouse.yc_mindistance->value) + { + dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (distvalue) + { + dist=c_mindistance->value; + } + } + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } +#ifdef LATER + if( cam_contain->value ) + { + // check new ideal + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction == 1.0 ) + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + } + else +#endif + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + + // Move towards ideal + VectorCopy( cam_ofs, camAngles ); + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( cam_snapto->value ) + { + camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; + camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; + camAngles[ 2 ] = cam_idealdist->value; + } + else + { + if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) + camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); + + if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) + camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); + + if( fabs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) + camAngles[ 2 ] = cam_idealdist->value; + else + camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; + } +#ifdef LATER + if( cam_contain->value ) + { + // Test new position + dist = camAngles[ ROLL ]; + camAngles[ ROLL ] = 0; + + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + ext[0] = ext[1] = ext[2] = 0.0; + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction != 1.0 ) + return; + } +#endif + cam_ofs[ 0 ] = camAngles[ 0 ]; + cam_ofs[ 1 ] = camAngles[ 1 ]; + cam_ofs[ 2 ] = dist; +} + +extern void KeyDown (kbutton_t *b); // HACK +extern void KeyUp (kbutton_t *b); // HACK + +void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } +void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } +void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } +void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } +void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } +void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } +void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } +void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } +void CAM_InDown(void) { KeyDown( &cam_in ); } +void CAM_InUp(void) { KeyUp( &cam_in ); } +void CAM_OutDown(void) { KeyDown( &cam_out ); } +void CAM_OutUp(void) { KeyUp( &cam_out ); } + +void CAM_ToThirdPerson(void) +{ + vec3_t viewangles; + +#if !defined( _DEBUG ) + if ( gEngfuncs.GetMaxClients() > 1 ) + { + // no thirdperson in multiplayer. + return; + } +#endif + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( !cam_thirdperson ) + { + cam_thirdperson = 1; + + cam_ofs[ YAW ] = viewangles[ YAW ]; + cam_ofs[ PITCH ] = viewangles[ PITCH ]; + cam_ofs[ 2 ] = CAM_MIN_DIST; + } + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToFirstPerson(void) +{ + cam_thirdperson = 0; + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToggleSnapto( void ) +{ + cam_snapto->value = !cam_snapto->value; +} + +void CAM_Init( void ) +{ + gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown ); + gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp ); + gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown ); + gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp ); + gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown ); + gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp ); + gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown ); + gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp ); + gEngfuncs.pfnAddCommand( "+camin", CAM_InDown ); + gEngfuncs.pfnAddCommand( "-camin", CAM_InUp ); + gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown ); + gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp ); + gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson ); + gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson ); + gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove); + gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove); + gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance ); + gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); + gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); + + cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson + cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view + cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw + cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch + cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance + cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world + + c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); + c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); + c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); + c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); + c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); + c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); +} + +void CAM_ClearStates( void ) +{ + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + cam_pitchup.state = 0; + cam_pitchdown.state = 0; + cam_yawleft.state = 0; + cam_yawright.state = 0; + cam_in.state = 0; + cam_out.state = 0; + + cam_thirdperson = 0; + cam_command->value = 0; + cam_mousemove=0; + + cam_snapto->value = 0; + cam_distancemove = 0; + + cam_ofs[ 0 ] = 0.0; + cam_ofs[ 1 ] = 0.0; + cam_ofs[ 2 ] = CAM_MIN_DIST; + + cam_idealpitch->value = viewangles[ PITCH ]; + cam_idealyaw->value = viewangles[ YAW ]; + cam_idealdist->value = CAM_MIN_DIST; +} + +void CAM_StartMouseMove(void) +{ + float flSensitivity; + + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_mousemove) + { + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndMouseMove(void) +{ + cam_mousemove=0; + iMouseInUse=0; +} + + +//---------------------------------------------------------- +//routines to start the process of moving the cam in or out +//using the mouse +//---------------------------------------------------------- +void CAM_StartDistance(void) +{ + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_distancemove) + { + cam_distancemove=1; + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndDistance(void) +{ + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; +} + +int DLLEXPORT CL_IsThirdPerson( void ) +{ + return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) ); +} + +void DLLEXPORT CL_CameraOffset( float *ofs ) +{ + VectorCopy( cam_ofs, ofs ); +} diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index 9f30b17a..c48cf373 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -1,30 +1,30 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( IN_DEFSH ) -#define IN_DEFSH -#pragma once - -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - -#ifdef _WIN32 -#include -#else -typedef struct point_s{ - int x; - int y; -} POINT; -#define GetCursorPos(x) -#define SetCursorPos(x,y) -#endif - -#endif +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( IN_DEFSH ) +#define IN_DEFSH +#pragma once + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#ifdef _WIN32 +#include +#else +typedef struct point_s{ + int x; + int y; +} POINT; +#define GetCursorPos(x) +#define SetCursorPos(x,y) +#endif + +#endif diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp index bb4ecbf3..f89f0232 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -1,1006 +1,1006 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// cl.input.c -- builds an intended movement command to send to the server - -//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed - -// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All -// rights reserved. -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -extern "C" -{ -#include "kbutton.h" -} -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" -#include "camera.h" -#include "in_defs.h" -#include "view.h" -#include -#include - - - -extern "C" -{ - struct kbutton_s DLLEXPORT *KB_Find( const char *name ); - void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); - void DLLEXPORT HUD_Shutdown( void ); - int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); -} - -extern int g_iAlive; - -extern int g_weaponselect; -extern cl_enginefunc_t gEngfuncs; - -// Defined in pm_math.c -extern "C" float anglemod( float a ); - -void IN_Init (void); -void IN_Move ( float frametime, usercmd_t *cmd); -void IN_Shutdown( void ); -void V_Init( void ); -void VectorAngles( const float *forward, float *angles ); -int CL_ButtonBits( int ); - -// xxx need client dll function to get and clear impuse -extern cvar_t *in_joystick; - -int in_impulse = 0; -int in_cancel = 0; - -cvar_t *m_pitch; -cvar_t *m_yaw; -cvar_t *m_forward; -cvar_t *m_side; - -cvar_t *lookstrafe; -cvar_t *lookspring; -cvar_t *cl_pitchup; -cvar_t *cl_pitchdown; -cvar_t *cl_upspeed; -cvar_t *cl_forwardspeed; -cvar_t *cl_backspeed; -cvar_t *cl_sidespeed; -cvar_t *cl_movespeedkey; -cvar_t *cl_yawspeed; -cvar_t *cl_pitchspeed; -cvar_t *cl_anglespeedkey; -cvar_t *cl_vsmoothing; -/* -=============================================================================== - -KEY BUTTONS - -Continuous button event tracking is complicated by the fact that two different -input sources (say, mouse button 1 and the control key) can both press the -same button, but the button should only be released when both of the -pressing key have been released. - -When a key event issues a button command (+forward, +attack, etc), it appends -its key number as a parameter to the command so it can be matched up with -the release. - -state bit 0 is the current state of the key -state bit 1 is edge triggered on the up to down transition -state bit 2 is edge triggered on the down to up transition - -=============================================================================== -*/ - - -kbutton_t in_mlook; -kbutton_t in_klook; -kbutton_t in_jlook; -kbutton_t in_left; -kbutton_t in_right; -kbutton_t in_forward; -kbutton_t in_back; -kbutton_t in_lookup; -kbutton_t in_lookdown; -kbutton_t in_moveleft; -kbutton_t in_moveright; -kbutton_t in_strafe; -kbutton_t in_speed; -kbutton_t in_use; -kbutton_t in_jump; -kbutton_t in_attack; -kbutton_t in_attack2; -kbutton_t in_up; -kbutton_t in_down; -kbutton_t in_duck; -kbutton_t in_reload; -kbutton_t in_alt1; -kbutton_t in_score; -kbutton_t in_break; -kbutton_t in_graph; // Display the netgraph - -typedef struct kblist_s -{ - struct kblist_s *next; - kbutton_t *pkey; - char name[32]; -} kblist_t; - -kblist_t *g_kbkeys = NULL; - -/* -============ -KB_ConvertString - -Removes references to +use and replaces them with the keyname in the output string. If - a binding is unfound, then the original text is retained. -NOTE: Only works for text with +word in it. -============ -*/ -int KB_ConvertString( char *in, char **ppout ) -{ - char sz[ 4096 ]; - char binding[ 64 ]; - char *p; - char *pOut; - char *pEnd; - const char *pBinding; - - if ( !ppout ) - return 0; - - *ppout = NULL; - p = in; - pOut = sz; - while ( *p ) - { - if ( *p == '+' ) - { - pEnd = binding; - while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) - { - *pEnd++ = *p++; - } - - *pEnd = '\0'; - - pBinding = NULL; - if ( strlen( binding + 1 ) > 0 ) - { - // See if there is a binding for binding? - pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); - } - - if ( pBinding ) - { - *pOut++ = '['; - pEnd = (char *)pBinding; - } - else - { - pEnd = binding; - } - - while ( *pEnd ) - { - *pOut++ = *pEnd++; - } - - if ( pBinding ) - { - *pOut++ = ']'; - } - } - else - { - *pOut++ = *p++; - } - } - - *pOut = '\0'; - - pOut = ( char * )malloc( strlen( sz ) + 1 ); - strcpy( pOut, sz ); - *ppout = pOut; - - return 1; -} - -/* -============ -KB_Find - -Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files -============ -*/ -struct kbutton_s DLLEXPORT *KB_Find( const char *name ) -{ - kblist_t *p; - p = g_kbkeys; - while ( p ) - { - if ( !stricmp( name, p->name ) ) - return p->pkey; - - p = p->next; - } - return NULL; -} - -/* -============ -KB_Add - -Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find -============ -*/ -void KB_Add( const char *name, kbutton_t *pkb ) -{ - kblist_t *p; - kbutton_t *kb; - - kb = KB_Find( name ); - - if ( kb ) - return; - - p = ( kblist_t * )malloc( sizeof( kblist_t ) ); - memset( p, 0, sizeof( *p ) ); - - strcpy( p->name, name ); - p->pkey = pkb; - - p->next = g_kbkeys; - g_kbkeys = p; -} - -/* -============ -KB_Init - -Add kbutton_t definitions that the engine can query if needed -============ -*/ -void KB_Init( void ) -{ - g_kbkeys = NULL; - - KB_Add( "in_graph", &in_graph ); - KB_Add( "in_mlook", &in_mlook ); - KB_Add( "in_jlook", &in_jlook ); -} - -/* -============ -KB_Shutdown - -Clear kblist -============ -*/ -void KB_Shutdown( void ) -{ - kblist_t *p, *n; - p = g_kbkeys; - while ( p ) - { - n = p->next; - free( p ); - p = n; - } - g_kbkeys = NULL; -} - -/* -============ -KeyDown -============ -*/ -void KeyDown (kbutton_t *b) -{ - int k; - char *c; - - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) - k = atoi(c); - else - k = -1; // typed manually at the console for continuous down - - if (k == b->down[0] || k == b->down[1]) - return; // repeating key - - if (!b->down[0]) - b->down[0] = k; - else if (!b->down[1]) - b->down[1] = k; - else - { - gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); - return; - } - - if (b->state & 1) - return; // still down - b->state |= 1 + 2; // down + impulse down -} - -/* -============ -KeyUp -============ -*/ -void KeyUp (kbutton_t *b) -{ - int k; - char *c; - - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) - k = atoi(c); - else - { // typed manually at the console, assume for unsticking, so clear all - b->down[0] = b->down[1] = 0; - b->state = 4; // impulse up - return; - } - - if (b->down[0] == k) - b->down[0] = 0; - else if (b->down[1] == k) - b->down[1] = 0; - else - return; // key up without coresponding down (menu pass through) - if (b->down[0] || b->down[1]) - { - //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); - return; // some other key is still holding it down - } - - if (!(b->state & 1)) - return; // still up (this should not happen) - - b->state &= ~1; // now up - b->state |= 4; // impulse up -} - -/* -============ -HUD_Key_Event - -Return 1 to allow engine to process the key, otherwise, act on it as needed -============ -*/ -int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) -{ - - return 1; -} - -void IN_BreakDown( void ) { KeyDown( &in_break );}; -void IN_BreakUp( void ) { KeyUp( &in_break ); }; -void IN_KLookDown (void) {KeyDown(&in_klook);} -void IN_KLookUp (void) {KeyUp(&in_klook);} -void IN_JLookDown (void) {KeyDown(&in_jlook);} -void IN_JLookUp (void) {KeyUp(&in_jlook);} -void IN_MLookDown (void) {KeyDown(&in_mlook);} -void IN_UpDown(void) {KeyDown(&in_up);} -void IN_UpUp(void) {KeyUp(&in_up);} -void IN_DownDown(void) {KeyDown(&in_down);} -void IN_DownUp(void) {KeyUp(&in_down);} -void IN_LeftDown(void) {KeyDown(&in_left);} -void IN_LeftUp(void) {KeyUp(&in_left);} -void IN_RightDown(void) {KeyDown(&in_right);} -void IN_RightUp(void) {KeyUp(&in_right);} - -void IN_ForwardDown(void) -{ - KeyDown(&in_forward); - gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); -} - -void IN_ForwardUp(void) -{ - KeyUp(&in_forward); - gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); -} - -void IN_BackDown(void) -{ - KeyDown(&in_back); - gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); -} - -void IN_BackUp(void) -{ - KeyUp(&in_back); - gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); -} -void IN_LookupDown(void) {KeyDown(&in_lookup);} -void IN_LookupUp(void) {KeyUp(&in_lookup);} -void IN_LookdownDown(void) {KeyDown(&in_lookdown);} -void IN_LookdownUp(void) {KeyUp(&in_lookdown);} -void IN_MoveleftDown(void) -{ - KeyDown(&in_moveleft); - gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); -} - -void IN_MoveleftUp(void) -{ - KeyUp(&in_moveleft); - gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); -} - -void IN_MoverightDown(void) -{ - KeyDown(&in_moveright); - gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); -} - -void IN_MoverightUp(void) -{ - KeyUp(&in_moveright); - gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); -} -void IN_SpeedDown(void) {KeyDown(&in_speed);} -void IN_SpeedUp(void) {KeyUp(&in_speed);} -void IN_StrafeDown(void) {KeyDown(&in_strafe);} -void IN_StrafeUp(void) {KeyUp(&in_strafe);} - -// needs capture by hud/vgui also -extern void __CmdFunc_InputPlayerSpecial(void); - -void IN_Attack2Down(void) -{ - KeyDown(&in_attack2); - - gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); -} - -void IN_Attack2Up(void) {KeyUp(&in_attack2);} -void IN_UseDown (void) -{ - KeyDown(&in_use); - gHUD.m_Spectator.HandleButtonsDown( IN_USE ); -} -void IN_UseUp (void) {KeyUp(&in_use);} -void IN_JumpDown (void) -{ - KeyDown(&in_jump); - gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); - -} -void IN_JumpUp (void) {KeyUp(&in_jump);} -void IN_DuckDown(void) -{ - KeyDown(&in_duck); - gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); - -} -void IN_DuckUp(void) {KeyUp(&in_duck);} -void IN_ReloadDown(void) {KeyDown(&in_reload);} -void IN_ReloadUp(void) {KeyUp(&in_reload);} -void IN_Alt1Down(void) {KeyDown(&in_alt1);} -void IN_Alt1Up(void) {KeyUp(&in_alt1);} -void IN_GraphDown(void) {KeyDown(&in_graph);} -void IN_GraphUp(void) {KeyUp(&in_graph);} - -void IN_AttackDown(void) -{ - KeyDown( &in_attack ); - gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); -} - -void IN_AttackUp(void) -{ - KeyUp( &in_attack ); - in_cancel = 0; -} - -// Special handling -void IN_Cancel(void) -{ - in_cancel = 1; -} - -void IN_Impulse (void) -{ - in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); -} - -void IN_ScoreDown(void) -{ - KeyDown(&in_score); -} - -void IN_ScoreUp(void) -{ - KeyUp(&in_score); -} - -void IN_MLookUp (void) -{ - KeyUp( &in_mlook ); -} - -/* -=============== -CL_KeyState - -Returns 0.25 if a key was pressed and released during the frame, -0.5 if it was pressed and held -0 if held then released, and -1.0 if held for the entire time -=============== -*/ -float CL_KeyState (kbutton_t *key) -{ - float val = 0.0; - int impulsedown, impulseup, down; - - impulsedown = key->state & 2; - impulseup = key->state & 4; - down = key->state & 1; - - if ( impulsedown && !impulseup ) - { - // pressed and held this frame? - val = down ? 0.5 : 0.0; - } - - if ( impulseup && !impulsedown ) - { - // released this frame? - val = down ? 0.0 : 0.0; - } - - if ( !impulsedown && !impulseup ) - { - // held the entire frame? - val = down ? 1.0 : 0.0; - } - - if ( impulsedown && impulseup ) - { - if ( down ) - { - // released and re-pressed this frame - val = 0.75; - } - else - { - // pressed and released this frame - val = 0.25; - } - } - - // clear impulses - key->state &= 1; - return val; -} - -/* -================ -CL_AdjustAngles - -Moves the local angle positions -================ -*/ -void CL_AdjustAngles ( float frametime, float *viewangles ) -{ - float speed; - float up, down; - - if (in_speed.state & 1) - { - speed = frametime * cl_anglespeedkey->value; - } - else - { - speed = frametime; - } - - if (!(in_strafe.state & 1)) - { - viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); - viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); - viewangles[YAW] = anglemod(viewangles[YAW]); - } - if (in_klook.state & 1) - { - viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); - viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); - } - - up = CL_KeyState (&in_lookup); - down = CL_KeyState(&in_lookdown); - - viewangles[PITCH] -= speed*cl_pitchspeed->value * up; - viewangles[PITCH] += speed*cl_pitchspeed->value * down; +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= - if (viewangles[PITCH] > cl_pitchdown->value) - viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) - viewangles[PITCH] = -cl_pitchup->value; - - if (viewangles[ROLL] > 50) - viewangles[ROLL] = 50; - if (viewangles[ROLL] < -50) - viewangles[ROLL] = -50; -} - -/* -================ -CL_CreateMove - -Send the intended movement message to the server -if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and -2 ) we have finished signing on to server -================ -*/ -void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) -{ - float spd; - vec3_t viewangles; - static vec3_t oldangles; - - if ( active ) - { - //memset( viewangles, 0, sizeof( vec3_t ) ); - //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; - gEngfuncs.GetViewAngles( (float *)viewangles ); - - CL_AdjustAngles ( frametime, viewangles ); - - memset (cmd, 0, sizeof(*cmd)); - - gEngfuncs.SetViewAngles( (float *)viewangles ); - - if ( in_strafe.state & 1 ) - { - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); - } - - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); - - cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); - cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); - - if ( !(in_klook.state & 1 ) ) - { - cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); - cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); - } - - // adjust for speed key - if ( in_speed.state & 1 ) - { - cmd->forwardmove *= cl_movespeedkey->value; - cmd->sidemove *= cl_movespeedkey->value; - cmd->upmove *= cl_movespeedkey->value; - } - - // clip to maxspeed - spd = gEngfuncs.GetClientMaxspeed(); - if ( spd != 0.0 ) - { - // scale the 3 speeds so that the total velocity is not > cl.maxspeed - float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); - - if ( fmov > spd ) - { - float fratio = spd / fmov; - cmd->forwardmove *= fratio; - cmd->sidemove *= fratio; - cmd->upmove *= fratio; - } - } - - // Allow mice and other controllers to add their inputs - IN_Move ( frametime, cmd ); - } - - cmd->impulse = in_impulse; - in_impulse = 0; - - cmd->weaponselect = g_weaponselect; - g_weaponselect = 0; - // - // set button and flag bits - // - cmd->buttons = CL_ButtonBits( 1 ); - - - // Using joystick? - if ( in_joystick->value ) - { - if ( cmd->forwardmove > 0 ) - { - cmd->buttons |= IN_FORWARD; - } - else if ( cmd->forwardmove < 0 ) - { - cmd->buttons |= IN_BACK; - } - } - - gEngfuncs.GetViewAngles( (float *)viewangles ); - // Set current view angles. - - if ( g_iAlive ) - { - VectorCopy( viewangles, cmd->viewangles ); - VectorCopy( viewangles, oldangles ); - } - else - { - VectorCopy( oldangles, cmd->viewangles ); - } - -} - -/* -============ -CL_IsDead - -Returns 1 if health is <= 0 -============ -*/ -int CL_IsDead( void ) -{ - return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; -} - -/* -============ -CL_ButtonBits - -Returns appropriate button info for keyboard and mouse state -Set bResetState to 1 to clear old state info -============ -*/ -int CL_ButtonBits( int bResetState ) -{ - int bits = 0; - - if ( in_attack.state & 3 ) - { - if(gHUD.m_MOTD.m_bShow) - gHUD.m_MOTD.Reset(); - else - bits |= IN_ATTACK; - } +// cl.input.c -- builds an intended movement command to send to the server - - if (in_duck.state & 3) - { - bits |= IN_DUCK; - } - - if (in_jump.state & 3) - { - bits |= IN_JUMP; - } - - if ( in_forward.state & 3 ) - { - bits |= IN_FORWARD; - } - - if (in_back.state & 3) - { - bits |= IN_BACK; - } - - if (in_use.state & 3) - { - bits |= IN_USE; - } - - if (in_cancel) - { - bits |= IN_CANCEL; - } - - if ( in_left.state & 3 ) - { - bits |= IN_LEFT; - } - - if (in_right.state & 3) - { - bits |= IN_RIGHT; - } - - if ( in_moveleft.state & 3 ) - { - bits |= IN_MOVELEFT; - } - - if (in_moveright.state & 3) - { - bits |= IN_MOVERIGHT; - } - - if (in_attack2.state & 3) - { - bits |= IN_ATTACK2; - } - - if (in_reload.state & 3) - { - bits |= IN_RELOAD; - } - - if (in_alt1.state & 3) - { - bits |= IN_ALT1; - } - - if ( in_score.state & 3 ) - { - bits |= IN_SCORE; - } - - // Dead or in intermission? Shore scoreboard, too - if ( CL_IsDead() || gHUD.m_iIntermission ) - { - bits |= IN_SCORE; - } - - if ( bResetState ) - { - in_attack.state &= ~2; - in_duck.state &= ~2; - in_jump.state &= ~2; - in_forward.state &= ~2; - in_back.state &= ~2; - in_use.state &= ~2; - in_left.state &= ~2; - in_right.state &= ~2; - in_moveleft.state &= ~2; - in_moveright.state &= ~2; - in_attack2.state &= ~2; - in_reload.state &= ~2; - in_alt1.state &= ~2; - in_score.state &= ~2; - } - - return bits; -} - -/* -============ -CL_ResetButtonBits - -============ -*/ -void CL_ResetButtonBits( int bits ) -{ - int bitsNew = CL_ButtonBits( 0 ) ^ bits; - - // Has the attack button been changed - if ( bitsNew & IN_ATTACK ) - { - // Was it pressed? or let go? - if ( bits & IN_ATTACK ) - { - KeyDown( &in_attack ); - } - else - { - // totally clear state - in_attack.state &= ~7; - } - } -} - -/* -============ -InitInput -============ -*/ -void InitInput (void) -{ - gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); - gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); - gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); - gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); - gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); - gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); - gEngfuncs.pfnAddCommand ("+right",IN_RightDown); - gEngfuncs.pfnAddCommand ("-right",IN_RightUp); - gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); - gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); - gEngfuncs.pfnAddCommand ("+back",IN_BackDown); - gEngfuncs.pfnAddCommand ("-back",IN_BackUp); - gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); - gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); - gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); - gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); - gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); - gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); - gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); - gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); - gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); - gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); - gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); - gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); - gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); - gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); - gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); - gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); - gEngfuncs.pfnAddCommand ("+use", IN_UseDown); - gEngfuncs.pfnAddCommand ("-use", IN_UseUp); - gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); - gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); - gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); - gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); - gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); - gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); - gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); - gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); - gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); - gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); - gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); - gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); - gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); - gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); - gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); - gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); - gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); - gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); - gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); - - lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); - lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); - cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); - cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); - cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); - cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); - cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); - cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); - cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); - cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); - cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); - cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); - - cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); - - m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); - m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); - m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); - m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); - - // Initialize third person camera controls. - CAM_Init(); - // Initialize inputs - IN_Init(); - // Initialize keyboard - KB_Init(); - // Initialize view system - V_Init(); -} - -/* -============ -ShutdownInput -============ -*/ -void ShutdownInput (void) -{ - IN_Shutdown(); - KB_Shutdown(); -} - -void DLLEXPORT HUD_Shutdown( void ) -{ - ShutdownInput(); -} +//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +extern "C" +{ +#include "kbutton.h" +} +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "view.h" +#include +#include + + + +extern "C" +{ + struct kbutton_s DLLEXPORT *KB_Find( const char *name ); + void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); + void DLLEXPORT HUD_Shutdown( void ); + int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); +} + +extern int g_iAlive; + +extern int g_weaponselect; +extern cl_enginefunc_t gEngfuncs; + +// Defined in pm_math.c +extern "C" float anglemod( float a ); + +void IN_Init (void); +void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Shutdown( void ); +void V_Init( void ); +void VectorAngles( const float *forward, float *angles ); +int CL_ButtonBits( int ); + +// xxx need client dll function to get and clear impuse +extern cvar_t *in_joystick; + +int in_impulse = 0; +int in_cancel = 0; + +cvar_t *m_pitch; +cvar_t *m_yaw; +cvar_t *m_forward; +cvar_t *m_side; + +cvar_t *lookstrafe; +cvar_t *lookspring; +cvar_t *cl_pitchup; +cvar_t *cl_pitchdown; +cvar_t *cl_upspeed; +cvar_t *cl_forwardspeed; +cvar_t *cl_backspeed; +cvar_t *cl_sidespeed; +cvar_t *cl_movespeedkey; +cvar_t *cl_yawspeed; +cvar_t *cl_pitchspeed; +cvar_t *cl_anglespeedkey; +cvar_t *cl_vsmoothing; +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook; +kbutton_t in_klook; +kbutton_t in_jlook; +kbutton_t in_left; +kbutton_t in_right; +kbutton_t in_forward; +kbutton_t in_back; +kbutton_t in_lookup; +kbutton_t in_lookdown; +kbutton_t in_moveleft; +kbutton_t in_moveright; +kbutton_t in_strafe; +kbutton_t in_speed; +kbutton_t in_use; +kbutton_t in_jump; +kbutton_t in_attack; +kbutton_t in_attack2; +kbutton_t in_up; +kbutton_t in_down; +kbutton_t in_duck; +kbutton_t in_reload; +kbutton_t in_alt1; +kbutton_t in_score; +kbutton_t in_break; +kbutton_t in_graph; // Display the netgraph + +typedef struct kblist_s +{ + struct kblist_s *next; + kbutton_t *pkey; + char name[32]; +} kblist_t; + +kblist_t *g_kbkeys = NULL; + +/* +============ +KB_ConvertString + +Removes references to +use and replaces them with the keyname in the output string. If + a binding is unfound, then the original text is retained. +NOTE: Only works for text with +word in it. +============ +*/ +int KB_ConvertString( char *in, char **ppout ) +{ + char sz[ 4096 ]; + char binding[ 64 ]; + char *p; + char *pOut; + char *pEnd; + const char *pBinding; + + if ( !ppout ) + return 0; + + *ppout = NULL; + p = in; + pOut = sz; + while ( *p ) + { + if ( *p == '+' ) + { + pEnd = binding; + while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + { + *pEnd++ = *p++; + } + + *pEnd = '\0'; + + pBinding = NULL; + if ( strlen( binding + 1 ) > 0 ) + { + // See if there is a binding for binding? + pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); + } + + if ( pBinding ) + { + *pOut++ = '['; + pEnd = (char *)pBinding; + } + else + { + pEnd = binding; + } + + while ( *pEnd ) + { + *pOut++ = *pEnd++; + } + + if ( pBinding ) + { + *pOut++ = ']'; + } + } + else + { + *pOut++ = *p++; + } + } + + *pOut = '\0'; + + pOut = ( char * )malloc( strlen( sz ) + 1 ); + strcpy( pOut, sz ); + *ppout = pOut; + + return 1; +} + +/* +============ +KB_Find + +Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files +============ +*/ +struct kbutton_s DLLEXPORT *KB_Find( const char *name ) +{ + kblist_t *p; + p = g_kbkeys; + while ( p ) + { + if ( !stricmp( name, p->name ) ) + return p->pkey; + + p = p->next; + } + return NULL; +} + +/* +============ +KB_Add + +Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find +============ +*/ +void KB_Add( const char *name, kbutton_t *pkb ) +{ + kblist_t *p; + kbutton_t *kb; + + kb = KB_Find( name ); + + if ( kb ) + return; + + p = ( kblist_t * )malloc( sizeof( kblist_t ) ); + memset( p, 0, sizeof( *p ) ); + + strcpy( p->name, name ); + p->pkey = pkb; + + p->next = g_kbkeys; + g_kbkeys = p; +} + +/* +============ +KB_Init + +Add kbutton_t definitions that the engine can query if needed +============ +*/ +void KB_Init( void ) +{ + g_kbkeys = NULL; + + KB_Add( "in_graph", &in_graph ); + KB_Add( "in_mlook", &in_mlook ); + KB_Add( "in_jlook", &in_jlook ); +} + +/* +============ +KB_Shutdown + +Clear kblist +============ +*/ +void KB_Shutdown( void ) +{ + kblist_t *p, *n; + p = g_kbkeys; + while ( p ) + { + n = p->next; + free( p ); + p = n; + } + g_kbkeys = NULL; +} + +/* +============ +KeyDown +============ +*/ +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyUp +============ +*/ +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + { + //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + return; // some other key is still holding it down + } + + if (!(b->state & 1)) + return; // still up (this should not happen) + + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +/* +============ +HUD_Key_Event + +Return 1 to allow engine to process the key, otherwise, act on it as needed +============ +*/ +int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) +{ + + return 1; +} + +void IN_BreakDown( void ) { KeyDown( &in_break );}; +void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_JLookDown (void) {KeyDown(&in_jlook);} +void IN_JLookUp (void) {KeyUp(&in_jlook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} + +void IN_ForwardDown(void) +{ + KeyDown(&in_forward); + gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); +} + +void IN_ForwardUp(void) +{ + KeyUp(&in_forward); + gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); +} + +void IN_BackDown(void) +{ + KeyDown(&in_back); + gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); +} + +void IN_BackUp(void) +{ + KeyUp(&in_back); + gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); +} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) +{ + KeyDown(&in_moveleft); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); +} + +void IN_MoveleftUp(void) +{ + KeyUp(&in_moveleft); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); +} + +void IN_MoverightDown(void) +{ + KeyDown(&in_moveright); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); +} + +void IN_MoverightUp(void) +{ + KeyUp(&in_moveright); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); +} +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +// needs capture by hud/vgui also +extern void __CmdFunc_InputPlayerSpecial(void); + +void IN_Attack2Down(void) +{ + KeyDown(&in_attack2); + + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); +} + +void IN_Attack2Up(void) {KeyUp(&in_attack2);} +void IN_UseDown (void) +{ + KeyDown(&in_use); + gHUD.m_Spectator.HandleButtonsDown( IN_USE ); +} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) +{ + KeyDown(&in_jump); + gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); + +} +void IN_JumpUp (void) {KeyUp(&in_jump);} +void IN_DuckDown(void) +{ + KeyDown(&in_duck); + gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); + +} +void IN_DuckUp(void) {KeyUp(&in_duck);} +void IN_ReloadDown(void) {KeyDown(&in_reload);} +void IN_ReloadUp(void) {KeyUp(&in_reload);} +void IN_Alt1Down(void) {KeyDown(&in_alt1);} +void IN_Alt1Up(void) {KeyUp(&in_alt1);} +void IN_GraphDown(void) {KeyDown(&in_graph);} +void IN_GraphUp(void) {KeyUp(&in_graph);} + +void IN_AttackDown(void) +{ + KeyDown( &in_attack ); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); +} + +void IN_AttackUp(void) +{ + KeyUp( &in_attack ); + in_cancel = 0; +} + +// Special handling +void IN_Cancel(void) +{ + in_cancel = 1; +} + +void IN_Impulse (void) +{ + in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); +} + +void IN_ScoreDown(void) +{ + KeyDown(&in_score); +} + +void IN_ScoreUp(void) +{ + KeyUp(&in_score); +} + +void IN_MLookUp (void) +{ + KeyUp( &in_mlook ); +} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val = 0.0; + int impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + + if ( impulsedown && !impulseup ) + { + // pressed and held this frame? + val = down ? 0.5 : 0.0; + } + + if ( impulseup && !impulsedown ) + { + // released this frame? + val = down ? 0.0 : 0.0; + } + + if ( !impulsedown && !impulseup ) + { + // held the entire frame? + val = down ? 1.0 : 0.0; + } + + if ( impulsedown && impulseup ) + { + if ( down ) + { + // released and re-pressed this frame + val = 0.75; + } + else + { + // pressed and released this frame + val = 0.25; + } + } + + // clear impulses + key->state &= 1; + return val; +} + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles ( float frametime, float *viewangles ) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + { + speed = frametime * cl_anglespeedkey->value; + } + else + { + speed = frametime; + } + + if (!(in_strafe.state & 1)) + { + viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); + viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); + viewangles[YAW] = anglemod(viewangles[YAW]); + } + if (in_klook.state & 1) + { + viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); + viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + viewangles[PITCH] -= speed*cl_pitchspeed->value * up; + viewangles[PITCH] += speed*cl_pitchspeed->value * down; + + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + if (viewangles[ROLL] > 50) + viewangles[ROLL] = 50; + if (viewangles[ROLL] < -50) + viewangles[ROLL] = -50; +} + +/* +================ +CL_CreateMove + +Send the intended movement message to the server +if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and +2 ) we have finished signing on to server +================ +*/ +void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) +{ + float spd; + vec3_t viewangles; + static vec3_t oldangles; + + if ( active ) + { + //memset( viewangles, 0, sizeof( vec3_t ) ); + //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + gEngfuncs.GetViewAngles( (float *)viewangles ); + + CL_AdjustAngles ( frametime, viewangles ); + + memset (cmd, 0, sizeof(*cmd)); + + gEngfuncs.SetViewAngles( (float *)viewangles ); + + if ( in_strafe.state & 1 ) + { + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + + if ( !(in_klook.state & 1 ) ) + { + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); + } + + // adjust for speed key + if ( in_speed.state & 1 ) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + cmd->upmove *= cl_movespeedkey->value; + } + + // clip to maxspeed + spd = gEngfuncs.GetClientMaxspeed(); + if ( spd != 0.0 ) + { + // scale the 3 speeds so that the total velocity is not > cl.maxspeed + float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + + if ( fmov > spd ) + { + float fratio = spd / fmov; + cmd->forwardmove *= fratio; + cmd->sidemove *= fratio; + cmd->upmove *= fratio; + } + } + + // Allow mice and other controllers to add their inputs + IN_Move ( frametime, cmd ); + } + + cmd->impulse = in_impulse; + in_impulse = 0; + + cmd->weaponselect = g_weaponselect; + g_weaponselect = 0; + // + // set button and flag bits + // + cmd->buttons = CL_ButtonBits( 1 ); + + + // Using joystick? + if ( in_joystick->value ) + { + if ( cmd->forwardmove > 0 ) + { + cmd->buttons |= IN_FORWARD; + } + else if ( cmd->forwardmove < 0 ) + { + cmd->buttons |= IN_BACK; + } + } + + gEngfuncs.GetViewAngles( (float *)viewangles ); + // Set current view angles. + + if ( g_iAlive ) + { + VectorCopy( viewangles, cmd->viewangles ); + VectorCopy( viewangles, oldangles ); + } + else + { + VectorCopy( oldangles, cmd->viewangles ); + } + +} + +/* +============ +CL_IsDead + +Returns 1 if health is <= 0 +============ +*/ +int CL_IsDead( void ) +{ + return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; +} + +/* +============ +CL_ButtonBits + +Returns appropriate button info for keyboard and mouse state +Set bResetState to 1 to clear old state info +============ +*/ +int CL_ButtonBits( int bResetState ) +{ + int bits = 0; + + if ( in_attack.state & 3 ) + { + if(gHUD.m_MOTD.m_bShow) + gHUD.m_MOTD.Reset(); + else + bits |= IN_ATTACK; + } + + + if (in_duck.state & 3) + { + bits |= IN_DUCK; + } + + if (in_jump.state & 3) + { + bits |= IN_JUMP; + } + + if ( in_forward.state & 3 ) + { + bits |= IN_FORWARD; + } + + if (in_back.state & 3) + { + bits |= IN_BACK; + } + + if (in_use.state & 3) + { + bits |= IN_USE; + } + + if (in_cancel) + { + bits |= IN_CANCEL; + } + + if ( in_left.state & 3 ) + { + bits |= IN_LEFT; + } + + if (in_right.state & 3) + { + bits |= IN_RIGHT; + } + + if ( in_moveleft.state & 3 ) + { + bits |= IN_MOVELEFT; + } + + if (in_moveright.state & 3) + { + bits |= IN_MOVERIGHT; + } + + if (in_attack2.state & 3) + { + bits |= IN_ATTACK2; + } + + if (in_reload.state & 3) + { + bits |= IN_RELOAD; + } + + if (in_alt1.state & 3) + { + bits |= IN_ALT1; + } + + if ( in_score.state & 3 ) + { + bits |= IN_SCORE; + } + + // Dead or in intermission? Shore scoreboard, too + if ( CL_IsDead() || gHUD.m_iIntermission ) + { + bits |= IN_SCORE; + } + + if ( bResetState ) + { + in_attack.state &= ~2; + in_duck.state &= ~2; + in_jump.state &= ~2; + in_forward.state &= ~2; + in_back.state &= ~2; + in_use.state &= ~2; + in_left.state &= ~2; + in_right.state &= ~2; + in_moveleft.state &= ~2; + in_moveright.state &= ~2; + in_attack2.state &= ~2; + in_reload.state &= ~2; + in_alt1.state &= ~2; + in_score.state &= ~2; + } + + return bits; +} + +/* +============ +CL_ResetButtonBits + +============ +*/ +void CL_ResetButtonBits( int bits ) +{ + int bitsNew = CL_ButtonBits( 0 ) ^ bits; + + // Has the attack button been changed + if ( bitsNew & IN_ATTACK ) + { + // Was it pressed? or let go? + if ( bits & IN_ATTACK ) + { + KeyDown( &in_attack ); + } + else + { + // totally clear state + in_attack.state &= ~7; + } + } +} + +/* +============ +InitInput +============ +*/ +void InitInput (void) +{ + gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); + gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); + gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); + gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); + gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); + gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); + gEngfuncs.pfnAddCommand ("+right",IN_RightDown); + gEngfuncs.pfnAddCommand ("-right",IN_RightUp); + gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); + gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); + gEngfuncs.pfnAddCommand ("+back",IN_BackDown); + gEngfuncs.pfnAddCommand ("-back",IN_BackUp); + gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); + gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); + gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); + gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); + gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); + gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); + gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); + gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); + gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); + gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); + gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); + gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); + gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); + gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); + gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); + gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); + gEngfuncs.pfnAddCommand ("+use", IN_UseDown); + gEngfuncs.pfnAddCommand ("-use", IN_UseUp); + gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); + gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); + gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); + gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); + gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); + gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); + gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); + gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); + gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); + gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); + gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); + gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); + gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); + gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); + gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); + gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); + gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); + gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); + gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + + lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + + cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + + m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + + // Initialize third person camera controls. + CAM_Init(); + // Initialize inputs + IN_Init(); + // Initialize keyboard + KB_Init(); + // Initialize view system + V_Init(); +} + +/* +============ +ShutdownInput +============ +*/ +void ShutdownInput (void) +{ + IN_Shutdown(); + KB_Shutdown(); +} + +void DLLEXPORT HUD_Shutdown( void ) +{ + ShutdownInput(); +} diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp index 7176746b..1bacdf07 100644 --- a/cl_dll/inputw32.cpp +++ b/cl_dll/inputw32.cpp @@ -1,947 +1,947 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// in_win.c -- windows 95 mouse and joystick code -// 02/21/97 JCB Added extended DirectInput code to support external controllers. - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" -#include "camera.h" -#include "in_defs.h" -#include "../engine/keydefs.h" -#include "view.h" -#include "windows.h" - -#define MOUSE_BUTTON_COUNT 5 - -// Set this to 1 to show mouse cursor. Experimental -int g_iVisibleMouse = 0; - -extern "C" -{ - void DLLEXPORT IN_ActivateMouse( void ); - void DLLEXPORT IN_DeactivateMouse( void ); - void DLLEXPORT IN_MouseEvent (int mstate); - void DLLEXPORT IN_Accumulate (void); - void DLLEXPORT IN_ClearStates (void); -} - -extern cl_enginefunc_t gEngfuncs; - -extern int iMouseInUse; - -extern kbutton_t in_strafe; -extern kbutton_t in_mlook; -extern kbutton_t in_speed; -extern kbutton_t in_jlook; - -extern cvar_t *m_pitch; -extern cvar_t *m_yaw; -extern cvar_t *m_forward; -extern cvar_t *m_side; - -extern cvar_t *lookstrafe; -extern cvar_t *lookspring; -extern cvar_t *cl_pitchdown; -extern cvar_t *cl_pitchup; -extern cvar_t *cl_yawspeed; -extern cvar_t *cl_sidespeed; -extern cvar_t *cl_forwardspeed; -extern cvar_t *cl_pitchspeed; -extern cvar_t *cl_movespeedkey; - -// mouse variables -cvar_t *m_filter; -cvar_t *sensitivity; - -int mouse_buttons; -int mouse_oldbuttonstate; -POINT current_pos; -int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; - -static int restore_spi; -static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; -static int mouseactive; -int mouseinitialized; -static int mouseparmsvalid; -static int mouseshowtoggle = 1; - -// joystick defines and variables -// where should defines be moved? -#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick -#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball -#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V -#define JOY_AXIS_X 0 -#define JOY_AXIS_Y 1 -#define JOY_AXIS_Z 2 -#define JOY_AXIS_R 3 -#define JOY_AXIS_U 4 -#define JOY_AXIS_V 5 - -enum _ControlList -{ - AxisNada = 0, - AxisForward, - AxisLook, - AxisSide, - AxisTurn -}; - -DWORD dwAxisFlags[JOY_MAX_AXES] = -{ - JOY_RETURNX, - JOY_RETURNY, - JOY_RETURNZ, - JOY_RETURNR, - JOY_RETURNU, - JOY_RETURNV -}; - -DWORD dwAxisMap[ JOY_MAX_AXES ]; -DWORD dwControlMap[ JOY_MAX_AXES ]; -PDWORD pdwRawValue[ JOY_MAX_AXES ]; - -// none of these cvars are saved over a session -// this means that advanced controller configuration needs to be executed -// each time. this avoids any problems with getting back to a default usage -// or when changing from one controller to another. this way at least something -// works. -cvar_t *in_joystick; -cvar_t *joy_name; -cvar_t *joy_advanced; -cvar_t *joy_advaxisx; -cvar_t *joy_advaxisy; -cvar_t *joy_advaxisz; -cvar_t *joy_advaxisr; -cvar_t *joy_advaxisu; -cvar_t *joy_advaxisv; -cvar_t *joy_forwardthreshold; -cvar_t *joy_sidethreshold; -cvar_t *joy_pitchthreshold; -cvar_t *joy_yawthreshold; -cvar_t *joy_forwardsensitivity; -cvar_t *joy_sidesensitivity; -cvar_t *joy_pitchsensitivity; -cvar_t *joy_yawsensitivity; -cvar_t *joy_wwhack1; -cvar_t *joy_wwhack2; - -int joy_avail, joy_advancedinit, joy_haspov; -DWORD joy_oldbuttonstate, joy_oldpovstate; - -int joy_id; -DWORD joy_flags; -DWORD joy_numbuttons; - -static JOYINFOEX ji; - -/* -=========== -Force_CenterView_f -=========== -*/ -void Force_CenterView_f (void) -{ - vec3_t viewangles; - - if (!iMouseInUse) - { - gEngfuncs.GetViewAngles( (float *)viewangles ); - viewangles[PITCH] = 0; - gEngfuncs.SetViewAngles( (float *)viewangles ); - } -} - -/* -=========== -IN_ActivateMouse -=========== -*/ -void DLLEXPORT IN_ActivateMouse (void) -{ - if (mouseinitialized) - { - if (mouseparmsvalid) - restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); - mouseactive = 1; - } -} - -/* -=========== -IN_DeactivateMouse -=========== -*/ -void DLLEXPORT IN_DeactivateMouse (void) -{ - if (mouseinitialized) - { - if (restore_spi) - SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); - - mouseactive = 0; - } -} - -/* -=========== -IN_StartupMouse -=========== -*/ -void IN_StartupMouse (void) -{ - if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) - return; - - mouseinitialized = 1; - mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); - - if (mouseparmsvalid) - { - if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) - newmouseparms[2] = originalmouseparms[2]; - - if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) - { - newmouseparms[0] = originalmouseparms[0]; - newmouseparms[1] = originalmouseparms[1]; - } - - if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) - { - newmouseparms[0] = originalmouseparms[0]; - newmouseparms[1] = originalmouseparms[1]; - newmouseparms[2] = originalmouseparms[2]; - } - } - - mouse_buttons = MOUSE_BUTTON_COUNT; -} - -/* -=========== -IN_Shutdown -=========== -*/ -void IN_Shutdown (void) -{ - IN_DeactivateMouse (); -} - -/* -=========== -IN_GetMousePos - -Ask for mouse position from engine -=========== -*/ -void IN_GetMousePos( int *mx, int *my ) -{ - gEngfuncs.GetMousePosition( mx, my ); -} - -/* -=========== -IN_ResetMouse - -FIXME: Call through to engine? -=========== -*/ -void IN_ResetMouse( void ) -{ - SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); -} - -/* -=========== -IN_MouseEvent -=========== -*/ -void DLLEXPORT IN_MouseEvent (int mstate) -{ - int i; - - if ( iMouseInUse || g_iVisibleMouse ) - return; - - // perform button actions - for (i=0 ; ivalue) - { - mouse_x = (mx + old_mouse_x) * 0.5; - mouse_y = (my + old_mouse_y) * 0.5; - } - else - { - mouse_x = mx; - mouse_y = my; - } - - old_mouse_x = mx; - old_mouse_y = my; - - if ( gHUD.GetSensitivity() != 0 ) - { - mouse_x *= gHUD.GetSensitivity(); - mouse_y *= gHUD.GetSensitivity(); - } - else - { - mouse_x *= sensitivity->value; - mouse_y *= sensitivity->value; - } - - // add mouse X/Y movement to cmd - if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) - cmd->sidemove += m_side->value * mouse_x; - else - viewangles[YAW] -= m_yaw->value * mouse_x; - - if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) - { - viewangles[PITCH] += m_pitch->value * mouse_y; - if (viewangles[PITCH] > cl_pitchdown->value) - viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) - viewangles[PITCH] = -cl_pitchup->value; - } - else - { - if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) - { - cmd->upmove -= m_forward->value * mouse_y; - } - else - { - cmd->forwardmove -= m_forward->value * mouse_y; - } - } - - // if the mouse has moved, force it to the center, so there's room to move - if ( mx || my ) - { - IN_ResetMouse(); - } - } - - gEngfuncs.SetViewAngles( (float *)viewangles ); - -/* -//#define TRACE_TEST -#if defined( TRACE_TEST ) - { - int mx, my; - void V_Move( int mx, int my ); - IN_GetMousePos( &mx, &my ); - V_Move( mx, my ); - } -#endif -*/ -} - -/* -=========== -IN_Accumulate -=========== -*/ -void DLLEXPORT IN_Accumulate (void) -{ - //only accumulate mouse if we are not moving the camera with the mouse - if ( !iMouseInUse && !g_iVisibleMouse ) - { - if (mouseactive) - { - GetCursorPos (¤t_pos); - - mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); - my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); - - // force the mouse to the center, so there's room to move - IN_ResetMouse(); - } - } - -} - -/* -=================== -IN_ClearStates -=================== -*/ -void DLLEXPORT IN_ClearStates (void) -{ - if ( !mouseactive ) - return; - - mx_accum = 0; - my_accum = 0; - mouse_oldbuttonstate = 0; -} - -/* -=============== -IN_StartupJoystick -=============== -*/ -void IN_StartupJoystick (void) -{ - int numdevs; - JOYCAPS jc; - MMRESULT mmr; - - // assume no joystick - joy_avail = 0; - - // abort startup if user requests no joystick - if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) - return; - - // verify joystick driver is present - if ((numdevs = joyGetNumDevs ()) == 0) - { - gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); - return; - } - - // cycle through the joystick ids for the first valid one - for (joy_id=0 ; joy_idvalue == 0.0) - { - // default joystick initialization - // 2 axes only with joystick control - dwAxisMap[JOY_AXIS_X] = AxisTurn; - // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; - dwAxisMap[JOY_AXIS_Y] = AxisForward; - // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; - } - else - { - if ( strcmp ( joy_name->string, "joystick") != 0 ) - { - // notify user of advanced controller - gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); - } - - // advanced initialization here - // data supplied by user via joy_axisn cvars - dwTemp = (DWORD) joy_advaxisx->value; - dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisy->value; - dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisz->value; - dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisr->value; - dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisu->value; - dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisv->value; - dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; - } - - // compute the axes to collect from DirectInput - joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; - for (i = 0; i < JOY_MAX_AXES; i++) - { - if (dwAxisMap[i] != AxisNada) - { - joy_flags |= dwAxisFlags[i]; - } - } -} - - -/* -=========== -IN_Commands -=========== -*/ -void IN_Commands (void) -{ - int i, key_index; - DWORD buttonstate, povstate; - - if (!joy_avail) - { - return; - } - - - // loop through the joystick buttons - // key a joystick event or auxillary event for higher number buttons for each state change - buttonstate = ji.dwButtons; - for (i=0 ; i < (int)joy_numbuttons ; i++) - { - if ( (buttonstate & (1<value != 0.0) - { - ji.dwUpos += 100; - } - return 1; - } - else - { - // read error occurred - // turning off the joystick seems too harsh for 1 read error,\ - // but what should be done? - // Con_Printf ("IN_ReadJoystick: no response\n"); - // joy_avail = 0; - return 0; - } -} - - -/* -=========== -IN_JoyMove -=========== -*/ -void IN_JoyMove ( float frametime, usercmd_t *cmd ) -{ - float speed, aspeed; - float fAxisValue, fTemp; - int i; - vec3_t viewangles; - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - - // complete initialization if first time in - // this is needed as cvars are not available at initialization time - if( joy_advancedinit != 1 ) - { - Joy_AdvancedUpdate_f(); - joy_advancedinit = 1; - } - - // verify joystick is available and that the user wants to use it - if (!joy_avail || !in_joystick->value) - { - return; - } - - // collect the joystick data, if possible - if (IN_ReadJoystick () != 1) - { - return; - } - - if (in_speed.state & 1) - speed = cl_movespeedkey->value; - else - speed = 1; - - aspeed = speed * frametime; - - // loop through the axes - for (i = 0; i < JOY_MAX_AXES; i++) - { - // get the floating point zero-centered, potentially-inverted data for the current axis - fAxisValue = (float) *pdwRawValue[i]; - // move centerpoint to zero - fAxisValue -= 32768.0; - - if (joy_wwhack2->value != 0.0) - { - if (dwAxisMap[i] == AxisTurn) - { - // this is a special formula for the Logitech WingMan Warrior - // y=ax^b; where a = 300 and b = 1.3 - // also x values are in increments of 800 (so this is factored out) - // then bounds check result to level out excessively high spin rates - fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); - if (fTemp > 14000.0) - fTemp = 14000.0; - // restore direction information - fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; - } - } - - // convert range from -32768..32767 to -1..1 - fAxisValue /= 32768.0; - - switch (dwAxisMap[i]) - { - case AxisForward: - if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) - { - // user wants forward control to become look control - if (fabs(fAxisValue) > joy_pitchthreshold->value) - { - // if mouse invert is on, invert the joystick pitch value - // only absolute control support here (joy_advanced is 0) - if (m_pitch->value < 0.0) - { - viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; - } - else - { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; - } - V_StopPitchDrift(); - } - else - { - // no pitch movement - // disable pitch return-to-center unless requested by user - // *** this code can be removed when the lookspring bug is fixed - // *** the bug always has the lookspring feature on - if(lookspring->value == 0.0) - { - V_StopPitchDrift(); - } - } - } - else - { - // user wants forward control to be forward control - if (fabs(fAxisValue) > joy_forwardthreshold->value) - { - cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; - } - } - break; - - case AxisSide: - if (fabs(fAxisValue) > joy_sidethreshold->value) - { - cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; - } - break; - - case AxisTurn: - if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) - { - // user wants turn control to become side control - if (fabs(fAxisValue) > joy_sidethreshold->value) - { - cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; - } - } - else - { - // user wants turn control to be turn control - if (fabs(fAxisValue) > joy_yawthreshold->value) - { - if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) - { - viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; - } - else - { - viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; - } - - } - } - break; - - case AxisLook: - if (in_jlook.state & 1) - { - if (fabs(fAxisValue) > joy_pitchthreshold->value) - { - // pitch movement detected and pitch movement desired by user - if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) - { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; - } - else - { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; - } - V_StopPitchDrift(); - } - else - { - // no pitch movement - // disable pitch return-to-center unless requested by user - // *** this code can be removed when the lookspring bug is fixed - // *** the bug always has the lookspring feature on - if( lookspring->value == 0.0 ) - { - V_StopPitchDrift(); - } - } - } - break; - - default: - break; - } - } - - // bounds check pitch - if (viewangles[PITCH] > cl_pitchdown->value) - viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) - viewangles[PITCH] = -cl_pitchup->value; - - gEngfuncs.SetViewAngles( (float *)viewangles ); - -} - -/* -=========== -IN_Move -=========== -*/ -void IN_Move ( float frametime, usercmd_t *cmd) -{ - if ( !iMouseInUse && mouseactive ) - { - IN_MouseMove ( frametime, cmd); - } - - IN_JoyMove ( frametime, cmd); -} - -/* -=========== -IN_Init -=========== -*/ -void IN_Init (void) -{ - m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); - sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. - - in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); - joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); - joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); - joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); - joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); - joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); - joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); - joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); - joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); - joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); - joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); - joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); - joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); - joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); - joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); - joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); - joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); - joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); - joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); - - gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); - gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); - - IN_StartupMouse (); - IN_StartupJoystick (); +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// in_win.c -- windows 95 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "../engine/keydefs.h" +#include "view.h" +#include "windows.h" + +#define MOUSE_BUTTON_COUNT 5 + +// Set this to 1 to show mouse cursor. Experimental +int g_iVisibleMouse = 0; + +extern "C" +{ + void DLLEXPORT IN_ActivateMouse( void ); + void DLLEXPORT IN_DeactivateMouse( void ); + void DLLEXPORT IN_MouseEvent (int mstate); + void DLLEXPORT IN_Accumulate (void); + void DLLEXPORT IN_ClearStates (void); +} + +extern cl_enginefunc_t gEngfuncs; + +extern int iMouseInUse; + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; + +// mouse variables +cvar_t *m_filter; +cvar_t *sensitivity; + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, + AxisForward, + AxisLook, + AxisSide, + AxisTurn +}; + +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, + JOY_RETURNY, + JOY_RETURNZ, + JOY_RETURNR, + JOY_RETURNU, + JOY_RETURNV +}; + +DWORD dwAxisMap[ JOY_MAX_AXES ]; +DWORD dwControlMap[ JOY_MAX_AXES ]; +PDWORD pdwRawValue[ JOY_MAX_AXES ]; + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; + +int joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; + +static JOYINFOEX ji; + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + vec3_t viewangles; + + if (!iMouseInUse) + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + viewangles[PITCH] = 0; + gEngfuncs.SetViewAngles( (float *)viewangles ); + } +} + +/* +=========== +IN_ActivateMouse +=========== +*/ +void DLLEXPORT IN_ActivateMouse (void) +{ + if (mouseinitialized) + { + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + mouseactive = 1; + } +} + +/* +=========== +IN_DeactivateMouse +=========== +*/ +void DLLEXPORT IN_DeactivateMouse (void) +{ + if (mouseinitialized) + { + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); + + mouseactive = 0; + } +} + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) + return; + + mouseinitialized = 1; + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + newmouseparms[2] = originalmouseparms[2]; + + if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } + + mouse_buttons = MOUSE_BUTTON_COUNT; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + IN_DeactivateMouse (); +} + +/* +=========== +IN_GetMousePos + +Ask for mouse position from engine +=========== +*/ +void IN_GetMousePos( int *mx, int *my ) +{ + gEngfuncs.GetMousePosition( mx, my ); +} + +/* +=========== +IN_ResetMouse + +FIXME: Call through to engine? +=========== +*/ +void IN_ResetMouse( void ) +{ + SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); +} + +/* +=========== +IN_MouseEvent +=========== +*/ +void DLLEXPORT IN_MouseEvent (int mstate) +{ + int i; + + if ( iMouseInUse || g_iVisibleMouse ) + return; + + // perform button actions + for (i=0 ; ivalue) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + if ( gHUD.GetSensitivity() != 0 ) + { + mouse_x *= gHUD.GetSensitivity(); + mouse_y *= gHUD.GetSensitivity(); + } + else + { + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + } + + // add mouse X/Y movement to cmd + if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + cmd->sidemove += m_side->value * mouse_x; + else + viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + viewangles[PITCH] += m_pitch->value * mouse_y; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + else + { + if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + { + cmd->upmove -= m_forward->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } + + // if the mouse has moved, force it to the center, so there's room to move + if ( mx || my ) + { + IN_ResetMouse(); + } + } + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +/* +//#define TRACE_TEST +#if defined( TRACE_TEST ) + { + int mx, my; + void V_Move( int mx, int my ); + IN_GetMousePos( &mx, &my ); + V_Move( mx, my ); + } +#endif +*/ +} + +/* +=========== +IN_Accumulate +=========== +*/ +void DLLEXPORT IN_Accumulate (void) +{ + //only accumulate mouse if we are not moving the camera with the mouse + if ( !iMouseInUse && !g_iVisibleMouse ) + { + if (mouseactive) + { + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); + + // force the mouse to the center, so there's room to move + IN_ResetMouse(); + } + } + +} + +/* +=================== +IN_ClearStates +=================== +*/ +void DLLEXPORT IN_ClearStates (void) +{ + if ( !mouseactive ) + return; + + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; +} + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick + joy_avail = 0; + + // abort startup if user requests no joystick + if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_idvalue == 0.0) + { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } + else + { + if ( strcmp ( joy_name->string, "joystick") != 0 ) + { + // notify user of advanced controller + gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + } + + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = (DWORD) joy_advaxisx->value; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisy->value; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisz->value; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisr->value; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisu->value; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisv->value; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } + + // compute the axes to collect from DirectInput + joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; + for (i = 0; i < JOY_MAX_AXES; i++) + { + if (dwAxisMap[i] != AxisNada) + { + joy_flags |= dwAxisFlags[i]; + } + } +} + + +/* +=========== +IN_Commands +=========== +*/ +void IN_Commands (void) +{ + int i, key_index; + DWORD buttonstate, povstate; + + if (!joy_avail) + { + return; + } + + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = ji.dwButtons; + for (i=0 ; i < (int)joy_numbuttons ; i++) + { + if ( (buttonstate & (1<value != 0.0) + { + ji.dwUpos += 100; + } + return 1; + } + else + { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Con_Printf ("IN_ReadJoystick: no response\n"); + // joy_avail = 0; + return 0; + } +} + + +/* +=========== +IN_JoyMove +=========== +*/ +void IN_JoyMove ( float frametime, usercmd_t *cmd ) +{ + float speed, aspeed; + float fAxisValue, fTemp; + int i; + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + + // complete initialization if first time in + // this is needed as cvars are not available at initialization time + if( joy_advancedinit != 1 ) + { + Joy_AdvancedUpdate_f(); + joy_advancedinit = 1; + } + + // verify joystick is available and that the user wants to use it + if (!joy_avail || !in_joystick->value) + { + return; + } + + // collect the joystick data, if possible + if (IN_ReadJoystick () != 1) + { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + + aspeed = speed * frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) + { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = (float) *pdwRawValue[i]; + // move centerpoint to zero + fAxisValue -= 32768.0; + + if (joy_wwhack2->value != 0.0) + { + if (dwAxisMap[i] == AxisTurn) + { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is factored out) + // then bounds check result to level out excessively high spin rates + fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is 0) + if (m_pitch->value < 0.0) + { + viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if(lookspring->value == 0.0) + { + V_StopPitchDrift(); + } + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold->value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold->value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + } + else + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (in_jlook.state & 1) + { + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if( lookspring->value == 0.0 ) + { + V_StopPitchDrift(); + } + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +} + +/* +=========== +IN_Move +=========== +*/ +void IN_Move ( float frametime, usercmd_t *cmd) +{ + if ( !iMouseInUse && mouseactive ) + { + IN_MouseMove ( frametime, cmd); + } + + IN_JoyMove ( frametime, cmd); +} + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + + gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); + gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + IN_StartupMouse (); + IN_StartupJoystick (); } \ No newline at end of file diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h index a772b3d3..23cd8acc 100644 --- a/cl_dll/kbutton.h +++ b/cl_dll/kbutton.h @@ -1,18 +1,18 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( KBUTTONH ) -#define KBUTTONH -#pragma once - -typedef struct kbutton_s -{ - int down[2]; // key nums holding it down - int state; // low bit is down state -} kbutton_t; - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + #endif // !KBUTTONH \ No newline at end of file diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index f43984dd..e46cf06d 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -1,188 +1,188 @@ -/*** -* -* 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. -* -****/ -// -// menu.cpp -// -// generic menu handler -// -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - - -#define MAX_MENU_STRING 512 -char g_szMenuString[MAX_MENU_STRING]; -char g_szPrelocalisedMenuString[MAX_MENU_STRING]; - -int KB_ConvertString( char *in, char **ppout ); - -DECLARE_MESSAGE( m_Menu, ShowMenu ); - -int CHudMenu :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( ShowMenu ); - - InitHUDData(); - - return 1; -} - -void CHudMenu :: InitHUDData( void ) -{ - m_fMenuDisplayed = 0; - m_bitsValidSlots = 0; - Reset(); -} - -void CHudMenu :: Reset( void ) -{ - g_szPrelocalisedMenuString[0] = 0; - m_fWaitingForMore = FALSE; -} - -int CHudMenu :: VidInit( void ) -{ - return 1; -} - -int CHudMenu :: Draw( float flTime ) -{ +/*** +* +* 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. +* +****/ +// +// menu.cpp +// +// generic menu handler +// +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + +#define MAX_MENU_STRING 512 +char g_szMenuString[MAX_MENU_STRING]; +char g_szPrelocalisedMenuString[MAX_MENU_STRING]; + +int KB_ConvertString( char *in, char **ppout ); + +DECLARE_MESSAGE( m_Menu, ShowMenu ); + +int CHudMenu :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( ShowMenu ); + + InitHUDData(); + + return 1; +} + +void CHudMenu :: InitHUDData( void ) +{ + m_fMenuDisplayed = 0; + m_bitsValidSlots = 0; + Reset(); +} + +void CHudMenu :: Reset( void ) +{ + g_szPrelocalisedMenuString[0] = 0; + m_fWaitingForMore = FALSE; +} + +int CHudMenu :: VidInit( void ) +{ + return 1; +} + +int CHudMenu :: Draw( float flTime ) +{ int i; - // check for if menu is set to disappear - if ( m_flShutoffTime > 0 ) - { - if ( m_flShutoffTime <= gHUD.m_flTime ) - { // times up, shutoff - m_fMenuDisplayed = 0; - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - } - - // don't draw the menu if the scoreboard is being shown + // check for if menu is set to disappear + if ( m_flShutoffTime > 0 ) + { + if ( m_flShutoffTime <= gHUD.m_flTime ) + { // times up, shutoff + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + } + + // don't draw the menu if the scoreboard is being shown - - // draw the menu, along the left-hand side of the screen - - // count the number of newlines - int nlc = 0; - for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) - { - if ( g_szMenuString[i] == '\n' ) - nlc++; - } - - // center it - int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text - int x = 20; - - i = 0; - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) - { - gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); - y += 12; - - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) - i++; - if ( g_szMenuString[i] == '\n' ) - i++; - } - - return 1; -} - -// selects an item from the menu -void CHudMenu :: SelectMenuItem( int menu_item ) -{ - // if menu_item is in a valid slot, send a menuselect command to the server - if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) - { - char szbuf[32]; - sprintf( szbuf, "menuselect %d\n", menu_item ); - ClientCmd( szbuf ); - - // remove the menu - m_fMenuDisplayed = 0; - m_iFlags &= ~HUD_ACTIVE; - } -} - - -// Message handler for ShowMenu message -// takes four values: -// short: a bitfield of keys that are valid input -// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. -// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string -// string: menu string to display -// if this message is never received, then scores will simply be the combined totals of the players. -int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) -{ - char *temp = NULL; - - BEGIN_READ( pbuf, iSize ); - - m_bitsValidSlots = READ_SHORT(); - int DisplayTime = READ_CHAR(); - int NeedMore = READ_BYTE(); - - if ( DisplayTime > 0 ) - m_flShutoffTime = DisplayTime + gHUD.m_flTime; - else - m_flShutoffTime = -1; - - if ( m_bitsValidSlots ) - { - if ( !m_fWaitingForMore ) // this is the start of a new menu - { - strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING ); - } - else - { // append to the current menu string - strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); - } - g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) - - if ( !NeedMore ) - { // we have the whole string, so we can localise it now - strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); - - // Swap in characters - if ( KB_ConvertString( g_szMenuString, &temp ) ) - { - strcpy( g_szMenuString, temp ); - free( temp ); - } - } - - m_fMenuDisplayed = 1; - m_iFlags |= HUD_ACTIVE; - } - else - { - m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off - m_iFlags &= ~HUD_ACTIVE; - } - - m_fWaitingForMore = NeedMore; - - return 1; -} + + // draw the menu, along the left-hand side of the screen + + // count the number of newlines + int nlc = 0; + for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + { + if ( g_szMenuString[i] == '\n' ) + nlc++; + } + + // center it + int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text + int x = 20; + + i = 0; + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) + { + gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); + y += 12; + + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) + i++; + if ( g_szMenuString[i] == '\n' ) + i++; + } + + return 1; +} + +// selects an item from the menu +void CHudMenu :: SelectMenuItem( int menu_item ) +{ + // if menu_item is in a valid slot, send a menuselect command to the server + if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) + { + char szbuf[32]; + sprintf( szbuf, "menuselect %d\n", menu_item ); + ClientCmd( szbuf ); + + // remove the menu + m_fMenuDisplayed = 0; + m_iFlags &= ~HUD_ACTIVE; + } +} + + +// Message handler for ShowMenu message +// takes four values: +// short: a bitfield of keys that are valid input +// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. +// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string +// string: menu string to display +// if this message is never received, then scores will simply be the combined totals of the players. +int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) +{ + char *temp = NULL; + + BEGIN_READ( pbuf, iSize ); + + m_bitsValidSlots = READ_SHORT(); + int DisplayTime = READ_CHAR(); + int NeedMore = READ_BYTE(); + + if ( DisplayTime > 0 ) + m_flShutoffTime = DisplayTime + gHUD.m_flTime; + else + m_flShutoffTime = -1; + + if ( m_bitsValidSlots ) + { + if ( !m_fWaitingForMore ) // this is the start of a new menu + { + strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING ); + } + else + { // append to the current menu string + strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); + } + g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) + + if ( !NeedMore ) + { // we have the whole string, so we can localise it now + strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + + // Swap in characters + if ( KB_ConvertString( g_szMenuString, &temp ) ) + { + strcpy( g_szMenuString, temp ); + free( temp ); + } + } + + m_fMenuDisplayed = 1; + m_iFlags |= HUD_ACTIVE; + } + else + { + m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off + m_iFlags &= ~HUD_ACTIVE; + } + + m_fWaitingForMore = NeedMore; + + return 1; +} diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index e6bb857d..c9b71aa5 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -1,536 +1,536 @@ -/*** -* -* 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. -* -****/ -// -// Message.cpp -// -// implementation of CHudMessage class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "parsemsg.h" - -DECLARE_MESSAGE( m_Message, HudText ) -DECLARE_MESSAGE( m_Message, GameTitle ) - -// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt -client_textmessage_t g_pCustomMessage; -char *g_pCustomName = "Custom"; -char g_pCustomText[1024]; - -int CHudMessage::Init(void) -{ - HOOK_MESSAGE( HudText ); - HOOK_MESSAGE( GameTitle ); - - gHUD.AddHudElem(this); - - Reset(); - - return 1; -}; - -int CHudMessage::VidInit( void ) -{ - m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); - m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); - - return 1; -}; - - -void CHudMessage::Reset( void ) -{ - memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); - memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); - - m_gameTitleTime = 0; - m_pGameTitle = NULL; -} - - -float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) -{ - float fadeTime = fadein + hold; - float fadeBlend; - - if ( localTime < 0 ) - return 0; - - if ( localTime < fadein ) - { - fadeBlend = 1 - ((fadein - localTime) / fadein); - } - else if ( localTime > fadeTime ) - { - if ( fadeout > 0 ) - fadeBlend = 1 - ((localTime - fadeTime) / fadeout); - else - fadeBlend = 0; - } - else - fadeBlend = 1; - - return fadeBlend; -} - - -int CHudMessage::XPosition( float x, int width, int totalWidth ) -{ - int xPos; - - if ( x == -1 ) - { - xPos = (ScreenWidth - width) / 2; - } - else - { - if ( x < 0 ) - xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right - else - xPos = x * ScreenWidth; - } - - if ( xPos + width > ScreenWidth ) - xPos = ScreenWidth - width; - else if ( xPos < 0 ) - xPos = 0; - - return xPos; -} - - -int CHudMessage::YPosition( float y, int height ) -{ - int yPos; - - if ( y == -1 ) // Centered? - yPos = (ScreenHeight - height) * 0.5; - else - { - // Alight bottom? - if ( y < 0 ) - yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom - else // align top - yPos = y * ScreenHeight; - } - - if ( yPos + height > ScreenHeight ) - yPos = ScreenHeight - height; - else if ( yPos < 0 ) - yPos = 0; - - return yPos; -} - - -void CHudMessage::MessageScanNextChar( void ) -{ - int srcRed, srcGreen, srcBlue, destRed = 0, destGreen = 0, destBlue = 0; - int blend; - - srcRed = m_parms.pMessage->r1; - srcGreen = m_parms.pMessage->g1; - srcBlue = m_parms.pMessage->b1; - blend = 0; // Pure source - - switch( m_parms.pMessage->effect ) - { - // Fade-in / Fade-out - case 0: - case 1: - destRed = destGreen = destBlue = 0; - blend = m_parms.fadeBlend; - break; - - case 2: - m_parms.charTime += m_parms.pMessage->fadein; - if ( m_parms.charTime > m_parms.time ) - { - srcRed = srcGreen = srcBlue = 0; - blend = 0; // pure source - } - else - { - float deltaTime = m_parms.time - m_parms.charTime; - - destRed = destGreen = destBlue = 0; - if ( m_parms.time > m_parms.fadeTime ) - { - blend = m_parms.fadeBlend; - } - else if ( deltaTime > m_parms.pMessage->fxtime ) - blend = 0; // pure dest - else - { - destRed = m_parms.pMessage->r2; - destGreen = m_parms.pMessage->g2; - destBlue = m_parms.pMessage->b2; - blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); - } - } - break; - } - if ( blend > 255 ) - blend = 255; - else if ( blend < 0 ) - blend = 0; - - m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; - m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; - m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; - - if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) - { - if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) - TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); - } -} - - -void CHudMessage::MessageScanStart( void ) -{ - switch( m_parms.pMessage->effect ) - { - // Fade-in / out with flicker - case 1: - case 0: - m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; - - - if ( m_parms.time < m_parms.pMessage->fadein ) - { - m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); - } - else if ( m_parms.time > m_parms.fadeTime ) - { - if ( m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); - else - m_parms.fadeBlend = 255; // Pure dest (off) - } - else - m_parms.fadeBlend = 0; // Pure source (on) - m_parms.charTime = 0; - - if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) - m_parms.charTime = 1; - break; - - case 2: - m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; - - if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); - else - m_parms.fadeBlend = 0; - break; - } -} - - -void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) -{ - int i, j, length, width; - const char *pText; - unsigned char line[80]; - - pText = pMessage->pMessage; - // Count lines - m_parms.lines = 1; - m_parms.time = time; - m_parms.pMessage = pMessage; - length = 0; - width = 0; - m_parms.totalWidth = 0; - while ( *pText ) - { - if ( *pText == '\n' ) - { - m_parms.lines++; - if ( width > m_parms.totalWidth ) - m_parms.totalWidth = width; - width = 0; - } - else - width += gHUD.m_scrinfo.charWidths[*pText]; - pText++; - length++; - } - m_parms.length = length; - m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); - - - m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); - pText = pMessage->pMessage; - - m_parms.charTime = 0; - - MessageScanStart(); - - for ( i = 0; i < m_parms.lines; i++ ) - { - m_parms.lineLength = 0; - m_parms.width = 0; - while ( *pText && *pText != '\n' ) - { - unsigned char c = *pText; - line[m_parms.lineLength] = c; - m_parms.width += gHUD.m_scrinfo.charWidths[c]; - m_parms.lineLength++; - pText++; - } - pText++; // Skip LF - line[m_parms.lineLength] = 0; - - m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); - - for ( j = 0; j < m_parms.lineLength; j++ ) - { - m_parms.text = line[j]; - int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; - MessageScanNextChar(); - - if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth ) - TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); - m_parms.x = next; - } - - m_parms.y += gHUD.m_scrinfo.iCharHeight; - } -} - - -int CHudMessage::Draw( float fTime ) -{ - int i, drawn; - client_textmessage_t *pMessage; - float endTime; - - drawn = 0; - - if ( m_gameTitleTime > 0 ) - { - float localTime = gHUD.m_flTime - m_gameTitleTime; - float brightness; - - // Maybe timer isn't set yet - if ( m_gameTitleTime > gHUD.m_flTime ) - m_gameTitleTime = gHUD.m_flTime; - - if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) - m_gameTitleTime = 0; - else - { - brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); - - int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; - int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; - int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; - - int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); - int y = YPosition( m_pGameTitle->y, fullHeight ); - - - SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); - - SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); - - drawn = 1; - } - } - // Fixup level transitions - for ( i = 0; i < maxHUDMessages; i++ ) - { - // Assume m_parms.time contains last time - if ( m_pMessages[i] ) - { - pMessage = m_pMessages[i]; - if ( m_startTime[i] > gHUD.m_flTime ) - m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this - } - } - - for ( i = 0; i < maxHUDMessages; i++ ) - { - if ( m_pMessages[i] ) - { - pMessage = m_pMessages[i]; - - // This is when the message is over - switch( pMessage->effect ) - { - case 0: - case 1: - endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime; - break; - - // Fade in is per character in scanning messages - case 2: - endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime; - break; - } - - if ( fTime <= endTime ) - { - float messageTime = fTime - m_startTime[i]; - - // Draw the message - // effect 0 is fade in/fade out - // effect 1 is flickery credits - // effect 2 is write out (training room) - MessageDrawScan( pMessage, messageTime ); - - drawn++; - } - else - { - // The message is over - m_pMessages[i] = NULL; - } - } - } - - // Remember the time -- to fix up level transitions - m_parms.time = gHUD.m_flTime; - // Don't call until we get another message - if ( !drawn ) - m_iFlags &= ~HUD_ACTIVE; - - return 1; -} - - -void CHudMessage::MessageAdd( const char *pName, float time ) -{ - int i,j; - client_textmessage_t *tempMessage; - - for ( i = 0; i < maxHUDMessages; i++ ) - { - if ( !m_pMessages[i] ) - { - // Trim off a leading # if it's there - if ( pName[0] == '#' ) - tempMessage = TextMessageGet( pName+1 ); - else - tempMessage = TextMessageGet( pName ); - // If we couldnt find it in the titles.txt, just create it - if ( !tempMessage ) - { - g_pCustomMessage.effect = 2; - g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; - g_pCustomMessage.r2 = 240; - g_pCustomMessage.g2 = 110; - g_pCustomMessage.b2 = 0; - g_pCustomMessage.a2 = 0; - g_pCustomMessage.x = -1; // Centered - g_pCustomMessage.y = 0.7; - g_pCustomMessage.fadein = 0.01; - g_pCustomMessage.fadeout = 1.5; - g_pCustomMessage.fxtime = 0.25; - g_pCustomMessage.holdtime = 5; - g_pCustomMessage.pName = g_pCustomName; - strcpy( g_pCustomText, pName ); - g_pCustomMessage.pMessage = g_pCustomText; - - tempMessage = &g_pCustomMessage; - } - - for ( j = 0; j < maxHUDMessages; j++ ) - { - if ( m_pMessages[j] ) - { - // is this message already in the list - if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) - { - return; - } - - // get rid of any other messages in same location (only one displays at a time) - if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) - { - if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) - { - m_pMessages[j] = NULL; - } - } - } - } - - m_pMessages[i] = tempMessage; - m_startTime[i] = time; - return; - } - } -} - - -int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - char *pString = READ_STRING(); - - MessageAdd( pString, gHUD.m_flTime ); - // Remember the time -- to fix up level transitions - m_parms.time = gHUD.m_flTime; - - // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - - return 1; -} - - -int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) -{ - m_pGameTitle = TextMessageGet( "GAMETITLE" ); - if ( m_pGameTitle != NULL ) - { - m_gameTitleTime = gHUD.m_flTime; - - // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - } - - return 1; -} - -void CHudMessage::MessageAdd(client_textmessage_t * newMessage ) -{ - m_parms.time = gHUD.m_flTime; - - // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) - m_iFlags |= HUD_ACTIVE; - - for ( int i = 0; i < maxHUDMessages; i++ ) - { - if ( !m_pMessages[i] ) - { - m_pMessages[i] = newMessage; - m_startTime[i] = gHUD.m_flTime; - return; - } - } - -} +/*** +* +* 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. +* +****/ +// +// Message.cpp +// +// implementation of CHudMessage class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE( m_Message, HudText ) +DECLARE_MESSAGE( m_Message, GameTitle ) + +// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt +client_textmessage_t g_pCustomMessage; +char *g_pCustomName = "Custom"; +char g_pCustomText[1024]; + +int CHudMessage::Init(void) +{ + HOOK_MESSAGE( HudText ); + HOOK_MESSAGE( GameTitle ); + + gHUD.AddHudElem(this); + + Reset(); + + return 1; +}; + +int CHudMessage::VidInit( void ) +{ + m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); + m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); + + return 1; +}; + + +void CHudMessage::Reset( void ) +{ + memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); + memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); + + m_gameTitleTime = 0; + m_pGameTitle = NULL; +} + + +float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) +{ + float fadeTime = fadein + hold; + float fadeBlend; + + if ( localTime < 0 ) + return 0; + + if ( localTime < fadein ) + { + fadeBlend = 1 - ((fadein - localTime) / fadein); + } + else if ( localTime > fadeTime ) + { + if ( fadeout > 0 ) + fadeBlend = 1 - ((localTime - fadeTime) / fadeout); + else + fadeBlend = 0; + } + else + fadeBlend = 1; + + return fadeBlend; +} + + +int CHudMessage::XPosition( float x, int width, int totalWidth ) +{ + int xPos; + + if ( x == -1 ) + { + xPos = (ScreenWidth - width) / 2; + } + else + { + if ( x < 0 ) + xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right + else + xPos = x * ScreenWidth; + } + + if ( xPos + width > ScreenWidth ) + xPos = ScreenWidth - width; + else if ( xPos < 0 ) + xPos = 0; + + return xPos; +} + + +int CHudMessage::YPosition( float y, int height ) +{ + int yPos; + + if ( y == -1 ) // Centered? + yPos = (ScreenHeight - height) * 0.5; + else + { + // Alight bottom? + if ( y < 0 ) + yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom + else // align top + yPos = y * ScreenHeight; + } + + if ( yPos + height > ScreenHeight ) + yPos = ScreenHeight - height; + else if ( yPos < 0 ) + yPos = 0; + + return yPos; +} + + +void CHudMessage::MessageScanNextChar( void ) +{ + int srcRed, srcGreen, srcBlue, destRed = 0, destGreen = 0, destBlue = 0; + int blend; + + srcRed = m_parms.pMessage->r1; + srcGreen = m_parms.pMessage->g1; + srcBlue = m_parms.pMessage->b1; + blend = 0; // Pure source + + switch( m_parms.pMessage->effect ) + { + // Fade-in / Fade-out + case 0: + case 1: + destRed = destGreen = destBlue = 0; + blend = m_parms.fadeBlend; + break; + + case 2: + m_parms.charTime += m_parms.pMessage->fadein; + if ( m_parms.charTime > m_parms.time ) + { + srcRed = srcGreen = srcBlue = 0; + blend = 0; // pure source + } + else + { + float deltaTime = m_parms.time - m_parms.charTime; + + destRed = destGreen = destBlue = 0; + if ( m_parms.time > m_parms.fadeTime ) + { + blend = m_parms.fadeBlend; + } + else if ( deltaTime > m_parms.pMessage->fxtime ) + blend = 0; // pure dest + else + { + destRed = m_parms.pMessage->r2; + destGreen = m_parms.pMessage->g2; + destBlue = m_parms.pMessage->b2; + blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); + } + } + break; + } + if ( blend > 255 ) + blend = 255; + else if ( blend < 0 ) + blend = 0; + + m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; + m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; + m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; + + if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) + { + if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); + } +} + + +void CHudMessage::MessageScanStart( void ) +{ + switch( m_parms.pMessage->effect ) + { + // Fade-in / out with flicker + case 1: + case 0: + m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; + + + if ( m_parms.time < m_parms.pMessage->fadein ) + { + m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); + } + else if ( m_parms.time > m_parms.fadeTime ) + { + if ( m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 255; // Pure dest (off) + } + else + m_parms.fadeBlend = 0; // Pure source (on) + m_parms.charTime = 0; + + if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) + m_parms.charTime = 1; + break; + + case 2: + m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; + + if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + else + m_parms.fadeBlend = 0; + break; + } +} + + +void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) +{ + int i, j, length, width; + const char *pText; + unsigned char line[80]; + + pText = pMessage->pMessage; + // Count lines + m_parms.lines = 1; + m_parms.time = time; + m_parms.pMessage = pMessage; + length = 0; + width = 0; + m_parms.totalWidth = 0; + while ( *pText ) + { + if ( *pText == '\n' ) + { + m_parms.lines++; + if ( width > m_parms.totalWidth ) + m_parms.totalWidth = width; + width = 0; + } + else + width += gHUD.m_scrinfo.charWidths[*pText]; + pText++; + length++; + } + m_parms.length = length; + m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); + + + m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); + pText = pMessage->pMessage; + + m_parms.charTime = 0; + + MessageScanStart(); + + for ( i = 0; i < m_parms.lines; i++ ) + { + m_parms.lineLength = 0; + m_parms.width = 0; + while ( *pText && *pText != '\n' ) + { + unsigned char c = *pText; + line[m_parms.lineLength] = c; + m_parms.width += gHUD.m_scrinfo.charWidths[c]; + m_parms.lineLength++; + pText++; + } + pText++; // Skip LF + line[m_parms.lineLength] = 0; + + m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); + + for ( j = 0; j < m_parms.lineLength; j++ ) + { + m_parms.text = line[j]; + int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; + MessageScanNextChar(); + + if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth ) + TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); + m_parms.x = next; + } + + m_parms.y += gHUD.m_scrinfo.iCharHeight; + } +} + + +int CHudMessage::Draw( float fTime ) +{ + int i, drawn; + client_textmessage_t *pMessage; + float endTime; + + drawn = 0; + + if ( m_gameTitleTime > 0 ) + { + float localTime = gHUD.m_flTime - m_gameTitleTime; + float brightness; + + // Maybe timer isn't set yet + if ( m_gameTitleTime > gHUD.m_flTime ) + m_gameTitleTime = gHUD.m_flTime; + + if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) + m_gameTitleTime = 0; + else + { + brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); + + int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; + int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; + int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; + + int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); + int y = YPosition( m_pGameTitle->y, fullHeight ); + + + SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); + + SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); + + drawn = 1; + } + } + // Fixup level transitions + for ( i = 0; i < maxHUDMessages; i++ ) + { + // Assume m_parms.time contains last time + if ( m_pMessages[i] ) + { + pMessage = m_pMessages[i]; + if ( m_startTime[i] > gHUD.m_flTime ) + m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this + } + } + + for ( i = 0; i < maxHUDMessages; i++ ) + { + if ( m_pMessages[i] ) + { + pMessage = m_pMessages[i]; + + // This is when the message is over + switch( pMessage->effect ) + { + case 0: + case 1: + endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime; + break; + + // Fade in is per character in scanning messages + case 2: + endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime; + break; + } + + if ( fTime <= endTime ) + { + float messageTime = fTime - m_startTime[i]; + + // Draw the message + // effect 0 is fade in/fade out + // effect 1 is flickery credits + // effect 2 is write out (training room) + MessageDrawScan( pMessage, messageTime ); + + drawn++; + } + else + { + // The message is over + m_pMessages[i] = NULL; + } + } + } + + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + // Don't call until we get another message + if ( !drawn ) + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} + + +void CHudMessage::MessageAdd( const char *pName, float time ) +{ + int i,j; + client_textmessage_t *tempMessage; + + for ( i = 0; i < maxHUDMessages; i++ ) + { + if ( !m_pMessages[i] ) + { + // Trim off a leading # if it's there + if ( pName[0] == '#' ) + tempMessage = TextMessageGet( pName+1 ); + else + tempMessage = TextMessageGet( pName ); + // If we couldnt find it in the titles.txt, just create it + if ( !tempMessage ) + { + g_pCustomMessage.effect = 2; + g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; + g_pCustomMessage.r2 = 240; + g_pCustomMessage.g2 = 110; + g_pCustomMessage.b2 = 0; + g_pCustomMessage.a2 = 0; + g_pCustomMessage.x = -1; // Centered + g_pCustomMessage.y = 0.7; + g_pCustomMessage.fadein = 0.01; + g_pCustomMessage.fadeout = 1.5; + g_pCustomMessage.fxtime = 0.25; + g_pCustomMessage.holdtime = 5; + g_pCustomMessage.pName = g_pCustomName; + strcpy( g_pCustomText, pName ); + g_pCustomMessage.pMessage = g_pCustomText; + + tempMessage = &g_pCustomMessage; + } + + for ( j = 0; j < maxHUDMessages; j++ ) + { + if ( m_pMessages[j] ) + { + // is this message already in the list + if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) + { + return; + } + + // get rid of any other messages in same location (only one displays at a time) + if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) + { + if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) + { + m_pMessages[j] = NULL; + } + } + } + } + + m_pMessages[i] = tempMessage; + m_startTime[i] = time; + return; + } + } +} + + +int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + char *pString = READ_STRING(); + + MessageAdd( pString, gHUD.m_flTime ); + // Remember the time -- to fix up level transitions + m_parms.time = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + + return 1; +} + + +int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) +{ + m_pGameTitle = TextMessageGet( "GAMETITLE" ); + if ( m_pGameTitle != NULL ) + { + m_gameTitleTime = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + } + + return 1; +} + +void CHudMessage::MessageAdd(client_textmessage_t * newMessage ) +{ + m_parms.time = gHUD.m_flTime; + + // Turn on drawing + if ( !(m_iFlags & HUD_ACTIVE) ) + m_iFlags |= HUD_ACTIVE; + + for ( int i = 0; i < maxHUDMessages; i++ ) + { + if ( !m_pMessages[i] ) + { + m_pMessages[i] = newMessage; + m_startTime[i] = gHUD.m_flTime; + return; + } + } + +} diff --git a/cl_dll/overview.cpp b/cl_dll/overview.cpp index 4f0ad0a3..04f1a984 100644 --- a/cl_dll/overview.cpp +++ b/cl_dll/overview.cpp @@ -1,163 +1,163 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "hud.h" -#include "cl_util.h" -#include "cl_entity.h" -#include "triangleapi.h" +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" #include "overview.h" - -// these are included for the math functions -#include "com_model.h" -#include "studio_util.h" - -#pragma warning(disable: 4244) - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CHudOverview::Init() -{ - gHUD.AddHudElem(this); - - m_iFlags |= HUD_ACTIVE; - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: Loads new icons -//----------------------------------------------------------------------------- -int CHudOverview::VidInit() -{ - m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); - m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flTime - -// intermission - -//----------------------------------------------------------------------------- -int CHudOverview::Draw(float flTime) -{ + +// these are included for the math functions +#include "com_model.h" +#include "studio_util.h" + +#pragma warning(disable: 4244) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudOverview::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudOverview::VidInit() +{ + m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); + m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudOverview::Draw(float flTime) +{ #if 0 - // only draw in overview mode - if (!gEngfuncs.Overview_GetOverviewState()) - return 1; - - // make sure we have player info -// gViewPort->GetAllPlayersInfo(); + // only draw in overview mode + if (!gEngfuncs.Overview_GetOverviewState()) + return 1; + + // make sure we have player info +// gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); - - // calculate player size on the overview - int x1, y1, x2, y2; - float v0[3]={0,0,0}, v1[3]={64,64,0}; - gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); - gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); - float scale = abs(x2 - x1); - - // loop through all the players and draw them on the map - for (int i = 1; i < MAX_PLAYERS; i++) - { - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); - - if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) - { - int x, y, z = 0; - float v[3]={pl->origin[0], pl->origin[1], 0}; - gEngfuncs.Overview_WorldToScreen(v, &x, &y); - - // hack in some team colors - float r, g, bc; - if (g_PlayerExtraInfo[i].teamnumber == 1) - { - r = 0.0f; g = 0.0f; bc = 1.0f; - } - else if (g_PlayerExtraInfo[i].teamnumber == 2) - { - r = 1.0f; g = 0.0f; bc = 0.0f; - } - else - { - // just use the default orange color if the team isn't set - r = 1.0f; g = 0.7f; bc = 0.0f; - } - - // set the current texture - gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); - - // additive render mode - gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); - - // no culling - gEngfuncs.pTriAPI->CullFace(TRI_NONE); - - // draw a square - gEngfuncs.pTriAPI->Begin(TRI_QUADS); - - // set the color to be that of the team - gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); - - // calculate rotational matrix - vec3_t a, b, angles; - float rmatrix[3][4]; // transformation matrix - VectorCopy(pl->angles, angles); - angles[0] = 0.0f; - angles[1] += 90.f; - angles[1] = -angles[1]; - angles[2] = 0.0f; - AngleMatrix(angles, rmatrix); - a[2] = 0; - - a[0] = -scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); - - a[0]=-scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - a[0]=scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - a[0]=scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - // finish up - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - - // draw the players name and health underneath - char string[256]; - sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); - DrawConsoleString(x, y + (1.1 * scale), string); - } - } - + + // calculate player size on the overview + int x1, y1, x2, y2; + float v0[3]={0,0,0}, v1[3]={64,64,0}; + gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); + gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); + float scale = abs(x2 - x1); + + // loop through all the players and draw them on the map + for (int i = 1; i < MAX_PLAYERS; i++) + { + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); + + if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) + { + int x, y, z = 0; + float v[3]={pl->origin[0], pl->origin[1], 0}; + gEngfuncs.Overview_WorldToScreen(v, &x, &y); + + // hack in some team colors + float r, g, bc; + if (g_PlayerExtraInfo[i].teamnumber == 1) + { + r = 0.0f; g = 0.0f; bc = 1.0f; + } + else if (g_PlayerExtraInfo[i].teamnumber == 2) + { + r = 1.0f; g = 0.0f; bc = 0.0f; + } + else + { + // just use the default orange color if the team isn't set + r = 1.0f; g = 0.7f; bc = 0.0f; + } + + // set the current texture + gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); + + // additive render mode + gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); + + // no culling + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + // draw a square + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + + // set the color to be that of the team + gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); + + // calculate rotational matrix + vec3_t a, b, angles; + float rmatrix[3][4]; // transformation matrix + VectorCopy(pl->angles, angles); + angles[0] = 0.0f; + angles[1] += 90.f; + angles[1] = -angles[1]; + angles[2] = 0.0f; + AngleMatrix(angles, rmatrix); + a[2] = 0; + + a[0] = -scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); + + a[0]=-scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + // finish up + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + + // draw the players name and health underneath + char string[256]; + sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); + DrawConsoleString(x, y + (1.1 * scale), string); + } + } + #endif - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: called every time a server is connected to -//----------------------------------------------------------------------------- -void CHudOverview::InitHUDData() -{ -// this block would force the spectator view to be on -// gEngfuncs.Overview_SetDrawOverview( 1 ); -// gEngfuncs.Overview_SetDrawInset( 0 ); -} - + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: called every time a server is connected to +//----------------------------------------------------------------------------- +void CHudOverview::InitHUDData() +{ +// this block would force the spectator view to be on +// gEngfuncs.Overview_SetDrawOverview( 1 ); +// gEngfuncs.Overview_SetDrawInset( 0 ); +} + diff --git a/cl_dll/overview.h b/cl_dll/overview.h index 7f0502e3..4de9ae75 100644 --- a/cl_dll/overview.h +++ b/cl_dll/overview.h @@ -1,31 +1,31 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef OVERVIEW_H -#define OVERVIEW_H -#pragma once - - -//----------------------------------------------------------------------------- -// Purpose: Handles the drawing of the top-down map and all the things on it -//----------------------------------------------------------------------------- -class CHudOverview : public CHudBase -{ -public: - int Init(); - int VidInit(); - - int Draw(float flTime); - void InitHUDData( void ); - -private: - HSPRITE m_hsprPlayer; - HSPRITE m_hsprViewcone; -}; - - -#endif // OVERVIEW_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef OVERVIEW_H +#define OVERVIEW_H +#pragma once + + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the top-down map and all the things on it +//----------------------------------------------------------------------------- +class CHudOverview : public CHudBase +{ +public: + int Init(); + int VidInit(); + + int Draw(float flTime); + void InitHUDData( void ); + +private: + HSPRITE m_hsprPlayer; + HSPRITE m_hsprViewcone; +}; + + +#endif // OVERVIEW_H diff --git a/cl_dll/parsemsg.cpp b/cl_dll/parsemsg.cpp index 84f03b8b..f242ff0d 100644 --- a/cl_dll/parsemsg.cpp +++ b/cl_dll/parsemsg.cpp @@ -1,166 +1,166 @@ -/*** -* -* 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. -* -****/ -// -// parsemsg.cpp -// -typedef unsigned char byte; -#define true 1 - -static byte *gpBuf; -static int giSize; -static int giRead; -static int giBadRead; - -void BEGIN_READ( void *buf, int size ) -{ - giRead = 0; - giBadRead = 0; - giSize = size; - gpBuf = (byte*)buf; -} - - -int READ_CHAR( void ) -{ - int c; - - if (giRead + 1 > giSize) - { - giBadRead = true; - return -1; - } - - c = (signed char)gpBuf[giRead]; - giRead++; - - return c; -} - -int READ_BYTE( void ) -{ - int c; - - if (giRead+1 > giSize) - { - giBadRead = true; - return -1; - } - - c = (unsigned char)gpBuf[giRead]; - giRead++; - - return c; -} - -int READ_SHORT( void ) -{ - int c; - - if (giRead+2 > giSize) - { - giBadRead = true; - return -1; - } - - c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); - - giRead += 2; - - return c; -} - -int READ_WORD( void ) -{ - return READ_SHORT(); -} - - -int READ_LONG( void ) -{ - int c; - - if (giRead+4 > giSize) - { - giBadRead = true; - return -1; - } - - c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); - - giRead += 4; - - return c; -} - -float READ_FLOAT( void ) -{ - union - { - byte b[4]; - float f; - int l; - } dat; - - dat.b[0] = gpBuf[giRead]; - dat.b[1] = gpBuf[giRead+1]; - dat.b[2] = gpBuf[giRead+2]; - dat.b[3] = gpBuf[giRead+3]; - giRead += 4; - -// dat.l = LittleLong (dat.l); - - return dat.f; -} - -char* READ_STRING( void ) -{ - static char string[2048]; - int l,c; - - string[0] = 0; - - l = 0; - do - { - if ( giRead+1 > giSize ) - break; // no more characters - - c = READ_BYTE(); - if (c == -1 || c == 0) - break; - string[l] = c; - l++; - } while (l < sizeof(string)-1); - - string[l] = 0; - - return string; -} - -float READ_COORD( void ) -{ - return (float)(READ_SHORT() * (1.0/8)); -} - -float READ_ANGLE( void ) -{ - return (float)(READ_CHAR() * (360.0/256)); -} - -float READ_HIRESANGLE( void ) -{ - return (float)(READ_SHORT() * (360.0/65536)); -} - +/*** +* +* 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. +* +****/ +// +// parsemsg.cpp +// +typedef unsigned char byte; +#define true 1 + +static byte *gpBuf; +static int giSize; +static int giRead; +static int giBadRead; + +void BEGIN_READ( void *buf, int size ) +{ + giRead = 0; + giBadRead = 0; + giSize = size; + gpBuf = (byte*)buf; +} + + +int READ_CHAR( void ) +{ + int c; + + if (giRead + 1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (signed char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_BYTE( void ) +{ + int c; + + if (giRead+1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (unsigned char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_SHORT( void ) +{ + int c; + + if (giRead+2 > giSize) + { + giBadRead = true; + return -1; + } + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); + + giRead += 2; + + return c; +} + +int READ_WORD( void ) +{ + return READ_SHORT(); +} + + +int READ_LONG( void ) +{ + int c; + + if (giRead+4 > giSize) + { + giBadRead = true; + return -1; + } + + c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); + + giRead += 4; + + return c; +} + +float READ_FLOAT( void ) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead+1]; + dat.b[2] = gpBuf[giRead+2]; + dat.b[3] = gpBuf[giRead+3]; + giRead += 4; + +// dat.l = LittleLong (dat.l); + + return dat.f; +} + +char* READ_STRING( void ) +{ + static char string[2048]; + int l,c; + + string[0] = 0; + + l = 0; + do + { + if ( giRead+1 > giSize ) + break; // no more characters + + c = READ_BYTE(); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float READ_COORD( void ) +{ + return (float)(READ_SHORT() * (1.0/8)); +} + +float READ_ANGLE( void ) +{ + return (float)(READ_CHAR() * (360.0/256)); +} + +float READ_HIRESANGLE( void ) +{ + return (float)(READ_SHORT() * (360.0/65536)); +} + diff --git a/cl_dll/parsemsg.h b/cl_dll/parsemsg.h index ab8ff154..0e6bd2a3 100644 --- a/cl_dll/parsemsg.h +++ b/cl_dll/parsemsg.h @@ -1,40 +1,40 @@ -/*** -* -* 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. -* -****/ -// -// parsemsg.h -// - -#define ASSERT( x ) - -void BEGIN_READ( void *buf, int size ); -int READ_CHAR( void ); -int READ_BYTE( void ); -int READ_SHORT( void ); -int READ_WORD( void ); -int READ_LONG( void ); -float READ_FLOAT( void ); -char* READ_STRING( void ); -float READ_COORD( void ); -float READ_ANGLE( void ); -float READ_HIRESANGLE( void ); - - - - - - - - - +/*** +* +* 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. +* +****/ +// +// parsemsg.h +// + +#define ASSERT( x ) + +void BEGIN_READ( void *buf, int size ); +int READ_CHAR( void ); +int READ_BYTE( void ); +int READ_SHORT( void ); +int READ_WORD( void ); +int READ_LONG( void ); +float READ_FLOAT( void ); +char* READ_STRING( void ); +float READ_COORD( void ); +float READ_ANGLE( void ); +float READ_HIRESANGLE( void ); + + + + + + + + + diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index ddfa00fe..10cf6ef3 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -1,313 +1,313 @@ -/*** -* -* 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. -* -****/ -// -// saytext.cpp -// -// implementation of CHudSayText class -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - - -extern float *GetClientColor( int clientIndex ); - -#define MAX_LINES 5 -#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ - -// allow 20 pixels on either side of the text -#define MAX_LINE_WIDTH ( ScreenWidth - 40 ) -#define LINE_START 10 -static float SCROLL_SPEED = 5; - -static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; -static float *g_pflNameColors[ MAX_LINES + 1 ]; -static int g_iNameLengths[ MAX_LINES + 1 ]; -static float flScrollTime = 0; // the time at which the lines next scroll up - -static int Y_START = 0; -static int line_height = 0; - -DECLARE_MESSAGE( m_SayText, SayText ); - -int CHudSayText :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( SayText ); - - InitHUDData(); - - m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); - m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); - - m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission - - return 1; -} - - -void CHudSayText :: InitHUDData( void ) -{ - memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); - memset( g_pflNameColors, 0, sizeof g_pflNameColors ); - memset( g_iNameLengths, 0, sizeof g_iNameLengths ); -} - -int CHudSayText :: VidInit( void ) -{ - return 1; -} - - -int ScrollTextUp( void ) -{ - ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer - g_szLineBuffer[MAX_LINES][0] = 0; - memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line - memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); - memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); - g_szLineBuffer[MAX_LINES-1][0] = 0; - - if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines - { - g_szLineBuffer[0][0] = 2; - return 1 + ScrollTextUp(); - } - - return 1; -} - -int CHudSayText :: Draw( float flTime ) -{ - int y = Y_START; - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); - - if ( flScrollTime <= flTime ) - { - if ( *g_szLineBuffer[0] ) - { - flScrollTime = flTime + m_HUD_saytext_time->value; - // push the console up - ScrollTextUp(); - } - else - { // buffer is empty, just disable drawing of this section - m_iFlags &= ~HUD_ACTIVE; - } - } - - for ( int i = 0; i < MAX_LINES; i++ ) - { - if ( *g_szLineBuffer[i] ) - { - if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) - { - // it's a saytext string - static char buf[MAX_PLAYER_NAME_LENGTH+32]; - - // draw the first x characters in the player color - strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); - buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; - DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); - int x = DrawConsoleString( LINE_START, y, buf ); - - // color is reset after each string draw - DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); - } - else - { - // normal draw - DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); - } - } - - y += line_height; - } - - - return 1; -} - -int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int client_index = READ_BYTE(); // the client who spoke the message - SayTextPrint( READ_STRING(), iSize - 1, client_index ); - - return 1; -} - -void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) -{ +/*** +* +* 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. +* +****/ +// +// saytext.cpp +// +// implementation of CHudSayText class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + +extern float *GetClientColor( int clientIndex ); + +#define MAX_LINES 5 +#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ + +// allow 20 pixels on either side of the text +#define MAX_LINE_WIDTH ( ScreenWidth - 40 ) +#define LINE_START 10 +static float SCROLL_SPEED = 5; + +static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; +static float *g_pflNameColors[ MAX_LINES + 1 ]; +static int g_iNameLengths[ MAX_LINES + 1 ]; +static float flScrollTime = 0; // the time at which the lines next scroll up + +static int Y_START = 0; +static int line_height = 0; + +DECLARE_MESSAGE( m_SayText, SayText ); + +int CHudSayText :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( SayText ); + + InitHUDData(); + + m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); + m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); + + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + + return 1; +} + + +void CHudSayText :: InitHUDData( void ) +{ + memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); + memset( g_pflNameColors, 0, sizeof g_pflNameColors ); + memset( g_iNameLengths, 0, sizeof g_iNameLengths ); +} + +int CHudSayText :: VidInit( void ) +{ + return 1; +} + + +int ScrollTextUp( void ) +{ + ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer + g_szLineBuffer[MAX_LINES][0] = 0; + memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line + memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); + memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); + g_szLineBuffer[MAX_LINES-1][0] = 0; + + if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines + { + g_szLineBuffer[0][0] = 2; + return 1 + ScrollTextUp(); + } + + return 1; +} + +int CHudSayText :: Draw( float flTime ) +{ + int y = Y_START; + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + if ( flScrollTime <= flTime ) + { + if ( *g_szLineBuffer[0] ) + { + flScrollTime = flTime + m_HUD_saytext_time->value; + // push the console up + ScrollTextUp(); + } + else + { // buffer is empty, just disable drawing of this section + m_iFlags &= ~HUD_ACTIVE; + } + } + + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( *g_szLineBuffer[i] ) + { + if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + { + // it's a saytext string + static char buf[MAX_PLAYER_NAME_LENGTH+32]; + + // draw the first x characters in the player color + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); + buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + int x = DrawConsoleString( LINE_START, y, buf ); + + // color is reset after each string draw + DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); + } + else + { + // normal draw + DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + } + } + + y += line_height; + } + + + return 1; +} + +int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int client_index = READ_BYTE(); // the client who spoke the message + SayTextPrint( READ_STRING(), iSize - 1, client_index ); + + return 1; +} + +void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) +{ int i; - ConsolePrint( pszBuf ); - - // find an empty string slot - for ( i = 0; i < MAX_LINES; i++ ) - { - if ( ! *g_szLineBuffer[i] ) - break; - } - if ( i == MAX_LINES ) - { - // force scroll buffer up - ScrollTextUp(); - i = MAX_LINES - 1; - } - - g_iNameLengths[i] = 0; - g_pflNameColors[i] = NULL; - - // if it's a say message, search for the players name in the string - if ( *pszBuf == 2 && clientIndex > 0 ) - { - GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); - const char *pName = g_PlayerInfoList[clientIndex].name; - - if ( pName ) - { - const char *nameInString = strstr( pszBuf, pName ); - - if ( nameInString ) - { - g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); - g_pflNameColors[i] = GetClientColor( clientIndex ); - } - } - } - - strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); - - // make sure the text fits in one line - EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); - - // Set scroll time - if ( i == 0 ) - { - flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; - } - - m_iFlags |= HUD_ACTIVE; - PlaySound( "misc/talk.wav", 1 ); - - if ( ScreenHeight >= 480 ) - Y_START = ScreenHeight - 60; - else - Y_START = ScreenHeight - 45; - Y_START -= (line_height * (MAX_LINES+1)); - -} - -void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) -{ - int line_width = 0; - GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); - - if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) - { // string is too long to fit on line - // scan the string until we find what word is too long, and wrap the end of the sentence after the word - int length = LINE_START; - int tmp_len = 0; - char *last_break = NULL; - for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) - { - // check for a color change, if so skip past it - if ( x[0] == '/' && x[1] == '(' ) - { - x += 2; - // skip forward until past mode specifier - while ( *x != 0 && *x != ')' ) - x++; - - if ( *x != 0 ) - x++; - - if ( *x == 0 ) - break; - } - - char buf[2]; - buf[1] = 0; - - if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character - last_break = x; - - buf[0] = *x; // get the length of the current character - GetConsoleStringSize( buf, &tmp_len, &line_height ); - length += tmp_len; - - if ( length > MAX_LINE_WIDTH ) - { // needs to be broken up - if ( !last_break ) - last_break = x-1; - - x = last_break; - - // find an empty string slot - int j; - do - { - for ( j = 0; j < MAX_LINES; j++ ) - { - if ( ! *g_szLineBuffer[j] ) - break; - } - if ( j == MAX_LINES ) - { - // need to make more room to display text, scroll stuff up then fix the pointers - int linesmoved = ScrollTextUp(); - line -= linesmoved; - last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); - } - } - while ( j == MAX_LINES ); - - // copy remaining string into next buffer, making sure it starts with a space character - if ( (char)*last_break == (char)' ' ) - { - int linelen = strlen(g_szLineBuffer[j]); - int remaininglen = strlen(last_break); - - if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) - strcat( g_szLineBuffer[j], last_break ); - } - else - { - if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) - { - strcat( g_szLineBuffer[j], " " ); - strcat( g_szLineBuffer[j], last_break ); - } - } - - *last_break = 0; // cut off the last string - - EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); - break; - } - } - } -} + ConsolePrint( pszBuf ); + + // find an empty string slot + for ( i = 0; i < MAX_LINES; i++ ) + { + if ( ! *g_szLineBuffer[i] ) + break; + } + if ( i == MAX_LINES ) + { + // force scroll buffer up + ScrollTextUp(); + i = MAX_LINES - 1; + } + + g_iNameLengths[i] = 0; + g_pflNameColors[i] = NULL; + + // if it's a say message, search for the players name in the string + if ( *pszBuf == 2 && clientIndex > 0 ) + { + GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); + const char *pName = g_PlayerInfoList[clientIndex].name; + + if ( pName ) + { + const char *nameInString = strstr( pszBuf, pName ); + + if ( nameInString ) + { + g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); + g_pflNameColors[i] = GetClientColor( clientIndex ); + } + } + } + + strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); + + // make sure the text fits in one line + EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); + + // Set scroll time + if ( i == 0 ) + { + flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; + } + + m_iFlags |= HUD_ACTIVE; + PlaySound( "misc/talk.wav", 1 ); + + if ( ScreenHeight >= 480 ) + Y_START = ScreenHeight - 60; + else + Y_START = ScreenHeight - 45; + Y_START -= (line_height * (MAX_LINES+1)); + +} + +void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) +{ + int line_width = 0; + GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); + + if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) + { // string is too long to fit on line + // scan the string until we find what word is too long, and wrap the end of the sentence after the word + int length = LINE_START; + int tmp_len = 0; + char *last_break = NULL; + for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) + { + // check for a color change, if so skip past it + if ( x[0] == '/' && x[1] == '(' ) + { + x += 2; + // skip forward until past mode specifier + while ( *x != 0 && *x != ')' ) + x++; + + if ( *x != 0 ) + x++; + + if ( *x == 0 ) + break; + } + + char buf[2]; + buf[1] = 0; + + if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character + last_break = x; + + buf[0] = *x; // get the length of the current character + GetConsoleStringSize( buf, &tmp_len, &line_height ); + length += tmp_len; + + if ( length > MAX_LINE_WIDTH ) + { // needs to be broken up + if ( !last_break ) + last_break = x-1; + + x = last_break; + + // find an empty string slot + int j; + do + { + for ( j = 0; j < MAX_LINES; j++ ) + { + if ( ! *g_szLineBuffer[j] ) + break; + } + if ( j == MAX_LINES ) + { + // need to make more room to display text, scroll stuff up then fix the pointers + int linesmoved = ScrollTextUp(); + line -= linesmoved; + last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + } + } + while ( j == MAX_LINES ); + + // copy remaining string into next buffer, making sure it starts with a space character + if ( (char)*last_break == (char)' ' ) + { + int linelen = strlen(g_szLineBuffer[j]); + int remaininglen = strlen(last_break); + + if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) + strcat( g_szLineBuffer[j], last_break ); + } + else + { + if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) + { + strcat( g_szLineBuffer[j], " " ); + strcat( g_szLineBuffer[j], last_break ); + } + } + + *last_break = 0; // cut off the last string + + EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); + break; + } + } + } +} diff --git a/cl_dll/soundsystem.cpp b/cl_dll/soundsystem.cpp index a25084c4..d368109b 100644 --- a/cl_dll/soundsystem.cpp +++ b/cl_dll/soundsystem.cpp @@ -1,162 +1,162 @@ -//======== (C) Copyright 1996-2002 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: -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//============================================================================= -#include -#include -#include -#include "r_studioint.h" - -extern engine_studio_api_t IEngineStudio; - -#define RENDERTYPE_UNDEFINED 0 -#define RENDERTYPE_SOFTWARE 1 -#define RENDERTYPE_HARDWARE 2 - -#define ENGINE_LAUNCHER_API_VERSION 1 - -LPDIRECTSOUND lpDS = NULL; -LPDIRECTSOUNDBUFFER lpDSBuf = NULL; -LPHWAVEOUT lpHW = NULL; - -static HMODULE hEngine = 0; - -typedef struct engine_api_s -{ - int version; - int rendertype; - int size; - - // Functions - void ( *unused1 ) ( void ); - void ( *unused2 ) ( void ); - void ( *unused3 ) ( void ); - void ( *unused4 ) ( void ); - void ( *unused5 ) ( void ); - void ( *unused6 ) ( void ); - void ( *unused7 ) ( void ); - void ( *unused8 ) ( void ); - void ( *unused9 ) ( void ); - void ( *unused10 ) ( void ); - void ( *unused11 ) ( void ); - void ( *unused12 ) ( void ); - void ( *unused13 ) ( void ); - void ( *unused14 ) ( void ); - void ( *unused15 ) ( void ); - void ( *unused16 ) ( void ); - void ( *unused17 ) ( void ); - void ( *unused18 ) ( void ); - void ( *unused19 ) ( void ); - void ( *unused20 ) ( void ); - void ( *unused21 ) ( void ); - void ( *unused22 ) ( void ); - void ( *unused23 ) ( void ); - void ( *unused24 ) ( void ); - void ( *unused25 ) ( void ); - void ( *unused26 ) ( void ); - void ( *unused27 ) ( void ); - void ( *unused28 ) ( void ); - void ( *unused29 ) ( void ); - void ( *unused30 ) ( void ); - void ( *unused31 ) ( void ); - void ( *unused32 ) ( void ); - void ( *unused33 ) ( void ); - void ( *unused34 ) ( void ); - - void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); - void *( *S_GetWAVPointer ) ( void ); - - void ( *unused35 ) ( void ); - void ( *unused36 ) ( void ); - void ( *unused37 ) ( void ); - void ( *unused38 ) ( void ); - void ( *unused39 ) ( void ); - void ( *unused40 ) ( void ); - void ( *unused41 ) ( void ); - void ( *unused42 ) ( void ); - void ( *unused43 ) ( void ); - void ( *unused44 ) ( void ); - void ( *unused45 ) ( void ); - void ( *unused46 ) ( void ); - void ( *unused47 ) ( void ); - void ( *unused48 ) ( void ); - void ( *unused49 ) ( void ); - void ( *unused50 ) ( void ); - void ( *unused51 ) ( void ); - void ( *unused52 ) ( void ); - void ( *unused53 ) ( void ); - void ( *unused54 ) ( void ); - void ( *unused55 ) ( void ); -} engine_api_t; - -static engine_api_t engineapi; - -typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); - -//----------------------------------------------------------------------------- -// Purpose: Get launcher/engine interface from engine module -// Input : hMod - -// Output : int -//----------------------------------------------------------------------------- -int Eng_LoadFunctions( HMODULE hMod ) -{ - engine_api_func pfnEngineAPI; - - pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); - if ( !pfnEngineAPI ) - return 0; - - if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) - return 0; - - // All is okay - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) -//----------------------------------------------------------------------------- -void LoadSoundAPIs( void ) -{ - hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); - if ( hEngine ) - { - if ( Eng_LoadFunctions( hEngine ) ) - { - if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) - { - engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); - lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Close engine library, release sound pointers -//----------------------------------------------------------------------------- -void ShutdownSoundAPIs( void ) -{ - if( hEngine ) - { - FreeLibrary( hEngine ); - hEngine = 0; - } - - lpDS = 0; - lpDSBuf = 0; - lpHW = 0; -} +//======== (C) Copyright 1996-2002 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: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include "r_studioint.h" + +extern engine_studio_api_t IEngineStudio; + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +LPDIRECTSOUND lpDS = NULL; +LPDIRECTSOUNDBUFFER lpDSBuf = NULL; +LPHWAVEOUT lpHW = NULL; + +static HMODULE hEngine = 0; + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + void ( *unused1 ) ( void ); + void ( *unused2 ) ( void ); + void ( *unused3 ) ( void ); + void ( *unused4 ) ( void ); + void ( *unused5 ) ( void ); + void ( *unused6 ) ( void ); + void ( *unused7 ) ( void ); + void ( *unused8 ) ( void ); + void ( *unused9 ) ( void ); + void ( *unused10 ) ( void ); + void ( *unused11 ) ( void ); + void ( *unused12 ) ( void ); + void ( *unused13 ) ( void ); + void ( *unused14 ) ( void ); + void ( *unused15 ) ( void ); + void ( *unused16 ) ( void ); + void ( *unused17 ) ( void ); + void ( *unused18 ) ( void ); + void ( *unused19 ) ( void ); + void ( *unused20 ) ( void ); + void ( *unused21 ) ( void ); + void ( *unused22 ) ( void ); + void ( *unused23 ) ( void ); + void ( *unused24 ) ( void ); + void ( *unused25 ) ( void ); + void ( *unused26 ) ( void ); + void ( *unused27 ) ( void ); + void ( *unused28 ) ( void ); + void ( *unused29 ) ( void ); + void ( *unused30 ) ( void ); + void ( *unused31 ) ( void ); + void ( *unused32 ) ( void ); + void ( *unused33 ) ( void ); + void ( *unused34 ) ( void ); + + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + + void ( *unused35 ) ( void ); + void ( *unused36 ) ( void ); + void ( *unused37 ) ( void ); + void ( *unused38 ) ( void ); + void ( *unused39 ) ( void ); + void ( *unused40 ) ( void ); + void ( *unused41 ) ( void ); + void ( *unused42 ) ( void ); + void ( *unused43 ) ( void ); + void ( *unused44 ) ( void ); + void ( *unused45 ) ( void ); + void ( *unused46 ) ( void ); + void ( *unused47 ) ( void ); + void ( *unused48 ) ( void ); + void ( *unused49 ) ( void ); + void ( *unused50 ) ( void ); + void ( *unused51 ) ( void ); + void ( *unused52 ) ( void ); + void ( *unused53 ) ( void ); + void ( *unused54 ) ( void ); + void ( *unused55 ) ( void ); +} engine_api_t; + +static engine_api_t engineapi; + +typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); + +//----------------------------------------------------------------------------- +// Purpose: Get launcher/engine interface from engine module +// Input : hMod - +// Output : int +//----------------------------------------------------------------------------- +int Eng_LoadFunctions( HMODULE hMod ) +{ + engine_api_func pfnEngineAPI; + + pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); + if ( !pfnEngineAPI ) + return 0; + + if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + return 0; + + // All is okay + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) +//----------------------------------------------------------------------------- +void LoadSoundAPIs( void ) +{ + hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); + if ( hEngine ) + { + if ( Eng_LoadFunctions( hEngine ) ) + { + if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) + { + engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); + lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Close engine library, release sound pointers +//----------------------------------------------------------------------------- +void ShutdownSoundAPIs( void ) +{ + if( hEngine ) + { + FreeLibrary( hEngine ); + hEngine = 0; + } + + lpDS = 0; + lpDSBuf = 0; + lpHW = 0; +} diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index 10ca630a..53a3e743 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -1,164 +1,164 @@ -/*** -* -* 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. -* -****/ -// -// status_icons.cpp -// -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" -#include -#include -#include "parsemsg.h" -#include "event_api.h" - -DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); - -int CHudStatusIcons::Init( void ) -{ - HOOK_MESSAGE( StatusIcon ); - - gHUD.AddHudElem( this ); - - Reset(); - - return 1; -} - -int CHudStatusIcons::VidInit( void ) -{ - - return 1; -} - -void CHudStatusIcons::Reset( void ) -{ - memset( m_IconList, 0, sizeof m_IconList ); - m_iFlags &= ~HUD_ACTIVE; -} - -// Draw status icons along the left-hand side of the screen -int CHudStatusIcons::Draw( float flTime ) -{ - if (gEngfuncs.IsSpectateOnly()) - return 1; - // find starting position to draw from, along right-hand side of screen - int x = 5; - int y = ScreenHeight / 2; - - // loop through icon list, and draw any valid icons drawing up from the middle of screen - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( m_IconList[i].spr ) - { - y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; - - SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); - SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); - } - } - - return 1; -} - -// Message handler for StatusIcon message -// accepts five values: -// byte : TRUE = ENABLE icon, FALSE = DISABLE icon -// string : the sprite name to display -// byte : red -// byte : green -// byte : blue -int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int ShouldEnable = READ_BYTE(); - char *pszIconName = READ_STRING(); - if ( ShouldEnable ) - { - int r = READ_BYTE(); - int g = READ_BYTE(); - int b = READ_BYTE(); - EnableIcon( pszIconName, r, g, b ); - m_iFlags |= HUD_ACTIVE; - } - else - { - DisableIcon( pszIconName ); - } - - return 1; -} - -// add the icon to the icon list, and set it's drawing color -void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) -{ +/*** +* +* 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. +* +****/ +// +// status_icons.cpp +// +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include +#include +#include "parsemsg.h" +#include "event_api.h" + +DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); + +int CHudStatusIcons::Init( void ) +{ + HOOK_MESSAGE( StatusIcon ); + + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +} + +int CHudStatusIcons::VidInit( void ) +{ + + return 1; +} + +void CHudStatusIcons::Reset( void ) +{ + memset( m_IconList, 0, sizeof m_IconList ); + m_iFlags &= ~HUD_ACTIVE; +} + +// Draw status icons along the left-hand side of the screen +int CHudStatusIcons::Draw( float flTime ) +{ + if (gEngfuncs.IsSpectateOnly()) + return 1; + // find starting position to draw from, along right-hand side of screen + int x = 5; + int y = ScreenHeight / 2; + + // loop through icon list, and draw any valid icons drawing up from the middle of screen + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( m_IconList[i].spr ) + { + y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; + + SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); + SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); + } + } + + return 1; +} + +// Message handler for StatusIcon message +// accepts five values: +// byte : TRUE = ENABLE icon, FALSE = DISABLE icon +// string : the sprite name to display +// byte : red +// byte : green +// byte : blue +int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int ShouldEnable = READ_BYTE(); + char *pszIconName = READ_STRING(); + if ( ShouldEnable ) + { + int r = READ_BYTE(); + int g = READ_BYTE(); + int b = READ_BYTE(); + EnableIcon( pszIconName, r, g, b ); + m_iFlags |= HUD_ACTIVE; + } + else + { + DisableIcon( pszIconName ); + } + + return 1; +} + +// add the icon to the icon list, and set it's drawing color +void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) +{ int i; - // check to see if the sprite is in the current list - for ( i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) - break; - } - - if ( i == MAX_ICONSPRITES ) - { - // icon not in list, so find an empty slot to add to - for ( i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !m_IconList[i].spr ) - break; - } - } - - // if we've run out of space in the list, overwrite the first icon - if ( i == MAX_ICONSPRITES ) - { - i = 0; - } - - // Load the sprite and add it to the list - // the sprite must be listed in hud.txt - int spr_index = gHUD.GetSpriteIndex( pszIconName ); - m_IconList[i].spr = gHUD.GetSprite( spr_index ); - m_IconList[i].rc = gHUD.GetSpriteRect( spr_index ); - m_IconList[i].r = red; - m_IconList[i].g = green; - m_IconList[i].b = blue; - strcpy( m_IconList[i].szSpriteName, pszIconName ); - - // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) - if ( strstr(m_IconList[i].szSpriteName, "grenade") ) - { - cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); - gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - } -} - -void CHudStatusIcons::DisableIcon( char *pszIconName ) -{ - // find the sprite is in the current list - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) - { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) - { - // clear the item from the list - memset( &m_IconList[i], 0, sizeof( icon_sprite_t ) ); - return; - } - } -} + // check to see if the sprite is in the current list + for ( i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + break; + } + + if ( i == MAX_ICONSPRITES ) + { + // icon not in list, so find an empty slot to add to + for ( i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !m_IconList[i].spr ) + break; + } + } + + // if we've run out of space in the list, overwrite the first icon + if ( i == MAX_ICONSPRITES ) + { + i = 0; + } + + // Load the sprite and add it to the list + // the sprite must be listed in hud.txt + int spr_index = gHUD.GetSpriteIndex( pszIconName ); + m_IconList[i].spr = gHUD.GetSprite( spr_index ); + m_IconList[i].rc = gHUD.GetSpriteRect( spr_index ); + m_IconList[i].r = red; + m_IconList[i].g = green; + m_IconList[i].b = blue; + strcpy( m_IconList[i].szSpriteName, pszIconName ); + + // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) + if ( strstr(m_IconList[i].szSpriteName, "grenade") ) + { + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + } +} + +void CHudStatusIcons::DisableIcon( char *pszIconName ) +{ + // find the sprite is in the current list + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + { + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + { + // clear the item from the list + memset( &m_IconList[i], 0, sizeof( icon_sprite_t ) ); + return; + } + } +} diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index e940187f..81566d1a 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -1,265 +1,265 @@ -/*** -* -* 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. -* -****/ -// -// statusbar.cpp -// -// generic text status bar, set by game dll -// runs across bottom of screen -// - -#include "hud.h" -#include "cl_util.h" -#include "parsemsg.h" - -#include -#include - -DECLARE_MESSAGE( m_StatusBar, StatusText ); -DECLARE_MESSAGE( m_StatusBar, StatusValue ); - -#define STATUSBAR_ID_LINE 1 - -float *GetClientColor( int clientIndex ); -extern float g_ColorYellow[3]; - -int CHudStatusBar :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( StatusText ); - HOOK_MESSAGE( StatusValue ); - - Reset(); - - CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); - - return 1; -} - -int CHudStatusBar :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudStatusBar :: Reset( void ) -{ - int i = 0; - - m_iFlags &= ~HUD_ACTIVE; // start out inactive - for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) - m_szStatusText[i][0] = 0; - memset( m_iStatusValues, 0, sizeof m_iStatusValues ); - - m_iStatusValues[0] = 1; // 0 is the special index, which always returns true - - // reset our colors for the status bar lines (yellow is default) - for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) - m_pflNameColors[i] = g_ColorYellow; -} - -void CHudStatusBar :: ParseStatusString( int line_num ) -{ - // localise string first - char szBuffer[MAX_STATUSTEXT_LENGTH]; - memset( szBuffer, 0, sizeof szBuffer ); - gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); - - // parse m_szStatusText & m_iStatusValues into m_szStatusBar - memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH ); - char *src = szBuffer; - char *dst = m_szStatusBar[line_num]; - - char *src_start = src, *dst_start = dst; - - while ( *src != 0 ) - { - while ( *src == '\n' ) - src++; // skip over any newlines - - if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) - break; - - int index = atoi( src ); - // should we draw this line? - if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) ) - { // parse this line and append result to the status bar - while ( *src >= '0' && *src <= '9' ) - src++; - - if ( *src == '\n' || *src == 0 ) - continue; // no more left in this text line - - // copy the text, char by char, until we hit a % or a \n - while ( *src != '\n' && *src != 0 ) - { - if ( *src != '%' ) - { // just copy the character - *dst = *src; - dst++, src++; - } - else - { - // get the descriptor - char valtype = *(++src); // move over % - - // if it's a %, draw a % sign - if ( valtype == '%' ) - { - *dst = valtype; - dst++, src++; - continue; - } - - // move over descriptor, then get and move over the index - index = atoi( ++src ); - while ( *src >= '0' && *src <= '9' ) - src++; - - if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) - { - int indexval = m_iStatusValues[index]; - - // get the string to substitute in place of the %XX - char szRepString[MAX_PLAYER_NAME_LENGTH]; - switch ( valtype ) - { - case 'p': // player name - GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); - if ( g_PlayerInfoList[indexval].name != NULL ) - { - strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); - m_pflNameColors[line_num] = GetClientColor( indexval ); - } - else - { - strcpy( szRepString, "******" ); - } - - break; - case 'i': // number - sprintf( szRepString, "%d", indexval ); - break; - default: - szRepString[0] = 0; - } - - for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) - *dst = *cp; - } - } - } - } - else - { - // skip to next line of text - while ( *src != 0 && *src != '\n' ) - src++; - } - } -} - -int CHudStatusBar :: Draw( float fTime ) -{ - if ( m_bReparseString ) - { - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) - { - m_pflNameColors[i] = g_ColorYellow; - ParseStatusString( i ); - } - m_bReparseString = FALSE; - } - - int Y_START = ScreenHeight - YRES(32 + 4); - - // Draw the status bar lines - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) - { - int TextHeight, TextWidth; - GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); - - int x = 4; - int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen - - // let user set status ID bar centering - if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) - { - x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 ); - y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); - } - - if ( m_pflNameColors[i] ) - DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); - - DrawConsoleString( x, y, m_szStatusBar[i] ); - } - - return 1; -} - -// Message handler for StatusText message -// accepts two values: -// byte: line number of status bar text -// string: status bar text -// this string describes how the status bar should be drawn -// a semi-regular expression: -// ( slotnum ([a..z] [%pX] [%iX])*)* -// where slotnum is an index into the Value table (see below) -// if slotnum is 0, the string is always drawn -// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline -// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] -// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] -int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int line = READ_BYTE(); - - if ( line < 0 || line >= MAX_STATUSBAR_LINES ) - return 1; - - strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH ); - m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) - - if ( m_szStatusText[0] == 0 ) - m_iFlags &= ~HUD_ACTIVE; - else - m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar - - m_bReparseString = TRUE; - - return 1; -} - -// Message handler for StatusText message -// accepts two values: -// byte: index into the status value array -// short: value to store -int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int index = READ_BYTE(); - if ( index < 1 || index >= MAX_STATUSBAR_VALUES ) - return 1; // index out of range - - m_iStatusValues[index] = READ_SHORT(); - - m_bReparseString = TRUE; - - return 1; -} +/*** +* +* 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. +* +****/ +// +// statusbar.cpp +// +// generic text status bar, set by game dll +// runs across bottom of screen +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +DECLARE_MESSAGE( m_StatusBar, StatusText ); +DECLARE_MESSAGE( m_StatusBar, StatusValue ); + +#define STATUSBAR_ID_LINE 1 + +float *GetClientColor( int clientIndex ); +extern float g_ColorYellow[3]; + +int CHudStatusBar :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( StatusText ); + HOOK_MESSAGE( StatusValue ); + + Reset(); + + CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); + + return 1; +} + +int CHudStatusBar :: VidInit( void ) +{ + // Load sprites here + + return 1; +} + +void CHudStatusBar :: Reset( void ) +{ + int i = 0; + + m_iFlags &= ~HUD_ACTIVE; // start out inactive + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_szStatusText[i][0] = 0; + memset( m_iStatusValues, 0, sizeof m_iStatusValues ); + + m_iStatusValues[0] = 1; // 0 is the special index, which always returns true + + // reset our colors for the status bar lines (yellow is default) + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_pflNameColors[i] = g_ColorYellow; +} + +void CHudStatusBar :: ParseStatusString( int line_num ) +{ + // localise string first + char szBuffer[MAX_STATUSTEXT_LENGTH]; + memset( szBuffer, 0, sizeof szBuffer ); + gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); + + // parse m_szStatusText & m_iStatusValues into m_szStatusBar + memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH ); + char *src = szBuffer; + char *dst = m_szStatusBar[line_num]; + + char *src_start = src, *dst_start = dst; + + while ( *src != 0 ) + { + while ( *src == '\n' ) + src++; // skip over any newlines + + if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) + break; + + int index = atoi( src ); + // should we draw this line? + if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) ) + { // parse this line and append result to the status bar + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( *src == '\n' || *src == 0 ) + continue; // no more left in this text line + + // copy the text, char by char, until we hit a % or a \n + while ( *src != '\n' && *src != 0 ) + { + if ( *src != '%' ) + { // just copy the character + *dst = *src; + dst++, src++; + } + else + { + // get the descriptor + char valtype = *(++src); // move over % + + // if it's a %, draw a % sign + if ( valtype == '%' ) + { + *dst = valtype; + dst++, src++; + continue; + } + + // move over descriptor, then get and move over the index + index = atoi( ++src ); + while ( *src >= '0' && *src <= '9' ) + src++; + + if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) + { + int indexval = m_iStatusValues[index]; + + // get the string to substitute in place of the %XX + char szRepString[MAX_PLAYER_NAME_LENGTH]; + switch ( valtype ) + { + case 'p': // player name + GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); + if ( g_PlayerInfoList[indexval].name != NULL ) + { + strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + m_pflNameColors[line_num] = GetClientColor( indexval ); + } + else + { + strcpy( szRepString, "******" ); + } + + break; + case 'i': // number + sprintf( szRepString, "%d", indexval ); + break; + default: + szRepString[0] = 0; + } + + for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) + *dst = *cp; + } + } + } + } + else + { + // skip to next line of text + while ( *src != 0 && *src != '\n' ) + src++; + } + } +} + +int CHudStatusBar :: Draw( float fTime ) +{ + if ( m_bReparseString ) + { + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + m_pflNameColors[i] = g_ColorYellow; + ParseStatusString( i ); + } + m_bReparseString = FALSE; + } + + int Y_START = ScreenHeight - YRES(32 + 4); + + // Draw the status bar lines + for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + int TextHeight, TextWidth; + GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); + + int x = 4; + int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen + + // let user set status ID bar centering + if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) + { + x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 ); + y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); + } + + if ( m_pflNameColors[i] ) + DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + + DrawConsoleString( x, y, m_szStatusBar[i] ); + } + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: line number of status bar text +// string: status bar text +// this string describes how the status bar should be drawn +// a semi-regular expression: +// ( slotnum ([a..z] [%pX] [%iX])*)* +// where slotnum is an index into the Value table (see below) +// if slotnum is 0, the string is always drawn +// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline +// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] +// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] +int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int line = READ_BYTE(); + + if ( line < 0 || line >= MAX_STATUSBAR_LINES ) + return 1; + + strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH ); + m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) + + if ( m_szStatusText[0] == 0 ) + m_iFlags &= ~HUD_ACTIVE; + else + m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar + + m_bReparseString = TRUE; + + return 1; +} + +// Message handler for StatusText message +// accepts two values: +// byte: index into the status value array +// short: value to store +int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + if ( index < 1 || index >= MAX_STATUSBAR_VALUES ) + return 1; // index out of range + + m_iStatusValues[index] = READ_SHORT(); + + m_bReparseString = TRUE; + + return 1; +} diff --git a/cl_dll/studio_util.cpp b/cl_dll/studio_util.cpp index ab14d96e..df5fc4bf 100644 --- a/cl_dll/studio_util.cpp +++ b/cl_dll/studio_util.cpp @@ -1,251 +1,251 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include "hud.h" -#include "cl_util.h" -#include "const.h" -#include "com_model.h" -#include "studio_util.h" - -/* -==================== -AngleMatrix - -==================== -*/ -void AngleMatrix (const float *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; -} - -/* -==================== -VectorCompare - -==================== -*/ -int VectorCompare (const float *v1, const float *v2) -{ - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) - return 0; - - return 1; -} - -/* -==================== -CrossProduct - -==================== -*/ -void CrossProduct (const float *v1, const float *v2, float *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]; -} - -/* -==================== -VectorTransform - -==================== -*/ -void VectorTransform (const float *in1, float in2[3][4], float *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]; -} - -/* -================ -ConcatTransforms - -================ -*/ -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) -{ - out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + - in1[0][2] * in2[2][0]; - out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + - in1[0][2] * in2[2][1]; - out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + - in1[0][2] * in2[2][2]; - out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + - in1[0][2] * in2[2][3] + in1[0][3]; - out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + - in1[1][2] * in2[2][0]; - out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + - in1[1][2] * in2[2][1]; - out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + - in1[1][2] * in2[2][2]; - out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + - in1[1][2] * in2[2][3] + in1[1][3]; - out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + - in1[2][2] * in2[2][0]; - out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + - in1[2][2] * in2[2][1]; - out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + - in1[2][2] * in2[2][2]; - out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + - in1[2][2] * in2[2][3] + in1[2][3]; -} - -// angles index are not the same as ROLL, PITCH, YAW - -/* -==================== -AngleQuaternion - -==================== -*/ -void AngleQuaternion( float *angles, vec4_t quaternion ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - // FIXME: rescale the inputs to 1/2 angle - angle = angles[2] * 0.5; - sy = sin(angle); - cy = cos(angle); - angle = angles[1] * 0.5; - sp = sin(angle); - cp = cos(angle); - angle = angles[0] * 0.5; - sr = sin(angle); - cr = cos(angle); - - quaternion[0] = sr*cp*cy-cr*sp*sy; // X - quaternion[1] = cr*sp*cy+sr*cp*sy; // Y - quaternion[2] = cr*cp*sy-sr*sp*cy; // Z - quaternion[3] = cr*cp*cy+sr*sp*sy; // W -} - -/* -==================== -QuaternionSlerp - -==================== -*/ -void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) -{ - int i; - float omega, cosom, sinom, sclp, sclq; - - // decide if one of the quaternions is backwards - float a = 0; - float b = 0; - - for (i = 0; i < 4; i++) - { - a += (p[i]-q[i])*(p[i]-q[i]); - b += (p[i]+q[i])*(p[i]+q[i]); - } - if (a > b) - { - for (i = 0; i < 4; i++) - { - q[i] = -q[i]; - } - } - - cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; - - if ((1.0 + cosom) > 0.000001) - { - if ((1.0 - cosom) > 0.000001) - { - omega = acos( cosom ); - sinom = sin( omega ); - sclp = sin( (1.0 - t)*omega) / sinom; - sclq = sin( t*omega ) / sinom; - } - else - { - sclp = 1.0 - t; - sclq = t; - } - for (i = 0; i < 4; i++) { - qt[i] = sclp * p[i] + sclq * q[i]; - } - } - else - { - qt[0] = -q[1]; - qt[1] = q[0]; - qt[2] = -q[3]; - qt[3] = q[2]; - sclp = sin( (1.0 - t) * (0.5 * M_PI)); - sclq = sin( t * (0.5 * M_PI)); - for (i = 0; i < 3; i++) - { - qt[i] = sclp * p[i] + sclq * qt[i]; - } - } -} - -/* -==================== -QuaternionMatrix - -==================== -*/ -void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) -{ - matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; - matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; - matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; - - matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; - matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; - matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; - - matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; - matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; - matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; -} - -/* -==================== -MatrixCopy - -==================== -*/ -void MatrixCopy( float in[3][4], float out[3][4] ) -{ - memcpy( out, in, sizeof( float ) * 3 * 4 ); +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio_util.h" + +/* +==================== +AngleMatrix + +==================== +*/ +void AngleMatrix (const float *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; +} + +/* +==================== +VectorCompare + +==================== +*/ +int VectorCompare (const float *v1, const float *v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +/* +==================== +CrossProduct + +==================== +*/ +void CrossProduct (const float *v1, const float *v2, float *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]; +} + +/* +==================== +VectorTransform + +==================== +*/ +void VectorTransform (const float *in1, float in2[3][4], float *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]; +} + +/* +================ +ConcatTransforms + +================ +*/ +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +// angles index are not the same as ROLL, PITCH, YAW + +/* +==================== +AngleQuaternion + +==================== +*/ +void AngleQuaternion( float *angles, vec4_t quaternion ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + // FIXME: rescale the inputs to 1/2 angle + angle = angles[2] * 0.5; + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * 0.5; + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * 0.5; + sr = sin(angle); + cr = cos(angle); + + quaternion[0] = sr*cp*cy-cr*sp*sy; // X + quaternion[1] = cr*sp*cy+sr*cp*sy; // Y + quaternion[2] = cr*cp*sy-sr*sp*cy; // Z + quaternion[3] = cr*cp*cy+sr*sp*sy; // W +} + +/* +==================== +QuaternionSlerp + +==================== +*/ +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) +{ + int i; + float omega, cosom, sinom, sclp, sclq; + + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + + for (i = 0; i < 4; i++) + { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + q[i] = -q[i]; + } + } + + cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.0 + cosom) > 0.000001) + { + if ((1.0 - cosom) > 0.000001) + { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0 - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else + { + sclp = 1.0 - t; + sclq = t; + } + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else + { + qt[0] = -q[1]; + qt[1] = q[0]; + qt[2] = -q[3]; + qt[3] = q[2]; + sclp = sin( (1.0 - t) * (0.5 * M_PI)); + sclq = sin( t * (0.5 * M_PI)); + for (i = 0; i < 3; i++) + { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } +} + +/* +==================== +QuaternionMatrix + +==================== +*/ +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) +{ + matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; +} + +/* +==================== +MatrixCopy + +==================== +*/ +void MatrixCopy( float in[3][4], float out[3][4] ) +{ + memcpy( out, in, sizeof( float ) * 3 * 4 ); } \ No newline at end of file diff --git a/cl_dll/studio_util.h b/cl_dll/studio_util.h index e1cb980e..aa8dcf6b 100644 --- a/cl_dll/studio_util.h +++ b/cl_dll/studio_util.h @@ -1,40 +1,40 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined( STUDIO_UTIL_H ) -#define STUDIO_UTIL_H -#if defined( WIN32 ) -#pragma once -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -#ifndef PITCH -// MOVEMENT INFO -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 -#endif - -#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) - -void AngleMatrix (const float *angles, float (*matrix)[4] ); -int VectorCompare (const float *v1, const float *v2); -void CrossProduct (const float *v1, const float *v2, float *cross); -void VectorTransform (const float *in1, float in2[3][4], float *out); -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); -void MatrixCopy( float in[3][4], float out[3][4] ); -void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); -void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); -void AngleQuaternion( float *angles, vec4_t quaternion ); - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( STUDIO_UTIL_H ) +#define STUDIO_UTIL_H +#if defined( WIN32 ) +#pragma once +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#ifndef PITCH +// MOVEMENT INFO +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 +#endif + +#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) + +void AngleMatrix (const float *angles, float (*matrix)[4] ); +int VectorCompare (const float *v1, const float *v2); +void CrossProduct (const float *v1, const float *v2, float *cross); +void VectorTransform (const float *in1, float in2[3][4], float *out); +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void MatrixCopy( float in[3][4], float out[3][4] ); +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); +void AngleQuaternion( float *angles, vec4_t quaternion ); + #endif // STUDIO_UTIL_H \ No newline at end of file diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index f40cd5e7..1228a07d 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -1,209 +1,209 @@ -/*** -* -* 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. -* -****/ -// -// text_message.cpp -// -// implementation of CHudTextMessage class -// -// this class routes messages through titles.txt for localisation -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "parsemsg.h" - - -DECLARE_MESSAGE( m_TextMessage, TextMsg ); - -int CHudTextMessage::Init(void) -{ - HOOK_MESSAGE( TextMsg ); - - gHUD.AddHudElem( this ); - - Reset(); - - return 1; -}; - -// Searches through the string for any msg names (indicated by a '#') -// any found are looked up in titles.txt and the new message substituted -// the new value is pushed into dst_buffer -char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) -{ - char *dst = dst_buffer; - for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) - { - if ( *src == '#' ) - { - // cut msg name out of string - static char word_buf[255]; - char *wdst = word_buf, *word_start = src; - for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) - { - *wdst = *src; - } - *wdst = 0; - - // lookup msg name in titles.txt - client_textmessage_t *clmsg = TextMessageGet( word_buf ); - if ( !clmsg || !(clmsg->pMessage) ) - { - src = word_start; - *dst = *src; - dst++, src++; - continue; - } - - // copy string into message over the msg name - for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) - { - *dst = *wsrc; - } - *dst = 0; - } - else - { - *dst = *src; - dst++, src++; - *dst = 0; - } - } - - dst_buffer[buffer_size-1] = 0; // ensure null termination - return dst_buffer; -} - -// As above, but with a local static buffer -char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) -{ - static char dst_buffer[1024]; - LocaliseTextString( msg, dst_buffer, 1024 ); - return dst_buffer; -} - -// Simplified version of LocaliseTextString; assumes string is only one word -char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) -{ - if ( !msg ) - return ""; - - // '#' character indicates this is a reference to a string in titles.txt, and not the string itself - if ( msg[0] == '#' ) - { - // this is a message name, so look up the real message - client_textmessage_t *clmsg = TextMessageGet( msg+1 ); - - if ( !clmsg || !(clmsg->pMessage) ) - return (char*)msg; // lookup failed, so return the original string - - if ( msg_dest ) - { - // check to see if titles.txt info overrides msg destination - // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination - if ( clmsg->effect < 0 ) // - *msg_dest = -clmsg->effect; - } - - return (char*)clmsg->pMessage; - } - else - { // nothing special about this message, so just return the same string - return (char*)msg; - } -} - -void StripEndNewlineFromString( char *str ) -{ - int s = strlen( str ) - 1; - if ( str[s] == '\n' || str[s] == '\r' ) - str[s] = 0; -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -char* ConvertCRtoNL( char *str ) -{ - for ( char *ch = str; *ch != 0; ch++ ) - if ( *ch == '\r' ) - *ch = '\n'; - return str; -} - -// Message handler for text messages -// displays a string, looking them up from the titles.txt file, which can be localised -// parameters: -// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) -// string: message -// optional parameters: -// string: message parameter 1 -// string: message parameter 2 -// string: message parameter 3 -// string: message parameter 4 -// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt -// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') -int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - - int msg_dest = READ_BYTE(); - - static char szBuf[6][128]; - char *msg_text = LookupString( READ_STRING(), &msg_dest ); - msg_text = strcpy( szBuf[0], msg_text ); - - // keep reading strings and using C format strings for subsituting the strings into the localised text string - char *sstr1 = LookupString( READ_STRING() ); - sstr1 = strcpy( szBuf[1], sstr1 ); - StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines - char *sstr2 = LookupString( READ_STRING() ); - sstr2 = strcpy( szBuf[2], sstr2 ); - StripEndNewlineFromString( sstr2 ); - char *sstr3 = LookupString( READ_STRING() ); - sstr3 = strcpy( szBuf[3], sstr3 ); - StripEndNewlineFromString( sstr3 ); - char *sstr4 = LookupString( READ_STRING() ); - sstr4 = strcpy( szBuf[4], sstr4 ); - StripEndNewlineFromString( sstr4 ); - char *psz = szBuf[5]; - - switch ( msg_dest ) - { - case HUD_PRINTCENTER: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); - CenterPrint( ConvertCRtoNL( psz ) ); - break; - - case HUD_PRINTNOTIFY: - psz[0] = 1; // mark this message to go into the notify buffer - sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 ); - ConsolePrint( ConvertCRtoNL( psz ) ); - break; - - case HUD_PRINTTALK: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); - gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); - break; - - case HUD_PRINTCONSOLE: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); - ConsolePrint( ConvertCRtoNL( psz ) ); - break; - } - - return 1; -} +/*** +* +* 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. +* +****/ +// +// text_message.cpp +// +// implementation of CHudTextMessage class +// +// this class routes messages through titles.txt for localisation +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + + +DECLARE_MESSAGE( m_TextMessage, TextMsg ); + +int CHudTextMessage::Init(void) +{ + HOOK_MESSAGE( TextMsg ); + + gHUD.AddHudElem( this ); + + Reset(); + + return 1; +}; + +// Searches through the string for any msg names (indicated by a '#') +// any found are looked up in titles.txt and the new message substituted +// the new value is pushed into dst_buffer +char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) +{ + char *dst = dst_buffer; + for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + { + if ( *src == '#' ) + { + // cut msg name out of string + static char word_buf[255]; + char *wdst = word_buf, *word_start = src; + for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) + { + *wdst = *src; + } + *wdst = 0; + + // lookup msg name in titles.txt + client_textmessage_t *clmsg = TextMessageGet( word_buf ); + if ( !clmsg || !(clmsg->pMessage) ) + { + src = word_start; + *dst = *src; + dst++, src++; + continue; + } + + // copy string into message over the msg name + for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) + { + *dst = *wsrc; + } + *dst = 0; + } + else + { + *dst = *src; + dst++, src++; + *dst = 0; + } + } + + dst_buffer[buffer_size-1] = 0; // ensure null termination + return dst_buffer; +} + +// As above, but with a local static buffer +char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) +{ + static char dst_buffer[1024]; + LocaliseTextString( msg, dst_buffer, 1024 ); + return dst_buffer; +} + +// Simplified version of LocaliseTextString; assumes string is only one word +char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) +{ + if ( !msg ) + return ""; + + // '#' character indicates this is a reference to a string in titles.txt, and not the string itself + if ( msg[0] == '#' ) + { + // this is a message name, so look up the real message + client_textmessage_t *clmsg = TextMessageGet( msg+1 ); + + if ( !clmsg || !(clmsg->pMessage) ) + return (char*)msg; // lookup failed, so return the original string + + if ( msg_dest ) + { + // check to see if titles.txt info overrides msg destination + // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination + if ( clmsg->effect < 0 ) // + *msg_dest = -clmsg->effect; + } + + return (char*)clmsg->pMessage; + } + else + { // nothing special about this message, so just return the same string + return (char*)msg; + } +} + +void StripEndNewlineFromString( char *str ) +{ + int s = strlen( str ) - 1; + if ( str[s] == '\n' || str[s] == '\r' ) + str[s] = 0; +} + +// converts all '\r' characters to '\n', so that the engine can deal with the properly +// returns a pointer to str +char* ConvertCRtoNL( char *str ) +{ + for ( char *ch = str; *ch != 0; ch++ ) + if ( *ch == '\r' ) + *ch = '\n'; + return str; +} + +// Message handler for text messages +// displays a string, looking them up from the titles.txt file, which can be localised +// parameters: +// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) +// string: message +// optional parameters: +// string: message parameter 1 +// string: message parameter 2 +// string: message parameter 3 +// string: message parameter 4 +// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt +// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') +int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int msg_dest = READ_BYTE(); + + static char szBuf[6][128]; + char *msg_text = LookupString( READ_STRING(), &msg_dest ); + msg_text = strcpy( szBuf[0], msg_text ); + + // keep reading strings and using C format strings for subsituting the strings into the localised text string + char *sstr1 = LookupString( READ_STRING() ); + sstr1 = strcpy( szBuf[1], sstr1 ); + StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines + char *sstr2 = LookupString( READ_STRING() ); + sstr2 = strcpy( szBuf[2], sstr2 ); + StripEndNewlineFromString( sstr2 ); + char *sstr3 = LookupString( READ_STRING() ); + sstr3 = strcpy( szBuf[3], sstr3 ); + StripEndNewlineFromString( sstr3 ); + char *sstr4 = LookupString( READ_STRING() ); + sstr4 = strcpy( szBuf[4], sstr4 ); + StripEndNewlineFromString( sstr4 ); + char *psz = szBuf[5]; + + switch ( msg_dest ) + { + case HUD_PRINTCENTER: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + CenterPrint( ConvertCRtoNL( psz ) ); + break; + + case HUD_PRINTNOTIFY: + psz[0] = 1; // mark this message to go into the notify buffer + sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 ); + ConsolePrint( ConvertCRtoNL( psz ) ); + break; + + case HUD_PRINTTALK: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); + break; + + case HUD_PRINTCONSOLE: + sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + ConsolePrint( ConvertCRtoNL( psz ) ); + break; + } + + return 1; +} diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h index f178c55b..06d9af09 100644 --- a/cl_dll/tf_defs.h +++ b/cl_dll/tf_defs.h @@ -1,1389 +1,1389 @@ -/*** -* -* 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. -* -****/ - -#ifndef __TF_DEFS_H -#define __TF_DEFS_H - -//=========================================================================== -// OLD OPTIONS.QC -//=========================================================================== -#define DEFAULT_AUTOZOOM FALSE -#define WEINER_SNIPER // autoaiming for sniper rifle -#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. - -//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server -#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active -#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active - -//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time -//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server -#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into -#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) -#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies - -#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. - // 60 is a mild setting, and won't make too much difference - // increasing it _decreases_ the amount of help the losing team gets - // Minimum setting is 1, which would really help the losing team - -#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to - // appear whenever a player connects -#define NEVER_TEAMFRAGS FALSE // teamfrags options always off -#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on -#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast -#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds - -#define MAPBRIEFING_MAXTEXTLENGTH 512 -#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed - -// Debug Options -//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res - // mode and/or piping the output from the server to a file. -#ifdef MAP_DEBUG - #define MDEBUG(x) x -#else - #define MDEBUG(x) -#endif -//#define VERBOSE // Verbose Debugging on/off - -//=========================================================================== -// OLD QUAKE Defs -//=========================================================================== -// items -#define IT_AXE 4096 -#define IT_SHOTGUN 1 -#define IT_SUPER_SHOTGUN 2 -#define IT_NAILGUN 4 -#define IT_SUPER_NAILGUN 8 -#define IT_GRENADE_LAUNCHER 16 -#define IT_ROCKET_LAUNCHER 32 -#define IT_LIGHTNING 64 -#define IT_EXTRA_WEAPON 128 - -#define IT_SHELLS 256 -#define IT_NAILS 512 -#define IT_ROCKETS 1024 -#define IT_CELLS 2048 - -#define IT_ARMOR1 8192 -#define IT_ARMOR2 16384 -#define IT_ARMOR3 32768 -#define IT_SUPERHEALTH 65536 - -#define IT_KEY1 131072 -#define IT_KEY2 262144 - -#define IT_INVISIBILITY 524288 -#define IT_INVULNERABILITY 1048576 -#define IT_SUIT 2097152 -#define IT_QUAD 4194304 -#define IT_HOOK 8388608 - -#define IT_KEY3 16777216 // Stomp invisibility -#define IT_KEY4 33554432 // Stomp invulnerability - -//=========================================================================== -// TEAMFORTRESS Defs -//=========================================================================== -// TeamFortress State Flags -#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade -#define TFSTATE_RELOADING 2 // Whether the player is reloading -#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE -#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn -#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon -#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) -#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) -#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) -#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) -#define TFSTATE_BURNING 512 // Is on fire -#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade -#define TFSTATE_AIMING 2048 // is using the laser sight -#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming -#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire -#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating -#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised -#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack -#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health - -// Defines used by TF_T_Damage (see combat.qc) -#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target -#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) -#define TF_TD_NOTSELF 4 // Doesn't damage self - -#define TF_TD_OTHER 0 // Ignore armorclass -#define TF_TD_SHOT 1 // Bullet damage -#define TF_TD_NAIL 2 // Nail damage -#define TF_TD_EXPLOSION 4 // Explosion damage -#define TF_TD_ELECTRICITY 8 // Electric damage -#define TF_TD_FIRE 16 // Fire damage -#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc - -/*==================================================*/ -/* Toggleable Game Settings */ -/*==================================================*/ -#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn -#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn -#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn - -#define TEAMPLAY_NORMAL 1 -#define TEAMPLAY_HALFDIRECT 2 -#define TEAMPLAY_NODIRECT 4 -#define TEAMPLAY_HALFEXPLOSIVE 8 -#define TEAMPLAY_NOEXPLOSIVE 16 -#define TEAMPLAY_LESSPLAYERSHELP 32 -#define TEAMPLAY_LESSSCOREHELP 64 -#define TEAMPLAY_HALFDIRECTARMOR 128 -#define TEAMPLAY_NODIRECTARMOR 256 -#define TEAMPLAY_HALFEXPARMOR 512 -#define TEAMPLAY_NOEXPARMOR 1024 -#define TEAMPLAY_HALFDIRMIRROR 2048 -#define TEAMPLAY_FULLDIRMIRROR 4096 -#define TEAMPLAY_HALFEXPMIRROR 8192 -#define TEAMPLAY_FULLEXPMIRROR 16384 - -#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) -// FortressMap stuff -#define TEAM1_CIVILIANS 1 -#define TEAM2_CIVILIANS 2 -#define TEAM3_CIVILIANS 4 -#define TEAM4_CIVILIANS 8 - -// Defines for the playerclass -#define PC_UNDEFINED 0 - -#define PC_SCOUT 1 -#define PC_SNIPER 2 -#define PC_SOLDIER 3 -#define PC_DEMOMAN 4 -#define PC_MEDIC 5 -#define PC_HVYWEAP 6 -#define PC_PYRO 7 -#define PC_SPY 8 -#define PC_ENGINEER 9 - -// Insert new class definitions here - -// PC_RANDOM _MUST_ be the third last class -#define PC_RANDOM 10 // Random playerclass -#define PC_CIVILIAN 11 // Civilians are a special class. They cannot - // be chosen by players, only enforced by maps -#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops - // through the playerclass. - -#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors - -// These are just for the scanner -#define SCAN_SENTRY 13 -#define SCAN_GOALITEM 14 - -// Values returned by CheckArea -enum -{ - CAREA_CLEAR, - CAREA_BLOCKED, - CAREA_NOBUILD -}; - -/*==================================================*/ -/* Impulse Defines */ -/*==================================================*/ -// Alias check to see whether they already have the aliases -#define TF_ALIAS_CHECK 13 - -// CTF Support Impulses -#define HOOK_IMP1 22 -#define FLAG_INFO 23 -#define HOOK_IMP2 39 - -// Axe -#define AXE_IMP 40 - -// Camera Impulse -#define TF_CAM_TARGET 50 -#define TF_CAM_ZOOM 51 -#define TF_CAM_ANGLE 52 -#define TF_CAM_VEC 53 -#define TF_CAM_PROJECTILE 54 -#define TF_CAM_PROJECTILE_Z 55 -#define TF_CAM_REVANGLE 56 -#define TF_CAM_OFFSET 57 -#define TF_CAM_DROP 58 -#define TF_CAM_FADETOBLACK 59 -#define TF_CAM_FADEFROMBLACK 60 -#define TF_CAM_FADETOWHITE 61 -#define TF_CAM_FADEFROMWHITE 62 - -// Last Weapon impulse -#define TF_LAST_WEAPON 69 - -// Status Bar Resolution Settings. Same as CTF to maintain ease of use. -#define TF_STATUSBAR_RES_START 71 -#define TF_STATUSBAR_RES_END 81 - -// Clan Messages -#define TF_MESSAGE_1 82 -#define TF_MESSAGE_2 83 -#define TF_MESSAGE_3 84 -#define TF_MESSAGE_4 85 -#define TF_MESSAGE_5 86 - -#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu - -// Added to PC_??? to get impulse to use if this clashes with your -// own impulses, just change this value, not the PC_?? -#define TF_CHANGEPC 100 -// The next few impulses are all the class selections -//PC_SCOUT 101 -//PC_SNIPER 102 -//PC_SOLDIER 103 -//PC_DEMOMAN 104 -//PC_MEDIC 105 -//PC_HVYWEAP 106 -//PC_PYRO 107 -//PC_RANDOM 108 -//PC_CIVILIAN 109 // Cannot be used -//PC_SPY 110 -//PC_ENGINEER 111 - -// Help impulses -#define TF_DISPLAYLOCATION 118 -#define TF_STATUS_QUERY 119 - -#define TF_HELP_MAP 131 - -// Information impulses -#define TF_INVENTORY 135 -#define TF_SHOWTF 136 -#define TF_SHOWLEGALCLASSES 137 - -// Team Impulses -#define TF_TEAM_1 140 // Join Team 1 -#define TF_TEAM_2 141 // Join Team 2 -#define TF_TEAM_3 142 // Join Team 3 -#define TF_TEAM_4 143 // Join Team 4 -#define TF_TEAM_CLASSES 144 // Impulse to display team classes -#define TF_TEAM_SCORES 145 // Impulse to display team scores -#define TF_TEAM_LIST 146 // Impulse to display the players in each team. - -// Grenade Impulses -#define TF_GRENADE_1 150 // Prime grenade type 1 -#define TF_GRENADE_2 151 // Prime grenade type 2 -#define TF_GRENADE_T 152 // Throw primed grenade - -// Impulses for new items -//#define TF_SCAN 159 // Scanner Pre-Impulse -#define TF_AUTO_SCAN 159 // Scanner On/Off -#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies -#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies -//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) -#define TF_SCAN_SOUND 162 // Scanner sounds on/off -#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) -#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) -#define TF_DETPACK_5 165 // Detpack set to 5 seconds -#define TF_DETPACK_20 166 // Detpack set to 20 seconds -#define TF_DETPACK_50 167 // Detpack set to 50 seconds -#define TF_DETPACK 168 // Detpack Pre-Impulse -#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack -#define TF_PB_DETONATE 170 // Detonate Pipebombs - -// Special skill -#define TF_SPECIAL_SKILL 171 - -// Ammo Drop impulse -#define TF_DROP_AMMO 172 - -// Reload impulse -#define TF_RELOAD 173 - -// auto-zoom toggle -#define TF_AUTOZOOM 174 - -// drop/pass commands -#define TF_DROPKEY 175 - -// Select Medikit -#define TF_MEDIKIT 176 - -// Spy Impulses -#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color -#define TF_SPY_DIE 178 // Feign Death - -// Engineer Impulses -#define TF_ENGINEER_BUILD 179 -#define TF_ENGINEER_SANDBAG 180 - -// Medic -#define TF_MEDIC_HELPME 181 - -// Status bar -#define TF_STATUSBAR_ON 182 -#define TF_STATUSBAR_OFF 183 - -// Discard impulse -#define TF_DISCARD 184 - -// ID Player impulse -#define TF_ID 185 - -// Clan Battle impulses -#define TF_SHOWIDS 186 - -// More Engineer Impulses -#define TF_ENGINEER_DETDISP 187 -#define TF_ENGINEER_DETSENT 188 - -// Admin Commands -#define TF_ADMIN_DEAL_CYCLE 189 -#define TF_ADMIN_KICK 190 -#define TF_ADMIN_BAN 191 -#define TF_ADMIN_COUNTPLAYERS 192 -#define TF_ADMIN_CEASEFIRE 193 - -// Drop Goal Items -#define TF_DROPGOALITEMS 194 - -// More Admin Commands -#define TF_ADMIN_NEXT 195 - -// More Engineer Impulses -#define TF_ENGINEER_DETEXIT 196 -#define TF_ENGINEER_DETENTRANCE 197 - -// Yet MORE Admin Commands -#define TF_ADMIN_LISTIPS 198 - -// Silent Spy Feign -#define TF_SPY_SILENTDIE 199 - - -/*==================================================*/ -/* Defines for the ENGINEER's Building ability */ -/*==================================================*/ -// Ammo costs -#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell -#define AMMO_COST_NAILS 1 -#define AMMO_COST_ROCKETS 2 -#define AMMO_COST_CELLS 2 - -// Building types -#define BUILD_DISPENSER 1 -#define BUILD_SENTRYGUN 2 -#define BUILD_MORTAR 3 -#define BUILD_TELEPORTER_ENTRANCE 4 -#define BUILD_TELEPORTER_EXIT 5 - -// Building metal costs -#define BUILD_COST_DISPENSER 100 // Metal needed to built -#define BUILD_COST_SENTRYGUN 130 -#define BUILD_COST_MORTAR 150 -#define BUILD_COST_TELEPORTER 125 - -#define BUILD_COST_SANDBAG 20 // Built with a separate alias - -// Building times -#define BUILD_TIME_DISPENSER 2 // seconds to build -#define BUILD_TIME_SENTRYGUN 5 -#define BUILD_TIME_MORTAR 5 -#define BUILD_TIME_TELEPORTER 4 - -// Building health levels -#define BUILD_HEALTH_DISPENSER 150 // Health of the building -#define BUILD_HEALTH_SENTRYGUN 150 -#define BUILD_HEALTH_MORTAR 200 -#define BUILD_HEALTH_TELEPORTER 80 - -// Dispenser's maximum carrying capability -#define BUILD_DISPENSER_MAX_SHELLS 400 -#define BUILD_DISPENSER_MAX_NAILS 600 -#define BUILD_DISPENSER_MAX_ROCKETS 300 -#define BUILD_DISPENSER_MAX_CELLS 400 -#define BUILD_DISPENSER_MAX_ARMOR 500 - -// Build state sent down to client -#define BS_BUILDING (1<<0) -#define BS_HAS_DISPENSER (1<<1) -#define BS_HAS_SENTRYGUN (1<<2) -#define BS_CANB_DISPENSER (1<<3) -#define BS_CANB_SENTRYGUN (1<<4) -/*==================================================*/ -/* Ammo quantities for dropping & dispenser use */ -/*==================================================*/ -#define DROP_SHELLS 20 -#define DROP_NAILS 20 -#define DROP_ROCKETS 10 -#define DROP_CELLS 10 -#define DROP_ARMOR 40 - -/*==================================================*/ -/* Team Defines */ -/*==================================================*/ -#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. - // A new global to hold new team colors is needed, and more flags - // in the spawnpoint spawnflags may need to be used. - // Basically, don't change this unless you know what you're doing :) - -/*==================================================*/ -/* New Weapon Defines */ -/*==================================================*/ -#define WEAP_HOOK 1 -#define WEAP_BIOWEAPON 2 -#define WEAP_MEDIKIT 4 -#define WEAP_SPANNER 8 -#define WEAP_AXE 16 -#define WEAP_SNIPER_RIFLE 32 -#define WEAP_AUTO_RIFLE 64 -#define WEAP_SHOTGUN 128 -#define WEAP_SUPER_SHOTGUN 256 -#define WEAP_NAILGUN 512 -#define WEAP_SUPER_NAILGUN 1024 -#define WEAP_GRENADE_LAUNCHER 2048 -#define WEAP_FLAMETHROWER 4096 -#define WEAP_ROCKET_LAUNCHER 8192 -#define WEAP_INCENDIARY 16384 -#define WEAP_ASSAULT_CANNON 32768 -#define WEAP_LIGHTNING 65536 -#define WEAP_DETPACK 131072 -#define WEAP_TRANQ 262144 -#define WEAP_LASER 524288 -// still room for 12 more weapons -// but we can remove some by giving the weapons -// a weapon mode (like the rifle) - -// HL-compatible weapon numbers -#define WEAPON_HOOK 1 -#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) -#define WEAPON_MEDIKIT (WEAPON_HOOK+2) -#define WEAPON_SPANNER (WEAPON_HOOK+3) -#define WEAPON_AXE (WEAPON_HOOK+4) -#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) -#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) -#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) -#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) -#define WEAPON_NAILGUN (WEAPON_HOOK+9) -#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) -#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) -#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) -#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) -#define WEAPON_INCENDIARY (WEAPON_HOOK+14) -#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) -#define WEAPON_LIGHTNING (WEAPON_HOOK+17) -#define WEAPON_DETPACK (WEAPON_HOOK+18) -#define WEAPON_TRANQ (WEAPON_HOOK+19) -#define WEAPON_LASER (WEAPON_HOOK+20) -#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) -#define WEAPON_KNIFE (WEAPON_HOOK+22) -#define WEAPON_BENCHMARK (WEAPON_HOOK+23) - -/*==================================================*/ -/* New Weapon Related Defines */ -/*==================================================*/ -// shots per reload -#define RE_SHOTGUN 8 -#define RE_SUPER_SHOTGUN 16 // 8 shots -#define RE_GRENADE_LAUNCHER 6 -#define RE_ROCKET_LAUNCHER 4 - -// reload times -#define RE_SHOTGUN_TIME 2 -#define RE_SUPER_SHOTGUN_TIME 3 -#define RE_GRENADE_LAUNCHER_TIME 4 -#define RE_ROCKET_LAUNCHER_TIME 5 - -// Maximum velocity you can move and fire the Sniper Rifle -#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 - -// Medikit -#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit -#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense - -// Spanner -#define WEAP_SPANNER_REPAIR 10 - -// Detpack -#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack -#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack -#define WEAP_DETPACK_SIZE 700 // Explosion Size -#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering -#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into - -// Tranquiliser Gun -#define TRANQ_TIME 15 - -// Grenades -#define GR_PRIMETIME 3 -#define GR_CALTROP_PRIME 0.5 -#define GR_TYPE_NONE 0 -#define GR_TYPE_NORMAL 1 -#define GR_TYPE_CONCUSSION 2 -#define GR_TYPE_NAIL 3 -#define GR_TYPE_MIRV 4 -#define GR_TYPE_NAPALM 5 -//#define GR_TYPE_FLARE 6 -#define GR_TYPE_GAS 7 -#define GR_TYPE_EMP 8 -#define GR_TYPE_CALTROP 9 -//#define GR_TYPE_FLASH 10 - -// Defines for WeaponMode -#define GL_NORMAL 0 -#define GL_PIPEBOMB 1 - -// Defines for OLD Concussion Grenade -#define GR_OLD_CONCUSS_TIME 5 -#define GR_OLD_CONCUSS_DEC 20 - -// Defines for Concussion Grenade -#define GR_CONCUSS_TIME 0.25 -#define GR_CONCUSS_DEC 10 -#define MEDIUM_PING 150 -#define HIGH_PING 200 - -// Defines for the Gas Grenade -#define GR_HALLU_TIME 0.3 -#define GR_OLD_HALLU_TIME 0.5 -#define GR_HALLU_DEC 2.5 - -// Defines for the BioInfection -#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players - -/*==================================================*/ -/* New Items */ -/*==================================================*/ -#define NIT_SCANNER 1 - -#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 -#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 - -/*==================================================*/ -/* New Item Flags */ -/*==================================================*/ -#define NIT_SCANNER_ENEMY 1 // Detect enemies -#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) -#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. - -/*==================================================*/ -/* New Item Related Defines */ -/*==================================================*/ -#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner - // is multiplied by this to get the scanrange. -#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan -#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected - // by scanners that only detect movement - -/*==================================================*/ -/* Variables used for New Weapons and Reloading */ -/*==================================================*/ -// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. -#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% -#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% -#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% -#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% -#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% - -/*==========================================================================*/ -/* TEAMFORTRESS CLASS DETAILS */ -/*==========================================================================*/ -// Class Details for SCOUT -#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. -#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level -#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed -#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed -#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class -#define PC_SCOUT_INITARMOR 25 // Armor level when respawned -#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption -#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned -#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class -#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned -#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN -#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry -#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry -#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry -#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry -#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned -#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned -#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned -#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned -#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has -#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has -#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned -#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned -#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has - -#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range -#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector -#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse -#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range -#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan - -// Class Details for SNIPER -#define PC_SNIPER_SKIN 5 -#define PC_SNIPER_MAXHEALTH 90 -#define PC_SNIPER_MAXSPEED 300 -#define PC_SNIPER_MAXSTRAFESPEED 300 -#define PC_SNIPER_MAXARMOR 50 -#define PC_SNIPER_INITARMOR 0 -#define PC_SNIPER_MAXARMORTYPE 0.3 -#define PC_SNIPER_INITARMORTYPE 0.3 -#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL -#define PC_SNIPER_INITARMORCLASS 0 -#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN -#define PC_SNIPER_MAXAMMO_SHOT 75 -#define PC_SNIPER_MAXAMMO_NAIL 100 -#define PC_SNIPER_MAXAMMO_CELL 50 -#define PC_SNIPER_MAXAMMO_ROCKET 25 -#define PC_SNIPER_INITAMMO_SHOT 60 -#define PC_SNIPER_INITAMMO_NAIL 50 -#define PC_SNIPER_INITAMMO_CELL 0 -#define PC_SNIPER_INITAMMO_ROCKET 0 -#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE -#define PC_SNIPER_GRENADE_INIT_1 2 -#define PC_SNIPER_GRENADE_INIT_2 0 -#define PC_SNIPER_TF_ITEMS 0 - -// Class Details for SOLDIER -#define PC_SOLDIER_SKIN 6 -#define PC_SOLDIER_MAXHEALTH 100 -#define PC_SOLDIER_MAXSPEED 240 -#define PC_SOLDIER_MAXSTRAFESPEED 240 -#define PC_SOLDIER_MAXARMOR 200 -#define PC_SOLDIER_INITARMOR 100 -#define PC_SOLDIER_MAXARMORTYPE 0.8 -#define PC_SOLDIER_INITARMORTYPE 0.8 -#define PC_SOLDIER_ARMORCLASSES 31 // ALL -#define PC_SOLDIER_INITARMORCLASS 0 -#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER -#define PC_SOLDIER_MAXAMMO_SHOT 100 -#define PC_SOLDIER_MAXAMMO_NAIL 100 -#define PC_SOLDIER_MAXAMMO_CELL 50 -#define PC_SOLDIER_MAXAMMO_ROCKET 50 -#define PC_SOLDIER_INITAMMO_SHOT 50 -#define PC_SOLDIER_INITAMMO_NAIL 0 -#define PC_SOLDIER_INITAMMO_CELL 0 -#define PC_SOLDIER_INITAMMO_ROCKET 10 -#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL -#define PC_SOLDIER_GRENADE_INIT_1 2 -#define PC_SOLDIER_GRENADE_INIT_2 1 -#define PC_SOLDIER_TF_ITEMS 0 - -#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active -#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active -#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active -#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's -#define MAX_CONCUSSION_GRENS 3 -#define MAX_CALTROP_CANS 3 - -// Class Details for DEMOLITION MAN -#define PC_DEMOMAN_SKIN 1 -#define PC_DEMOMAN_MAXHEALTH 90 -#define PC_DEMOMAN_MAXSPEED 280 -#define PC_DEMOMAN_MAXSTRAFESPEED 280 -#define PC_DEMOMAN_MAXARMOR 120 -#define PC_DEMOMAN_INITARMOR 50 -#define PC_DEMOMAN_MAXARMORTYPE 0.6 -#define PC_DEMOMAN_INITARMORTYPE 0.6 -#define PC_DEMOMAN_ARMORCLASSES 31 // ALL -#define PC_DEMOMAN_INITARMORCLASS 0 -#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK -#define PC_DEMOMAN_MAXAMMO_SHOT 75 -#define PC_DEMOMAN_MAXAMMO_NAIL 50 -#define PC_DEMOMAN_MAXAMMO_CELL 50 -#define PC_DEMOMAN_MAXAMMO_ROCKET 50 -#define PC_DEMOMAN_MAXAMMO_DETPACK 1 -#define PC_DEMOMAN_INITAMMO_SHOT 30 -#define PC_DEMOMAN_INITAMMO_NAIL 0 -#define PC_DEMOMAN_INITAMMO_CELL 0 -#define PC_DEMOMAN_INITAMMO_ROCKET 20 -#define PC_DEMOMAN_INITAMMO_DETPACK 1 -#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV -#define PC_DEMOMAN_GRENADE_INIT_1 2 -#define PC_DEMOMAN_GRENADE_INIT_2 2 -#define PC_DEMOMAN_TF_ITEMS 0 - -// Class Details for COMBAT MEDIC -#define PC_MEDIC_SKIN 3 -#define PC_MEDIC_MAXHEALTH 90 -#define PC_MEDIC_MAXSPEED 320 -#define PC_MEDIC_MAXSTRAFESPEED 320 -#define PC_MEDIC_MAXARMOR 100 -#define PC_MEDIC_INITARMOR 50 -#define PC_MEDIC_MAXARMORTYPE 0.6 -#define PC_MEDIC_INITARMORTYPE 0.3 -#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION -#define PC_MEDIC_INITARMORCLASS 0 -#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN -#define PC_MEDIC_MAXAMMO_SHOT 75 -#define PC_MEDIC_MAXAMMO_NAIL 150 -#define PC_MEDIC_MAXAMMO_CELL 50 -#define PC_MEDIC_MAXAMMO_ROCKET 25 -#define PC_MEDIC_MAXAMMO_MEDIKIT 100 -#define PC_MEDIC_INITAMMO_SHOT 50 -#define PC_MEDIC_INITAMMO_NAIL 50 -#define PC_MEDIC_INITAMMO_CELL 0 -#define PC_MEDIC_INITAMMO_ROCKET 0 -#define PC_MEDIC_INITAMMO_MEDIKIT 50 -#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION -#define PC_MEDIC_GRENADE_INIT_1 2 -#define PC_MEDIC_GRENADE_INIT_2 2 -#define PC_MEDIC_TF_ITEMS 0 -#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. -#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. - -// Class Details for HVYWEAP -#define PC_HVYWEAP_SKIN 2 -#define PC_HVYWEAP_MAXHEALTH 100 -#define PC_HVYWEAP_MAXSPEED 230 -#define PC_HVYWEAP_MAXSTRAFESPEED 230 -#define PC_HVYWEAP_MAXARMOR 300 -#define PC_HVYWEAP_INITARMOR 150 -#define PC_HVYWEAP_MAXARMORTYPE 0.8 -#define PC_HVYWEAP_INITARMORTYPE 0.8 -#define PC_HVYWEAP_ARMORCLASSES 31 // ALL -#define PC_HVYWEAP_INITARMORCLASS 0 -#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN -#define PC_HVYWEAP_MAXAMMO_SHOT 200 -#define PC_HVYWEAP_MAXAMMO_NAIL 200 -#define PC_HVYWEAP_MAXAMMO_CELL 50 -#define PC_HVYWEAP_MAXAMMO_ROCKET 25 -#define PC_HVYWEAP_INITAMMO_SHOT 200 -#define PC_HVYWEAP_INITAMMO_NAIL 0 -#define PC_HVYWEAP_INITAMMO_CELL 30 -#define PC_HVYWEAP_INITAMMO_ROCKET 0 -#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV -#define PC_HVYWEAP_GRENADE_INIT_1 2 -#define PC_HVYWEAP_GRENADE_INIT_2 1 -#define PC_HVYWEAP_TF_ITEMS 0 -#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon - - - -// Class Details for PYRO -#define PC_PYRO_SKIN 21 -#define PC_PYRO_MAXHEALTH 100 -#define PC_PYRO_MAXSPEED 300 -#define PC_PYRO_MAXSTRAFESPEED 300 -#define PC_PYRO_MAXARMOR 150 -#define PC_PYRO_INITARMOR 50 -#define PC_PYRO_MAXARMORTYPE 0.6 -#define PC_PYRO_INITARMORTYPE 0.6 -#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION -#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE -#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN -#define PC_PYRO_MAXAMMO_SHOT 40 -#define PC_PYRO_MAXAMMO_NAIL 50 -#define PC_PYRO_MAXAMMO_CELL 200 -#define PC_PYRO_MAXAMMO_ROCKET 20 -#define PC_PYRO_INITAMMO_SHOT 20 -#define PC_PYRO_INITAMMO_NAIL 0 -#define PC_PYRO_INITAMMO_CELL 120 -#define PC_PYRO_INITAMMO_ROCKET 5 -#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM -#define PC_PYRO_GRENADE_INIT_1 2 -#define PC_PYRO_GRENADE_INIT_2 4 -#define PC_PYRO_TF_ITEMS 0 -#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot - -// Class Details for SPY -#define PC_SPY_SKIN 22 -#define PC_SPY_MAXHEALTH 90 -#define PC_SPY_MAXSPEED 300 -#define PC_SPY_MAXSTRAFESPEED 300 -#define PC_SPY_MAXARMOR 100 -#define PC_SPY_INITARMOR 25 -#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 -#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 -#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION -#define PC_SPY_INITARMORCLASS 0 -#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN -#define PC_SPY_MAXAMMO_SHOT 40 -#define PC_SPY_MAXAMMO_NAIL 100 -#define PC_SPY_MAXAMMO_CELL 30 -#define PC_SPY_MAXAMMO_ROCKET 15 -#define PC_SPY_INITAMMO_SHOT 40 -#define PC_SPY_INITAMMO_NAIL 50 -#define PC_SPY_INITAMMO_CELL 10 -#define PC_SPY_INITAMMO_ROCKET 0 -#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS -#define PC_SPY_GRENADE_INIT_1 2 -#define PC_SPY_GRENADE_INIT_2 2 -#define PC_SPY_TF_ITEMS 0 -#define PC_SPY_CELL_REGEN_TIME 5 -#define PC_SPY_CELL_REGEN_AMOUNT 1 -#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible -#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover - -// Class Details for ENGINEER -#define PC_ENGINEER_SKIN 22 // Not used anymore -#define PC_ENGINEER_MAXHEALTH 80 -#define PC_ENGINEER_MAXSPEED 300 -#define PC_ENGINEER_MAXSTRAFESPEED 300 -#define PC_ENGINEER_MAXARMOR 50 -#define PC_ENGINEER_INITARMOR 25 -#define PC_ENGINEER_MAXARMORTYPE 0.6 -#define PC_ENGINEER_INITARMORTYPE 0.3 -#define PC_ENGINEER_ARMORCLASSES 31 // ALL -#define PC_ENGINEER_INITARMORCLASS 0 -#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN -#define PC_ENGINEER_MAXAMMO_SHOT 50 -#define PC_ENGINEER_MAXAMMO_NAIL 50 -#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal -#define PC_ENGINEER_MAXAMMO_ROCKET 30 -#define PC_ENGINEER_INITAMMO_SHOT 20 -#define PC_ENGINEER_INITAMMO_NAIL 25 -#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal -#define PC_ENGINEER_INITAMMO_ROCKET 0 -#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL -#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP -#define PC_ENGINEER_GRENADE_INIT_1 2 -#define PC_ENGINEER_GRENADE_INIT_2 2 -#define PC_ENGINEER_TF_ITEMS 0 - -// Class Details for CIVILIAN -#define PC_CIVILIAN_SKIN 22 -#define PC_CIVILIAN_MAXHEALTH 50 -#define PC_CIVILIAN_MAXSPEED 240 -#define PC_CIVILIAN_MAXSTRAFESPEED 240 -#define PC_CIVILIAN_MAXARMOR 0 -#define PC_CIVILIAN_INITARMOR 0 -#define PC_CIVILIAN_MAXARMORTYPE 0 -#define PC_CIVILIAN_INITARMORTYPE 0 -#define PC_CIVILIAN_ARMORCLASSES 0 -#define PC_CIVILIAN_INITARMORCLASS 0 -#define PC_CIVILIAN_WEAPONS WEAP_AXE -#define PC_CIVILIAN_MAXAMMO_SHOT 0 -#define PC_CIVILIAN_MAXAMMO_NAIL 0 -#define PC_CIVILIAN_MAXAMMO_CELL 0 -#define PC_CIVILIAN_MAXAMMO_ROCKET 0 -#define PC_CIVILIAN_INITAMMO_SHOT 0 -#define PC_CIVILIAN_INITAMMO_NAIL 0 -#define PC_CIVILIAN_INITAMMO_CELL 0 -#define PC_CIVILIAN_INITAMMO_ROCKET 0 -#define PC_CIVILIAN_GRENADE_TYPE_1 0 -#define PC_CIVILIAN_GRENADE_TYPE_2 0 -#define PC_CIVILIAN_GRENADE_INIT_1 0 -#define PC_CIVILIAN_GRENADE_INIT_2 0 -#define PC_CIVILIAN_TF_ITEMS 0 - - -/*==========================================================================*/ -/* TEAMFORTRESS GOALS */ -/*==========================================================================*/ -// For all these defines, see the tfortmap.txt that came with the zip -// for complete descriptions. -// Defines for Goal Activation types : goal_activation (in goals) -#define TFGA_TOUCH 1 // Activated when touched -#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion -#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met -#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner -#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning - -// Defines for Goal Effects types : goal_effect -#define TFGE_AP 1 // AP is affected. Default. -#define TFGE_AP_TEAM 2 // All of the AP's team. -#define TFGE_NOT_AP_TEAM 4 // All except AP's team. -#define TFGE_NOT_AP 8 // All except AP. -#define TFGE_WALL 16 // If set, walls stop the Radius effects -#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected -#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects - -// Defines for Goal Result types : goal_result -#define TFGR_SINGLE 1 // Goal can only be activated once -#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses -#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level -#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results -#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy -#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point -#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys - -// Defines for Goal Group Result types : goal_group -// None! -// But I'm leaving this variable in there, since it's fairly likely -// that some will show up sometime. - -// Defines for Goal Item types, : goal_activation (in items) -#define TFGI_GLOW 1 // Players carrying this GoalItem will glow -#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed -#define TFGI_DROP 4 // Players dying with this item will drop it -#define TFGI_RETURN_DROP 8 // Return if a player with it dies -#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation -#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE -#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details -#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped -#define TFGI_KEEP 256 // Players keep this item even when they die -#define TFGI_ITEMGLOWS 512 // Item glows when on the ground -#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed -#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning -#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players -#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc - -// Defines for methods of GoalItem returning -#define GI_RET_DROP_DEAD 0 // Dropped by a dead player -#define GI_RET_DROP_LIVING 1 // Dropped by a living player -#define GI_RET_GOAL 2 // Returned by a Goal -#define GI_RET_TIME 3 // Returned due to timeout - -// Defines for TeamSpawnpoints : goal_activation (in teamspawns) -#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times -#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times - -// Defines for TeamSpawnpoints : goal_effects (in teamspawns) -#define TFSP_REMOVESELF 1 // Remove itself after being spawned on - -// Defines for Goal States -#define TFGS_ACTIVE 1 -#define TFGS_INACTIVE 2 -#define TFGS_REMOVED 3 -#define TFGS_DELAYED 4 - -// Defines for GoalItem Removing from Player Methods -#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player -#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal -#define GI_DROP_PLAYERDROP 2 // Dropped by a player - -// Legal Playerclass Handling -#define TF_ILL_SCOUT 1 -#define TF_ILL_SNIPER 2 -#define TF_ILL_SOLDIER 4 -#define TF_ILL_DEMOMAN 8 -#define TF_ILL_MEDIC 16 -#define TF_ILL_HVYWEP 32 -#define TF_ILL_PYRO 64 -#define TF_ILL_RANDOMPC 128 -#define TF_ILL_SPY 256 -#define TF_ILL_ENGINEER 512 - -// Addition classes -#define CLASS_TFGOAL 128 -#define CLASS_TFGOAL_TIMER 129 -#define CLASS_TFGOAL_ITEM 130 -#define CLASS_TFSPAWN 131 - -/*==========================================================================*/ -/* Flamethrower */ -/*==========================================================================*/ -#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player -#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) -#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade -#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player -#define FLAME_NUMLIGHTS 1 // maximum number of light flame -#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' -#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode -#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames -#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. -#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn -#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players - -/*==================================================*/ -/* CTF Support defines */ -/*==================================================*/ -#define CTF_FLAG1 1 -#define CTF_FLAG2 2 -#define CTF_DROPOFF1 3 -#define CTF_DROPOFF2 4 -#define CTF_SCORE1 5 -#define CTF_SCORE2 6 - -//.float hook_out; - -/*==================================================*/ -/* Camera defines */ -/*==================================================*/ -/* -float live_camera; -.float camdist; -.vector camangle; -.entity camera_list; -*/ - -/*==================================================*/ -/* QuakeWorld defines */ -/*==================================================*/ -/* -float already_chosen_map; - -// grappling hook variables -.entity hook; -.float on_hook; -.float fire_held_down;// flag - TRUE if player is still holding down the - // fire button after throwing a hook. -*/ -/*==================================================*/ -/* Server Settings */ -/*==================================================*/ -// Admin modes -#define ADMIN_MODE_NONE 0 -#define ADMIN_MODE_DEAL 1 - -/*==================================================*/ -/* Death Message defines */ -/*==================================================*/ -#define DMSG_SHOTGUN 1 -#define DMSG_SSHOTGUN 2 -#define DMSG_NAILGUN 3 -#define DMSG_SNAILGUN 4 -#define DMSG_GRENADEL 5 -#define DMSG_ROCKETL 6 -#define DMSG_LIGHTNING 7 -#define DMSG_GREN_HAND 8 -#define DMSG_GREN_NAIL 9 -#define DMSG_GREN_MIRV 10 -#define DMSG_GREN_PIPE 11 -#define DMSG_DETPACK 12 -#define DMSG_BIOWEAPON 13 -#define DMSG_BIOWEAPON_ATT 14 -#define DMSG_FLAME 15 -#define DMSG_DETPACK_DIS 16 -#define DMSG_AXE 17 -#define DMSG_SNIPERRIFLE 18 -#define DMSG_AUTORIFLE 19 -#define DMSG_ASSAULTCANNON 20 -#define DMSG_HOOK 21 -#define DMSG_BACKSTAB 22 -#define DMSG_MEDIKIT 23 -#define DMSG_GREN_GAS 24 -#define DMSG_TRANQ 25 -#define DMSG_LASERBOLT 26 -#define DMSG_SENTRYGUN_BULLET 27 -#define DMSG_SNIPERLEGSHOT 28 -#define DMSG_SNIPERHEADSHOT 29 -#define DMSG_GREN_EMP 30 -#define DMSG_GREN_EMP_AMMO 31 -#define DMSG_SPANNER 32 -#define DMSG_INCENDIARY 33 -#define DMSG_SENTRYGUN_ROCKET 34 -#define DMSG_GREN_FLASH 35 -#define DMSG_TRIGGER 36 -#define DMSG_MIRROR 37 -#define DMSG_SENTRYDEATH 38 -#define DMSG_DISPENSERDEATH 39 -#define DMSG_GREN_AIRPIPE 40 -#define DMSG_CALTROP 41 - -/*==================================================*/ -// TOGGLEFLAGS -/*==================================================*/ -// Some of the toggleflags aren't used anymore, but the bits are still -// there to provide compatability with old maps -#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit -#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit -#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit -//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE -#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade -#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE -#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE -#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. -#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore -#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set - // In a map. Cannot be toggled by players. -#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only -#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off -//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags -#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps -#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation - -#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only - -/*======================*/ -// Menu stuff // -/*======================*/ - -#define MENU_DEFAULT 1 -#define MENU_TEAM 2 -#define MENU_CLASS 3 -#define MENU_MAPBRIEFING 4 -#define MENU_INTRO 5 -#define MENU_CLASSHELP 6 -#define MENU_CLASSHELP2 7 -#define MENU_REPEATHELP 8 - -#define MENU_SPECHELP 9 - - -#define MENU_SPY 12 -#define MENU_SPY_SKIN 13 -#define MENU_SPY_COLOR 14 -#define MENU_ENGINEER 15 -#define MENU_ENGINEER_FIX_DISPENSER 16 -#define MENU_ENGINEER_FIX_SENTRYGUN 17 -#define MENU_ENGINEER_FIX_MORTAR 18 -#define MENU_DISPENSER 19 -#define MENU_CLASS_CHANGE 20 -#define MENU_TEAM_CHANGE 21 - -#define MENU_REFRESH_RATE 25 - -#define MENU_VOICETWEAK 50 - -//============================ -// Timer Types -#define TF_TIMER_ANY 0 -#define TF_TIMER_CONCUSSION 1 -#define TF_TIMER_INFECTION 2 -#define TF_TIMER_HALLUCINATION 3 -#define TF_TIMER_TRANQUILISATION 4 -#define TF_TIMER_ROTHEALTH 5 -#define TF_TIMER_REGENERATION 6 -#define TF_TIMER_GRENPRIME 7 -#define TF_TIMER_CELLREGENERATION 8 -#define TF_TIMER_DETPACKSET 9 -#define TF_TIMER_DETPACKDISARM 10 -#define TF_TIMER_BUILD 11 -#define TF_TIMER_CHECKBUILDDISTANCE 12 -#define TF_TIMER_DISGUISE 13 -#define TF_TIMER_DISPENSERREFILL 14 - -// Non Player timers -#define TF_TIMER_RETURNITEM 100 -#define TF_TIMER_DELAYEDGOAL 101 -#define TF_TIMER_ENDROUND 102 - -//============================ -// Teamscore printing -#define TS_PRINT_SHORT 1 -#define TS_PRINT_LONG 2 -#define TS_PRINT_LONG_TO_ALL 3 - -#ifndef TF_DEFS_ONLY - -typedef struct -{ - int topColor; - int bottomColor; -} team_color_t; - - -/*==================================================*/ -/* GLOBAL VARIABLES */ -/*==================================================*/ -// FortressMap stuff -extern float number_of_teams; // number of teams supported by the map -extern int illegalclasses[5]; // Illegal playerclasses for all teams -extern int civilianteams; // Bitfield holding Civilian teams -extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams - -extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams - -extern int teamscores[5]; // Goal Score of each team -extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers -extern int teamfrags[5]; // Total Frags for each team -extern int teamlives[5]; // Number of lives each team's players have -extern int teammaxplayers[5]; // Max number of players allowed in each team -extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set - // stores the damage ratio players take/give -extern int teamallies[5]; // Keeps track of which teams are allied -extern string_t team_names[5]; - -extern BOOL CTF_Map; -extern BOOL birthday; -extern BOOL christmas; - -extern float num_world_flames; - -// Clan Battle stuff -extern float clan_scores_dumped; -extern float cb_prematch_time; -extern float fOldPrematch; -extern float fOldCeaseFire; -extern float cb_ceasefire_time; -extern float last_id; -extern float spy_off; -extern float old_grens; -extern float flagem_checked; -extern float flNextEqualisationCalc; -extern BOOL cease_fire; -extern BOOL no_cease_fire_text; -extern BOOL initial_cease_fire; -extern BOOL last_cease_fire; -// Autokick stuff -extern float autokick_kills; - -extern float deathmsg; // Global, which is set before every T_Damage, to indicate - // the death message that should be used. - -extern char *sTeamSpawnNames[]; -extern char *sClassNames[]; -extern char *sNewClassModelFiles[]; -extern char *sOldClassModelFiles[]; -extern char *sClassModels[]; -extern char *sClassCfgs[]; -extern char *sGrenadeNames[]; -extern string_t team_menu_string; - -extern int toggleflags; // toggleable flags - -extern CBaseEntity* g_pLastSpawns[5]; -extern BOOL g_bFirstClient; - -extern float g_fNextPrematchAlert; - -typedef struct -{ - int ip; - edict_t *pEdict; -} ip_storage_t; - -extern ip_storage_t g_IpStorage[32]; - -class CGhost; -/*==========================================================================*/ -BOOL ClassIsRestricted(float tno, int pc); -char* GetTeamName(int tno); -int TeamFortress_GetNoPlayers(); -void DestroyBuilding(CBaseEntity *eng, char *bld); -void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); -float anglemod( float v ); - -// Team Funcs -BOOL TeamFortress_TeamIsCivilian(float tno); -void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); -BOOL TeamFortress_TeamPutPlayerInTeam(); -void TeamFortress_TeamSetColor(int tno); -void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); -int TeamFortress_TeamGetScoreFrags(int tno); -int TeamFortress_TeamGetNoPlayers(int tno); -float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); -BOOL IsSpawnPointValid( Vector &pos ); -BOOL TeamFortress_SortTeams( void ); -void DumpClanScores( void ); -void CalculateTeamEqualiser(); - -// mapscript funcs -void ParseTFServerSettings(); -void ParseTFMapSettings(); -CBaseEntity* Finditem(int ino); -CBaseEntity* Findgoal(int gno); -CBaseEntity* Findteamspawn(int gno); -void RemoveGoal(CBaseEntity *Goal); -void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); -void dremove( CBaseEntity *te ); -void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); -void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); -void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); -void tfgoalitem_checkgoalreturn(CBaseEntity *Item); -void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); -void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); -void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); -// hooks into the mapscript for all entities -BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); -BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); - -// prematch & ceasefire -void Display_Prematch(); -void Check_Ceasefire(); - -// admin -void KickPlayer( CBaseEntity *pTarget ); -void BanPlayer( CBaseEntity *pTarget ); -CGhost *FindGhost( int iGhostID ); -int GetBattleID( edict_t *pEntity ); - -extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) -extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. -extern cvar_t tfc_spam_limit; // at this many points, gag the spammer -extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; -extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; -extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; -extern cvar_t allow_spectators; - -/*==========================================================================*/ -class CTFFlame : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT FlameThink( void ); - static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); - void FlameDestroy( void ); - - float m_flNextDamageTime; -}; - -/*==========================================================================*/ -// MAPSCRIPT CLASSES -class CTFGoal : public CBaseAnimating -{ -public: - void Spawn( void ); - void StartGoal( void ); - void EXPORT PlaceGoal( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int Classify ( void ) { return CLASS_TFGOAL; } - - void SetObjectCollisionBox( void ); -}; - -class CTFGoalItem : public CTFGoal -{ -public: - void Spawn( void ); - void StartItem( void ); - void EXPORT PlaceItem( void ); - int Classify ( void ) { return CLASS_TFGOAL_ITEM; } - - float m_flDroppedAt; -}; - -class CTFTimerGoal : public CTFGoal -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_TFGOAL_TIMER; } -}; - -class CTFSpawn : public CBaseEntity -{ -public: - void Spawn( void ); - void Activate( void ); - int Classify ( void ) { return CLASS_TFSPAWN; } - BOOL CheckTeam( int iTeamNo ); - - EHANDLE m_pTeamCheck; -}; - -class CTFDetect : public CBaseEntity -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_TFGOAL; } -}; - -class CTelefragDeath : public CBaseEntity -{ -public: - void Spawn( void ); - void EXPORT DeathTouch( CBaseEntity *pOther ); -}; - -class CTeamCheck : public CBaseDelay -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - BOOL TeamMatches( int iTeam ); -}; - -class CTeamSet : public CBaseDelay -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -#endif // TF_DEFS_ONLY -#endif // __TF_DEFS_H - - +/*** +* +* 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. +* +****/ + +#ifndef __TF_DEFS_H +#define __TF_DEFS_H + +//=========================================================================== +// OLD OPTIONS.QC +//=========================================================================== +#define DEFAULT_AUTOZOOM FALSE +#define WEINER_SNIPER // autoaiming for sniper rifle +#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. + +//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server +#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active +#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active + +//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time +//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server +#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into +#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) +#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies + +#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. + // 60 is a mild setting, and won't make too much difference + // increasing it _decreases_ the amount of help the losing team gets + // Minimum setting is 1, which would really help the losing team + +#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to + // appear whenever a player connects +#define NEVER_TEAMFRAGS FALSE // teamfrags options always off +#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on +#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast +#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds + +#define MAPBRIEFING_MAXTEXTLENGTH 512 +#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed + +// Debug Options +//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res + // mode and/or piping the output from the server to a file. +#ifdef MAP_DEBUG + #define MDEBUG(x) x +#else + #define MDEBUG(x) +#endif +//#define VERBOSE // Verbose Debugging on/off + +//=========================================================================== +// OLD QUAKE Defs +//=========================================================================== +// items +#define IT_AXE 4096 +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_EXTRA_WEAPON 128 + +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 + +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 + +#define IT_KEY1 131072 +#define IT_KEY2 262144 + +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_HOOK 8388608 + +#define IT_KEY3 16777216 // Stomp invisibility +#define IT_KEY4 33554432 // Stomp invulnerability + +//=========================================================================== +// TEAMFORTRESS Defs +//=========================================================================== +// TeamFortress State Flags +#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade +#define TFSTATE_RELOADING 2 // Whether the player is reloading +#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE +#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn +#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon +#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) +#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) +#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) +#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) +#define TFSTATE_BURNING 512 // Is on fire +#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade +#define TFSTATE_AIMING 2048 // is using the laser sight +#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating +#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised +#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health + +// Defines used by TF_T_Damage (see combat.qc) +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) +#define TF_TD_NOTSELF 4 // Doesn't damage self + +#define TF_TD_OTHER 0 // Ignore armorclass +#define TF_TD_SHOT 1 // Bullet damage +#define TF_TD_NAIL 2 // Nail damage +#define TF_TD_EXPLOSION 4 // Explosion damage +#define TF_TD_ELECTRICITY 8 // Electric damage +#define TF_TD_FIRE 16 // Fire damage +#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc + +/*==================================================*/ +/* Toggleable Game Settings */ +/*==================================================*/ +#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn + +#define TEAMPLAY_NORMAL 1 +#define TEAMPLAY_HALFDIRECT 2 +#define TEAMPLAY_NODIRECT 4 +#define TEAMPLAY_HALFEXPLOSIVE 8 +#define TEAMPLAY_NOEXPLOSIVE 16 +#define TEAMPLAY_LESSPLAYERSHELP 32 +#define TEAMPLAY_LESSSCOREHELP 64 +#define TEAMPLAY_HALFDIRECTARMOR 128 +#define TEAMPLAY_NODIRECTARMOR 256 +#define TEAMPLAY_HALFEXPARMOR 512 +#define TEAMPLAY_NOEXPARMOR 1024 +#define TEAMPLAY_HALFDIRMIRROR 2048 +#define TEAMPLAY_FULLDIRMIRROR 4096 +#define TEAMPLAY_HALFEXPMIRROR 8192 +#define TEAMPLAY_FULLEXPMIRROR 16384 + +#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) +// FortressMap stuff +#define TEAM1_CIVILIANS 1 +#define TEAM2_CIVILIANS 2 +#define TEAM3_CIVILIANS 4 +#define TEAM4_CIVILIANS 8 + +// Defines for the playerclass +#define PC_UNDEFINED 0 + +#define PC_SCOUT 1 +#define PC_SNIPER 2 +#define PC_SOLDIER 3 +#define PC_DEMOMAN 4 +#define PC_MEDIC 5 +#define PC_HVYWEAP 6 +#define PC_PYRO 7 +#define PC_SPY 8 +#define PC_ENGINEER 9 + +// Insert new class definitions here + +// PC_RANDOM _MUST_ be the third last class +#define PC_RANDOM 10 // Random playerclass +#define PC_CIVILIAN 11 // Civilians are a special class. They cannot + // be chosen by players, only enforced by maps +#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops + // through the playerclass. + +#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors + +// These are just for the scanner +#define SCAN_SENTRY 13 +#define SCAN_GOALITEM 14 + +// Values returned by CheckArea +enum +{ + CAREA_CLEAR, + CAREA_BLOCKED, + CAREA_NOBUILD +}; + +/*==================================================*/ +/* Impulse Defines */ +/*==================================================*/ +// Alias check to see whether they already have the aliases +#define TF_ALIAS_CHECK 13 + +// CTF Support Impulses +#define HOOK_IMP1 22 +#define FLAG_INFO 23 +#define HOOK_IMP2 39 + +// Axe +#define AXE_IMP 40 + +// Camera Impulse +#define TF_CAM_TARGET 50 +#define TF_CAM_ZOOM 51 +#define TF_CAM_ANGLE 52 +#define TF_CAM_VEC 53 +#define TF_CAM_PROJECTILE 54 +#define TF_CAM_PROJECTILE_Z 55 +#define TF_CAM_REVANGLE 56 +#define TF_CAM_OFFSET 57 +#define TF_CAM_DROP 58 +#define TF_CAM_FADETOBLACK 59 +#define TF_CAM_FADEFROMBLACK 60 +#define TF_CAM_FADETOWHITE 61 +#define TF_CAM_FADEFROMWHITE 62 + +// Last Weapon impulse +#define TF_LAST_WEAPON 69 + +// Status Bar Resolution Settings. Same as CTF to maintain ease of use. +#define TF_STATUSBAR_RES_START 71 +#define TF_STATUSBAR_RES_END 81 + +// Clan Messages +#define TF_MESSAGE_1 82 +#define TF_MESSAGE_2 83 +#define TF_MESSAGE_3 84 +#define TF_MESSAGE_4 85 +#define TF_MESSAGE_5 86 + +#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu + +// Added to PC_??? to get impulse to use if this clashes with your +// own impulses, just change this value, not the PC_?? +#define TF_CHANGEPC 100 +// The next few impulses are all the class selections +//PC_SCOUT 101 +//PC_SNIPER 102 +//PC_SOLDIER 103 +//PC_DEMOMAN 104 +//PC_MEDIC 105 +//PC_HVYWEAP 106 +//PC_PYRO 107 +//PC_RANDOM 108 +//PC_CIVILIAN 109 // Cannot be used +//PC_SPY 110 +//PC_ENGINEER 111 + +// Help impulses +#define TF_DISPLAYLOCATION 118 +#define TF_STATUS_QUERY 119 + +#define TF_HELP_MAP 131 + +// Information impulses +#define TF_INVENTORY 135 +#define TF_SHOWTF 136 +#define TF_SHOWLEGALCLASSES 137 + +// Team Impulses +#define TF_TEAM_1 140 // Join Team 1 +#define TF_TEAM_2 141 // Join Team 2 +#define TF_TEAM_3 142 // Join Team 3 +#define TF_TEAM_4 143 // Join Team 4 +#define TF_TEAM_CLASSES 144 // Impulse to display team classes +#define TF_TEAM_SCORES 145 // Impulse to display team scores +#define TF_TEAM_LIST 146 // Impulse to display the players in each team. + +// Grenade Impulses +#define TF_GRENADE_1 150 // Prime grenade type 1 +#define TF_GRENADE_2 151 // Prime grenade type 2 +#define TF_GRENADE_T 152 // Throw primed grenade + +// Impulses for new items +//#define TF_SCAN 159 // Scanner Pre-Impulse +#define TF_AUTO_SCAN 159 // Scanner On/Off +#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies +#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies +//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) +#define TF_SCAN_SOUND 162 // Scanner sounds on/off +#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) +#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) +#define TF_DETPACK_5 165 // Detpack set to 5 seconds +#define TF_DETPACK_20 166 // Detpack set to 20 seconds +#define TF_DETPACK_50 167 // Detpack set to 50 seconds +#define TF_DETPACK 168 // Detpack Pre-Impulse +#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack +#define TF_PB_DETONATE 170 // Detonate Pipebombs + +// Special skill +#define TF_SPECIAL_SKILL 171 + +// Ammo Drop impulse +#define TF_DROP_AMMO 172 + +// Reload impulse +#define TF_RELOAD 173 + +// auto-zoom toggle +#define TF_AUTOZOOM 174 + +// drop/pass commands +#define TF_DROPKEY 175 + +// Select Medikit +#define TF_MEDIKIT 176 + +// Spy Impulses +#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color +#define TF_SPY_DIE 178 // Feign Death + +// Engineer Impulses +#define TF_ENGINEER_BUILD 179 +#define TF_ENGINEER_SANDBAG 180 + +// Medic +#define TF_MEDIC_HELPME 181 + +// Status bar +#define TF_STATUSBAR_ON 182 +#define TF_STATUSBAR_OFF 183 + +// Discard impulse +#define TF_DISCARD 184 + +// ID Player impulse +#define TF_ID 185 + +// Clan Battle impulses +#define TF_SHOWIDS 186 + +// More Engineer Impulses +#define TF_ENGINEER_DETDISP 187 +#define TF_ENGINEER_DETSENT 188 + +// Admin Commands +#define TF_ADMIN_DEAL_CYCLE 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 + +// Drop Goal Items +#define TF_DROPGOALITEMS 194 + +// More Admin Commands +#define TF_ADMIN_NEXT 195 + +// More Engineer Impulses +#define TF_ENGINEER_DETEXIT 196 +#define TF_ENGINEER_DETENTRANCE 197 + +// Yet MORE Admin Commands +#define TF_ADMIN_LISTIPS 198 + +// Silent Spy Feign +#define TF_SPY_SILENTDIE 199 + + +/*==================================================*/ +/* Defines for the ENGINEER's Building ability */ +/*==================================================*/ +// Ammo costs +#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell +#define AMMO_COST_NAILS 1 +#define AMMO_COST_ROCKETS 2 +#define AMMO_COST_CELLS 2 + +// Building types +#define BUILD_DISPENSER 1 +#define BUILD_SENTRYGUN 2 +#define BUILD_MORTAR 3 +#define BUILD_TELEPORTER_ENTRANCE 4 +#define BUILD_TELEPORTER_EXIT 5 + +// Building metal costs +#define BUILD_COST_DISPENSER 100 // Metal needed to built +#define BUILD_COST_SENTRYGUN 130 +#define BUILD_COST_MORTAR 150 +#define BUILD_COST_TELEPORTER 125 + +#define BUILD_COST_SANDBAG 20 // Built with a separate alias + +// Building times +#define BUILD_TIME_DISPENSER 2 // seconds to build +#define BUILD_TIME_SENTRYGUN 5 +#define BUILD_TIME_MORTAR 5 +#define BUILD_TIME_TELEPORTER 4 + +// Building health levels +#define BUILD_HEALTH_DISPENSER 150 // Health of the building +#define BUILD_HEALTH_SENTRYGUN 150 +#define BUILD_HEALTH_MORTAR 200 +#define BUILD_HEALTH_TELEPORTER 80 + +// Dispenser's maximum carrying capability +#define BUILD_DISPENSER_MAX_SHELLS 400 +#define BUILD_DISPENSER_MAX_NAILS 600 +#define BUILD_DISPENSER_MAX_ROCKETS 300 +#define BUILD_DISPENSER_MAX_CELLS 400 +#define BUILD_DISPENSER_MAX_ARMOR 500 + +// Build state sent down to client +#define BS_BUILDING (1<<0) +#define BS_HAS_DISPENSER (1<<1) +#define BS_HAS_SENTRYGUN (1<<2) +#define BS_CANB_DISPENSER (1<<3) +#define BS_CANB_SENTRYGUN (1<<4) +/*==================================================*/ +/* Ammo quantities for dropping & dispenser use */ +/*==================================================*/ +#define DROP_SHELLS 20 +#define DROP_NAILS 20 +#define DROP_ROCKETS 10 +#define DROP_CELLS 10 +#define DROP_ARMOR 40 + +/*==================================================*/ +/* Team Defines */ +/*==================================================*/ +#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. + // A new global to hold new team colors is needed, and more flags + // in the spawnpoint spawnflags may need to be used. + // Basically, don't change this unless you know what you're doing :) + +/*==================================================*/ +/* New Weapon Defines */ +/*==================================================*/ +#define WEAP_HOOK 1 +#define WEAP_BIOWEAPON 2 +#define WEAP_MEDIKIT 4 +#define WEAP_SPANNER 8 +#define WEAP_AXE 16 +#define WEAP_SNIPER_RIFLE 32 +#define WEAP_AUTO_RIFLE 64 +#define WEAP_SHOTGUN 128 +#define WEAP_SUPER_SHOTGUN 256 +#define WEAP_NAILGUN 512 +#define WEAP_SUPER_NAILGUN 1024 +#define WEAP_GRENADE_LAUNCHER 2048 +#define WEAP_FLAMETHROWER 4096 +#define WEAP_ROCKET_LAUNCHER 8192 +#define WEAP_INCENDIARY 16384 +#define WEAP_ASSAULT_CANNON 32768 +#define WEAP_LIGHTNING 65536 +#define WEAP_DETPACK 131072 +#define WEAP_TRANQ 262144 +#define WEAP_LASER 524288 +// still room for 12 more weapons +// but we can remove some by giving the weapons +// a weapon mode (like the rifle) + +// HL-compatible weapon numbers +#define WEAPON_HOOK 1 +#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) +#define WEAPON_MEDIKIT (WEAPON_HOOK+2) +#define WEAPON_SPANNER (WEAPON_HOOK+3) +#define WEAPON_AXE (WEAPON_HOOK+4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) +#define WEAPON_NAILGUN (WEAPON_HOOK+9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) +#define WEAPON_INCENDIARY (WEAPON_HOOK+14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) +#define WEAPON_LIGHTNING (WEAPON_HOOK+17) +#define WEAPON_DETPACK (WEAPON_HOOK+18) +#define WEAPON_TRANQ (WEAPON_HOOK+19) +#define WEAPON_LASER (WEAPON_HOOK+20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) +#define WEAPON_KNIFE (WEAPON_HOOK+22) +#define WEAPON_BENCHMARK (WEAPON_HOOK+23) + +/*==================================================*/ +/* New Weapon Related Defines */ +/*==================================================*/ +// shots per reload +#define RE_SHOTGUN 8 +#define RE_SUPER_SHOTGUN 16 // 8 shots +#define RE_GRENADE_LAUNCHER 6 +#define RE_ROCKET_LAUNCHER 4 + +// reload times +#define RE_SHOTGUN_TIME 2 +#define RE_SUPER_SHOTGUN_TIME 3 +#define RE_GRENADE_LAUNCHER_TIME 4 +#define RE_ROCKET_LAUNCHER_TIME 5 + +// Maximum velocity you can move and fire the Sniper Rifle +#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 + +// Medikit +#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit +#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense + +// Spanner +#define WEAP_SPANNER_REPAIR 10 + +// Detpack +#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack +#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack +#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering +#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into + +// Tranquiliser Gun +#define TRANQ_TIME 15 + +// Grenades +#define GR_PRIMETIME 3 +#define GR_CALTROP_PRIME 0.5 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 +#define GR_TYPE_CALTROP 9 +//#define GR_TYPE_FLASH 10 + +// Defines for WeaponMode +#define GL_NORMAL 0 +#define GL_PIPEBOMB 1 + +// Defines for OLD Concussion Grenade +#define GR_OLD_CONCUSS_TIME 5 +#define GR_OLD_CONCUSS_DEC 20 + +// Defines for Concussion Grenade +#define GR_CONCUSS_TIME 0.25 +#define GR_CONCUSS_DEC 10 +#define MEDIUM_PING 150 +#define HIGH_PING 200 + +// Defines for the Gas Grenade +#define GR_HALLU_TIME 0.3 +#define GR_OLD_HALLU_TIME 0.5 +#define GR_HALLU_DEC 2.5 + +// Defines for the BioInfection +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players + +/*==================================================*/ +/* New Items */ +/*==================================================*/ +#define NIT_SCANNER 1 + +#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 +#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 + +/*==================================================*/ +/* New Item Flags */ +/*==================================================*/ +#define NIT_SCANNER_ENEMY 1 // Detect enemies +#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) +#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. + +/*==================================================*/ +/* New Item Related Defines */ +/*==================================================*/ +#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner + // is multiplied by this to get the scanrange. +#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan +#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected + // by scanners that only detect movement + +/*==================================================*/ +/* Variables used for New Weapons and Reloading */ +/*==================================================*/ +// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. +#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% +#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% +#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% +#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% +#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% + +/*==========================================================================*/ +/* TEAMFORTRESS CLASS DETAILS */ +/*==========================================================================*/ +// Class Details for SCOUT +#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. +#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed +#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed +#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption +#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned +#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class +#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned +#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN +#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry +#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry +#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry +#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry +#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned +#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned +#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned +#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has + +#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range +#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse +#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range +#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan + +// Class Details for SNIPER +#define PC_SNIPER_SKIN 5 +#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXSPEED 300 +#define PC_SNIPER_MAXSTRAFESPEED 300 +#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_INITARMOR 0 +#define PC_SNIPER_MAXARMORTYPE 0.3 +#define PC_SNIPER_INITARMORTYPE 0.3 +#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL +#define PC_SNIPER_INITARMORCLASS 0 +#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN +#define PC_SNIPER_MAXAMMO_SHOT 75 +#define PC_SNIPER_MAXAMMO_NAIL 100 +#define PC_SNIPER_MAXAMMO_CELL 50 +#define PC_SNIPER_MAXAMMO_ROCKET 25 +#define PC_SNIPER_INITAMMO_SHOT 60 +#define PC_SNIPER_INITAMMO_NAIL 50 +#define PC_SNIPER_INITAMMO_CELL 0 +#define PC_SNIPER_INITAMMO_ROCKET 0 +#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE +#define PC_SNIPER_GRENADE_INIT_1 2 +#define PC_SNIPER_GRENADE_INIT_2 0 +#define PC_SNIPER_TF_ITEMS 0 + +// Class Details for SOLDIER +#define PC_SOLDIER_SKIN 6 +#define PC_SOLDIER_MAXHEALTH 100 +#define PC_SOLDIER_MAXSPEED 240 +#define PC_SOLDIER_MAXSTRAFESPEED 240 +#define PC_SOLDIER_MAXARMOR 200 +#define PC_SOLDIER_INITARMOR 100 +#define PC_SOLDIER_MAXARMORTYPE 0.8 +#define PC_SOLDIER_INITARMORTYPE 0.8 +#define PC_SOLDIER_ARMORCLASSES 31 // ALL +#define PC_SOLDIER_INITARMORCLASS 0 +#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER +#define PC_SOLDIER_MAXAMMO_SHOT 100 +#define PC_SOLDIER_MAXAMMO_NAIL 100 +#define PC_SOLDIER_MAXAMMO_CELL 50 +#define PC_SOLDIER_MAXAMMO_ROCKET 50 +#define PC_SOLDIER_INITAMMO_SHOT 50 +#define PC_SOLDIER_INITAMMO_NAIL 0 +#define PC_SOLDIER_INITAMMO_CELL 0 +#define PC_SOLDIER_INITAMMO_ROCKET 10 +#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +#define PC_SOLDIER_GRENADE_INIT_1 2 +#define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_TF_ITEMS 0 + +#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active +#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active +#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active +#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's +#define MAX_CONCUSSION_GRENS 3 +#define MAX_CALTROP_CANS 3 + +// Class Details for DEMOLITION MAN +#define PC_DEMOMAN_SKIN 1 +#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXSPEED 280 +#define PC_DEMOMAN_MAXSTRAFESPEED 280 +#define PC_DEMOMAN_MAXARMOR 120 +#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMORTYPE 0.6 +#define PC_DEMOMAN_INITARMORTYPE 0.6 +#define PC_DEMOMAN_ARMORCLASSES 31 // ALL +#define PC_DEMOMAN_INITARMORCLASS 0 +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_MAXAMMO_SHOT 75 +#define PC_DEMOMAN_MAXAMMO_NAIL 50 +#define PC_DEMOMAN_MAXAMMO_CELL 50 +#define PC_DEMOMAN_MAXAMMO_ROCKET 50 +#define PC_DEMOMAN_MAXAMMO_DETPACK 1 +#define PC_DEMOMAN_INITAMMO_SHOT 30 +#define PC_DEMOMAN_INITAMMO_NAIL 0 +#define PC_DEMOMAN_INITAMMO_CELL 0 +#define PC_DEMOMAN_INITAMMO_ROCKET 20 +#define PC_DEMOMAN_INITAMMO_DETPACK 1 +#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_INIT_1 2 +#define PC_DEMOMAN_GRENADE_INIT_2 2 +#define PC_DEMOMAN_TF_ITEMS 0 + +// Class Details for COMBAT MEDIC +#define PC_MEDIC_SKIN 3 +#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXARMOR 100 +#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMORTYPE 0.6 +#define PC_MEDIC_INITARMORTYPE 0.3 +#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION +#define PC_MEDIC_INITARMORCLASS 0 +#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN +#define PC_MEDIC_MAXAMMO_SHOT 75 +#define PC_MEDIC_MAXAMMO_NAIL 150 +#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_ROCKET 25 +#define PC_MEDIC_MAXAMMO_MEDIKIT 100 +#define PC_MEDIC_INITAMMO_SHOT 50 +#define PC_MEDIC_INITAMMO_NAIL 50 +#define PC_MEDIC_INITAMMO_CELL 0 +#define PC_MEDIC_INITAMMO_ROCKET 0 +#define PC_MEDIC_INITAMMO_MEDIKIT 50 +#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_INIT_1 2 +#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_TF_ITEMS 0 +#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. +#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. + +// Class Details for HVYWEAP +#define PC_HVYWEAP_SKIN 2 +#define PC_HVYWEAP_MAXHEALTH 100 +#define PC_HVYWEAP_MAXSPEED 230 +#define PC_HVYWEAP_MAXSTRAFESPEED 230 +#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_INITARMOR 150 +#define PC_HVYWEAP_MAXARMORTYPE 0.8 +#define PC_HVYWEAP_INITARMORTYPE 0.8 +#define PC_HVYWEAP_ARMORCLASSES 31 // ALL +#define PC_HVYWEAP_INITARMORCLASS 0 +#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN +#define PC_HVYWEAP_MAXAMMO_SHOT 200 +#define PC_HVYWEAP_MAXAMMO_NAIL 200 +#define PC_HVYWEAP_MAXAMMO_CELL 50 +#define PC_HVYWEAP_MAXAMMO_ROCKET 25 +#define PC_HVYWEAP_INITAMMO_SHOT 200 +#define PC_HVYWEAP_INITAMMO_NAIL 0 +#define PC_HVYWEAP_INITAMMO_CELL 30 +#define PC_HVYWEAP_INITAMMO_ROCKET 0 +#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_INIT_1 2 +#define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon + + + +// Class Details for PYRO +#define PC_PYRO_SKIN 21 +#define PC_PYRO_MAXHEALTH 100 +#define PC_PYRO_MAXSPEED 300 +#define PC_PYRO_MAXSTRAFESPEED 300 +#define PC_PYRO_MAXARMOR 150 +#define PC_PYRO_INITARMOR 50 +#define PC_PYRO_MAXARMORTYPE 0.6 +#define PC_PYRO_INITARMORTYPE 0.6 +#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE +#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN +#define PC_PYRO_MAXAMMO_SHOT 40 +#define PC_PYRO_MAXAMMO_NAIL 50 +#define PC_PYRO_MAXAMMO_CELL 200 +#define PC_PYRO_MAXAMMO_ROCKET 20 +#define PC_PYRO_INITAMMO_SHOT 20 +#define PC_PYRO_INITAMMO_NAIL 0 +#define PC_PYRO_INITAMMO_CELL 120 +#define PC_PYRO_INITAMMO_ROCKET 5 +#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_INIT_1 2 +#define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot + +// Class Details for SPY +#define PC_SPY_SKIN 22 +#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXSPEED 300 +#define PC_SPY_MAXSTRAFESPEED 300 +#define PC_SPY_MAXARMOR 100 +#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_SPY_INITARMORCLASS 0 +#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_MAXAMMO_SHOT 40 +#define PC_SPY_MAXAMMO_NAIL 100 +#define PC_SPY_MAXAMMO_CELL 30 +#define PC_SPY_MAXAMMO_ROCKET 15 +#define PC_SPY_INITAMMO_SHOT 40 +#define PC_SPY_INITAMMO_NAIL 50 +#define PC_SPY_INITAMMO_CELL 10 +#define PC_SPY_INITAMMO_ROCKET 0 +#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_INIT_1 2 +#define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_TF_ITEMS 0 +#define PC_SPY_CELL_REGEN_TIME 5 +#define PC_SPY_CELL_REGEN_AMOUNT 1 +#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible +#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover + +// Class Details for ENGINEER +#define PC_ENGINEER_SKIN 22 // Not used anymore +#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXSPEED 300 +#define PC_ENGINEER_MAXSTRAFESPEED 300 +#define PC_ENGINEER_MAXARMOR 50 +#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMORTYPE 0.6 +#define PC_ENGINEER_INITARMORTYPE 0.3 +#define PC_ENGINEER_ARMORCLASSES 31 // ALL +#define PC_ENGINEER_INITARMORCLASS 0 +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_MAXAMMO_SHOT 50 +#define PC_ENGINEER_MAXAMMO_NAIL 50 +#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal +#define PC_ENGINEER_MAXAMMO_ROCKET 30 +#define PC_ENGINEER_INITAMMO_SHOT 20 +#define PC_ENGINEER_INITAMMO_NAIL 25 +#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal +#define PC_ENGINEER_INITAMMO_ROCKET 0 +#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_INIT_1 2 +#define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_TF_ITEMS 0 + +// Class Details for CIVILIAN +#define PC_CIVILIAN_SKIN 22 +#define PC_CIVILIAN_MAXHEALTH 50 +#define PC_CIVILIAN_MAXSPEED 240 +#define PC_CIVILIAN_MAXSTRAFESPEED 240 +#define PC_CIVILIAN_MAXARMOR 0 +#define PC_CIVILIAN_INITARMOR 0 +#define PC_CIVILIAN_MAXARMORTYPE 0 +#define PC_CIVILIAN_INITARMORTYPE 0 +#define PC_CIVILIAN_ARMORCLASSES 0 +#define PC_CIVILIAN_INITARMORCLASS 0 +#define PC_CIVILIAN_WEAPONS WEAP_AXE +#define PC_CIVILIAN_MAXAMMO_SHOT 0 +#define PC_CIVILIAN_MAXAMMO_NAIL 0 +#define PC_CIVILIAN_MAXAMMO_CELL 0 +#define PC_CIVILIAN_MAXAMMO_ROCKET 0 +#define PC_CIVILIAN_INITAMMO_SHOT 0 +#define PC_CIVILIAN_INITAMMO_NAIL 0 +#define PC_CIVILIAN_INITAMMO_CELL 0 +#define PC_CIVILIAN_INITAMMO_ROCKET 0 +#define PC_CIVILIAN_GRENADE_TYPE_1 0 +#define PC_CIVILIAN_GRENADE_TYPE_2 0 +#define PC_CIVILIAN_GRENADE_INIT_1 0 +#define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_TF_ITEMS 0 + + +/*==========================================================================*/ +/* TEAMFORTRESS GOALS */ +/*==========================================================================*/ +// For all these defines, see the tfortmap.txt that came with the zip +// for complete descriptions. +// Defines for Goal Activation types : goal_activation (in goals) +#define TFGA_TOUCH 1 // Activated when touched +#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion +#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met +#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner +#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning + +// Defines for Goal Effects types : goal_effect +#define TFGE_AP 1 // AP is affected. Default. +#define TFGE_AP_TEAM 2 // All of the AP's team. +#define TFGE_NOT_AP_TEAM 4 // All except AP's team. +#define TFGE_NOT_AP 8 // All except AP. +#define TFGE_WALL 16 // If set, walls stop the Radius effects +#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected +#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects + +// Defines for Goal Result types : goal_result +#define TFGR_SINGLE 1 // Goal can only be activated once +#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses +#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level +#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results +#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy +#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point +#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys + +// Defines for Goal Group Result types : goal_group +// None! +// But I'm leaving this variable in there, since it's fairly likely +// that some will show up sometime. + +// Defines for Goal Item types, : goal_activation (in items) +#define TFGI_GLOW 1 // Players carrying this GoalItem will glow +#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed +#define TFGI_DROP 4 // Players dying with this item will drop it +#define TFGI_RETURN_DROP 8 // Return if a player with it dies +#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation +#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE +#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details +#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped +#define TFGI_KEEP 256 // Players keep this item even when they die +#define TFGI_ITEMGLOWS 512 // Item glows when on the ground +#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning +#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players +#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc + +// Defines for methods of GoalItem returning +#define GI_RET_DROP_DEAD 0 // Dropped by a dead player +#define GI_RET_DROP_LIVING 1 // Dropped by a living player +#define GI_RET_GOAL 2 // Returned by a Goal +#define GI_RET_TIME 3 // Returned due to timeout + +// Defines for TeamSpawnpoints : goal_activation (in teamspawns) +#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times +#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times + +// Defines for TeamSpawnpoints : goal_effects (in teamspawns) +#define TFSP_REMOVESELF 1 // Remove itself after being spawned on + +// Defines for Goal States +#define TFGS_ACTIVE 1 +#define TFGS_INACTIVE 2 +#define TFGS_REMOVED 3 +#define TFGS_DELAYED 4 + +// Defines for GoalItem Removing from Player Methods +#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player +#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal +#define GI_DROP_PLAYERDROP 2 // Dropped by a player + +// Legal Playerclass Handling +#define TF_ILL_SCOUT 1 +#define TF_ILL_SNIPER 2 +#define TF_ILL_SOLDIER 4 +#define TF_ILL_DEMOMAN 8 +#define TF_ILL_MEDIC 16 +#define TF_ILL_HVYWEP 32 +#define TF_ILL_PYRO 64 +#define TF_ILL_RANDOMPC 128 +#define TF_ILL_SPY 256 +#define TF_ILL_ENGINEER 512 + +// Addition classes +#define CLASS_TFGOAL 128 +#define CLASS_TFGOAL_TIMER 129 +#define CLASS_TFGOAL_ITEM 130 +#define CLASS_TFSPAWN 131 + +/*==========================================================================*/ +/* Flamethrower */ +/*==========================================================================*/ +#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player +#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) +#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade +#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player +#define FLAME_NUMLIGHTS 1 // maximum number of light flame +#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' +#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode +#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames +#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. +#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn +#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players + +/*==================================================*/ +/* CTF Support defines */ +/*==================================================*/ +#define CTF_FLAG1 1 +#define CTF_FLAG2 2 +#define CTF_DROPOFF1 3 +#define CTF_DROPOFF2 4 +#define CTF_SCORE1 5 +#define CTF_SCORE2 6 + +//.float hook_out; + +/*==================================================*/ +/* Camera defines */ +/*==================================================*/ +/* +float live_camera; +.float camdist; +.vector camangle; +.entity camera_list; +*/ + +/*==================================================*/ +/* QuakeWorld defines */ +/*==================================================*/ +/* +float already_chosen_map; + +// grappling hook variables +.entity hook; +.float on_hook; +.float fire_held_down;// flag - TRUE if player is still holding down the + // fire button after throwing a hook. +*/ +/*==================================================*/ +/* Server Settings */ +/*==================================================*/ +// Admin modes +#define ADMIN_MODE_NONE 0 +#define ADMIN_MODE_DEAL 1 + +/*==================================================*/ +/* Death Message defines */ +/*==================================================*/ +#define DMSG_SHOTGUN 1 +#define DMSG_SSHOTGUN 2 +#define DMSG_NAILGUN 3 +#define DMSG_SNAILGUN 4 +#define DMSG_GRENADEL 5 +#define DMSG_ROCKETL 6 +#define DMSG_LIGHTNING 7 +#define DMSG_GREN_HAND 8 +#define DMSG_GREN_NAIL 9 +#define DMSG_GREN_MIRV 10 +#define DMSG_GREN_PIPE 11 +#define DMSG_DETPACK 12 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 +#define DMSG_FLAME 15 +#define DMSG_DETPACK_DIS 16 +#define DMSG_AXE 17 +#define DMSG_SNIPERRIFLE 18 +#define DMSG_AUTORIFLE 19 +#define DMSG_ASSAULTCANNON 20 +#define DMSG_HOOK 21 +#define DMSG_BACKSTAB 22 +#define DMSG_MEDIKIT 23 +#define DMSG_GREN_GAS 24 +#define DMSG_TRANQ 25 +#define DMSG_LASERBOLT 26 +#define DMSG_SENTRYGUN_BULLET 27 +#define DMSG_SNIPERLEGSHOT 28 +#define DMSG_SNIPERHEADSHOT 29 +#define DMSG_GREN_EMP 30 +#define DMSG_GREN_EMP_AMMO 31 +#define DMSG_SPANNER 32 +#define DMSG_INCENDIARY 33 +#define DMSG_SENTRYGUN_ROCKET 34 +#define DMSG_GREN_FLASH 35 +#define DMSG_TRIGGER 36 +#define DMSG_MIRROR 37 +#define DMSG_SENTRYDEATH 38 +#define DMSG_DISPENSERDEATH 39 +#define DMSG_GREN_AIRPIPE 40 +#define DMSG_CALTROP 41 + +/*==================================================*/ +// TOGGLEFLAGS +/*==================================================*/ +// Some of the toggleflags aren't used anymore, but the bits are still +// there to provide compatability with old maps +#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit +#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit +#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit +//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE +#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade +#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE +#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE +#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. +#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore +#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set + // In a map. Cannot be toggled by players. +#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only +#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off +//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags +#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps +#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation + +#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only + +/*======================*/ +// Menu stuff // +/*======================*/ + +#define MENU_DEFAULT 1 +#define MENU_TEAM 2 +#define MENU_CLASS 3 +#define MENU_MAPBRIEFING 4 +#define MENU_INTRO 5 +#define MENU_CLASSHELP 6 +#define MENU_CLASSHELP2 7 +#define MENU_REPEATHELP 8 + +#define MENU_SPECHELP 9 + + +#define MENU_SPY 12 +#define MENU_SPY_SKIN 13 +#define MENU_SPY_COLOR 14 +#define MENU_ENGINEER 15 +#define MENU_ENGINEER_FIX_DISPENSER 16 +#define MENU_ENGINEER_FIX_SENTRYGUN 17 +#define MENU_ENGINEER_FIX_MORTAR 18 +#define MENU_DISPENSER 19 +#define MENU_CLASS_CHANGE 20 +#define MENU_TEAM_CHANGE 21 + +#define MENU_REFRESH_RATE 25 + +#define MENU_VOICETWEAK 50 + +//============================ +// Timer Types +#define TF_TIMER_ANY 0 +#define TF_TIMER_CONCUSSION 1 +#define TF_TIMER_INFECTION 2 +#define TF_TIMER_HALLUCINATION 3 +#define TF_TIMER_TRANQUILISATION 4 +#define TF_TIMER_ROTHEALTH 5 +#define TF_TIMER_REGENERATION 6 +#define TF_TIMER_GRENPRIME 7 +#define TF_TIMER_CELLREGENERATION 8 +#define TF_TIMER_DETPACKSET 9 +#define TF_TIMER_DETPACKDISARM 10 +#define TF_TIMER_BUILD 11 +#define TF_TIMER_CHECKBUILDDISTANCE 12 +#define TF_TIMER_DISGUISE 13 +#define TF_TIMER_DISPENSERREFILL 14 + +// Non Player timers +#define TF_TIMER_RETURNITEM 100 +#define TF_TIMER_DELAYEDGOAL 101 +#define TF_TIMER_ENDROUND 102 + +//============================ +// Teamscore printing +#define TS_PRINT_SHORT 1 +#define TS_PRINT_LONG 2 +#define TS_PRINT_LONG_TO_ALL 3 + +#ifndef TF_DEFS_ONLY + +typedef struct +{ + int topColor; + int bottomColor; +} team_color_t; + + +/*==================================================*/ +/* GLOBAL VARIABLES */ +/*==================================================*/ +// FortressMap stuff +extern float number_of_teams; // number of teams supported by the map +extern int illegalclasses[5]; // Illegal playerclasses for all teams +extern int civilianteams; // Bitfield holding Civilian teams +extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams + +extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams + +extern int teamscores[5]; // Goal Score of each team +extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers +extern int teamfrags[5]; // Total Frags for each team +extern int teamlives[5]; // Number of lives each team's players have +extern int teammaxplayers[5]; // Max number of players allowed in each team +extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set + // stores the damage ratio players take/give +extern int teamallies[5]; // Keeps track of which teams are allied +extern string_t team_names[5]; + +extern BOOL CTF_Map; +extern BOOL birthday; +extern BOOL christmas; + +extern float num_world_flames; + +// Clan Battle stuff +extern float clan_scores_dumped; +extern float cb_prematch_time; +extern float fOldPrematch; +extern float fOldCeaseFire; +extern float cb_ceasefire_time; +extern float last_id; +extern float spy_off; +extern float old_grens; +extern float flagem_checked; +extern float flNextEqualisationCalc; +extern BOOL cease_fire; +extern BOOL no_cease_fire_text; +extern BOOL initial_cease_fire; +extern BOOL last_cease_fire; +// Autokick stuff +extern float autokick_kills; + +extern float deathmsg; // Global, which is set before every T_Damage, to indicate + // the death message that should be used. + +extern char *sTeamSpawnNames[]; +extern char *sClassNames[]; +extern char *sNewClassModelFiles[]; +extern char *sOldClassModelFiles[]; +extern char *sClassModels[]; +extern char *sClassCfgs[]; +extern char *sGrenadeNames[]; +extern string_t team_menu_string; + +extern int toggleflags; // toggleable flags + +extern CBaseEntity* g_pLastSpawns[5]; +extern BOOL g_bFirstClient; + +extern float g_fNextPrematchAlert; + +typedef struct +{ + int ip; + edict_t *pEdict; +} ip_storage_t; + +extern ip_storage_t g_IpStorage[32]; + +class CGhost; +/*==========================================================================*/ +BOOL ClassIsRestricted(float tno, int pc); +char* GetTeamName(int tno); +int TeamFortress_GetNoPlayers(); +void DestroyBuilding(CBaseEntity *eng, char *bld); +void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); +float anglemod( float v ); + +// Team Funcs +BOOL TeamFortress_TeamIsCivilian(float tno); +void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); +BOOL TeamFortress_TeamPutPlayerInTeam(); +void TeamFortress_TeamSetColor(int tno); +void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); +int TeamFortress_TeamGetScoreFrags(int tno); +int TeamFortress_TeamGetNoPlayers(int tno); +float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); +BOOL IsSpawnPointValid( Vector &pos ); +BOOL TeamFortress_SortTeams( void ); +void DumpClanScores( void ); +void CalculateTeamEqualiser(); + +// mapscript funcs +void ParseTFServerSettings(); +void ParseTFMapSettings(); +CBaseEntity* Finditem(int ino); +CBaseEntity* Findgoal(int gno); +CBaseEntity* Findteamspawn(int gno); +void RemoveGoal(CBaseEntity *Goal); +void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); +void dremove( CBaseEntity *te ); +void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); +void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); +void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); +void tfgoalitem_checkgoalreturn(CBaseEntity *Item); +void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); +void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); +void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); +// hooks into the mapscript for all entities +BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); +BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); + +// prematch & ceasefire +void Display_Prematch(); +void Check_Ceasefire(); + +// admin +void KickPlayer( CBaseEntity *pTarget ); +void BanPlayer( CBaseEntity *pTarget ); +CGhost *FindGhost( int iGhostID ); +int GetBattleID( edict_t *pEntity ); + +extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) +extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. +extern cvar_t tfc_spam_limit; // at this many points, gag the spammer +extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; +extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; +extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; +extern cvar_t allow_spectators; + +/*==========================================================================*/ +class CTFFlame : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT FlameThink( void ); + static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); + void FlameDestroy( void ); + + float m_flNextDamageTime; +}; + +/*==========================================================================*/ +// MAPSCRIPT CLASSES +class CTFGoal : public CBaseAnimating +{ +public: + void Spawn( void ); + void StartGoal( void ); + void EXPORT PlaceGoal( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int Classify ( void ) { return CLASS_TFGOAL; } + + void SetObjectCollisionBox( void ); +}; + +class CTFGoalItem : public CTFGoal +{ +public: + void Spawn( void ); + void StartItem( void ); + void EXPORT PlaceItem( void ); + int Classify ( void ) { return CLASS_TFGOAL_ITEM; } + + float m_flDroppedAt; +}; + +class CTFTimerGoal : public CTFGoal +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL_TIMER; } +}; + +class CTFSpawn : public CBaseEntity +{ +public: + void Spawn( void ); + void Activate( void ); + int Classify ( void ) { return CLASS_TFSPAWN; } + BOOL CheckTeam( int iTeamNo ); + + EHANDLE m_pTeamCheck; +}; + +class CTFDetect : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL; } +}; + +class CTelefragDeath : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT DeathTouch( CBaseEntity *pOther ); +}; + +class CTeamCheck : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + BOOL TeamMatches( int iTeam ); +}; + +class CTeamSet : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +#endif // TF_DEFS_ONLY +#endif // __TF_DEFS_H + + diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp index d16a1046..0286c689 100644 --- a/cl_dll/train.cpp +++ b/cl_dll/train.cpp @@ -1,85 +1,85 @@ -/*** -* -* 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. -* -****/ -// -// Train.cpp -// -// implementation of CHudAmmo class -// - -#include "hud.h" -#include "cl_util.h" -#include -#include -#include "parsemsg.h" - -DECLARE_MESSAGE(m_Train, Train ) - - -int CHudTrain::Init(void) -{ - HOOK_MESSAGE( Train ); - - m_iPos = 0; - m_iFlags = 0; - gHUD.AddHudElem(this); - - return 1; -}; - -int CHudTrain::VidInit(void) -{ - m_hSprite = 0; - - return 1; -}; - -int CHudTrain::Draw(float fTime) -{ - if ( !m_hSprite ) - m_hSprite = LoadSprite("sprites/%d_train.spr"); - - if (m_iPos) - { - int r, g, b, x, y; - - UnpackRGB(r,g,b, RGB_YELLOWISH); - SPR_Set(m_hSprite, r, g, b ); - - // This should show up to the right and part way up the armor number - y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; - x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4; - - SPR_DrawAdditive( m_iPos - 1, x, y, NULL); - - } - - return 1; -} - - -int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - // update Train data - m_iPos = READ_BYTE(); - - if (m_iPos) - m_iFlags |= HUD_ACTIVE; - else - m_iFlags &= ~HUD_ACTIVE; - - return 1; -} +/*** +* +* 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. +* +****/ +// +// Train.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Train, Train ) + + +int CHudTrain::Init(void) +{ + HOOK_MESSAGE( Train ); + + m_iPos = 0; + m_iFlags = 0; + gHUD.AddHudElem(this); + + return 1; +}; + +int CHudTrain::VidInit(void) +{ + m_hSprite = 0; + + return 1; +}; + +int CHudTrain::Draw(float fTime) +{ + if ( !m_hSprite ) + m_hSprite = LoadSprite("sprites/%d_train.spr"); + + if (m_iPos) + { + int r, g, b, x, y; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + SPR_Set(m_hSprite, r, g, b ); + + // This should show up to the right and part way up the armor number + y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; + x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4; + + SPR_DrawAdditive( m_iPos - 1, x, y, NULL); + + } + + return 1; +} + + +int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update Train data + m_iPos = READ_BYTE(); + + if (m_iPos) + m_iFlags |= HUD_ACTIVE; + else + m_iFlags &= ~HUD_ACTIVE; + + return 1; +} diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp index ef37c7a4..18dbc6b7 100644 --- a/cl_dll/tri.cpp +++ b/cl_dll/tri.cpp @@ -1,122 +1,122 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// Triangle rendering, if any - -#include "hud.h" -#include "cl_util.h" - -// Triangle rendering apis are in gEngfuncs.pTriAPI - -#include "const.h" -#include "entity_state.h" -#include "cl_entity.h" -#include "triangleapi.h" - -extern "C" -{ - void DLLEXPORT HUD_DrawNormalTriangles( void ); - void DLLEXPORT HUD_DrawTransparentTriangles( void ); -}; - -//#define TEST_IT -#if defined( TEST_IT ) - -/* -================= -Draw_Triangles - -Example routine. Draws a sprite offset from the player origin. -================= -*/ -void Draw_Triangles( void ) -{ - cl_entity_t *player; - vec3_t org; - - // Load it up with some bogus data - player = gEngfuncs.GetLocalPlayer(); - if ( !player ) - return; - - org = player->origin; - - org.x += 50; - org.y += 50; - - if (gHUD.m_hsprCursor == 0) - { - char sz[256]; - sprintf( sz, "sprites/cursor.spr" ); - gHUD.m_hsprCursor = SPR_Load( sz ); - } - - if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) - { - return; - } - - // Create a triangle, sigh - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - // Overload p->color with index into tracer palette, p->packedColor with brightness - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - // UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) - gEngfuncs.pTriAPI->Brightness( 1 ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); - - gEngfuncs.pTriAPI->Brightness( 1 ); - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); - - gEngfuncs.pTriAPI->Brightness( 1 ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); - - gEngfuncs.pTriAPI->Brightness( 1 ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); -} - -#endif - -/* -================= -HUD_DrawNormalTriangles - -Non-transparent triangles-- add them here -================= -*/ -void DLLEXPORT HUD_DrawNormalTriangles( void ) -{ - - gHUD.m_Spectator.DrawOverview(); - -#if defined( TEST_IT ) -// Draw_Triangles(); -#endif -} - -/* -================= -HUD_DrawTransparentTriangles - -Render any triangles with transparent rendermode needs here -================= -*/ -void DLLEXPORT HUD_DrawTransparentTriangles( void ) -{ - -#if defined( TEST_IT ) -// Draw_Triangles(); -#endif -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Triangle rendering, if any + +#include "hud.h" +#include "cl_util.h" + +// Triangle rendering apis are in gEngfuncs.pTriAPI + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "triangleapi.h" + +extern "C" +{ + void DLLEXPORT HUD_DrawNormalTriangles( void ); + void DLLEXPORT HUD_DrawTransparentTriangles( void ); +}; + +//#define TEST_IT +#if defined( TEST_IT ) + +/* +================= +Draw_Triangles + +Example routine. Draws a sprite offset from the player origin. +================= +*/ +void Draw_Triangles( void ) +{ + cl_entity_t *player; + vec3_t org; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + org = player->origin; + + org.x += 50; + org.y += 50; + + if (gHUD.m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + gHUD.m_hsprCursor = SPR_Load( sz ); + } + + if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) + { + return; + } + + // Create a triangle, sigh + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + // Overload p->color with index into tracer palette, p->packedColor with brightness + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + // UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); + + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +} + +#endif + +/* +================= +HUD_DrawNormalTriangles + +Non-transparent triangles-- add them here +================= +*/ +void DLLEXPORT HUD_DrawNormalTriangles( void ) +{ + + gHUD.m_Spectator.DrawOverview(); + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} + +/* +================= +HUD_DrawTransparentTriangles + +Render any triangles with transparent rendermode needs here +================= +*/ +void DLLEXPORT HUD_DrawTransparentTriangles( void ) +{ + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp index 69d8871c..14474a9f 100644 --- a/cl_dll/util.cpp +++ b/cl_dll/util.cpp @@ -1,133 +1,133 @@ -/*** -* -* 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 -// -// implementation of class-less helper functions -// - -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -#include "hud.h" -#include "cl_util.h" -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -extern vec3_t vec3_origin; - -double sqrt(double x); - -float Length(const float *v) -{ - int i; - float length; - - length = 0; - for (i=0 ; i< 3 ; i++) - length += v[i]*v[i]; - length = sqrt (length); // FIXME - - return length; -} - -void VectorAngles( const float *forward, float *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; -} - -float VectorNormalize (float *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 ( float *v ) -{ - v[0] = -v[0]; - v[1] = -v[1]; - v[2] = -v[2]; -} - -void VectorScale (const float *in, float scale, float *out) -{ - out[0] = in[0]*scale; - out[1] = in[1]*scale; - out[2] = in[2]*scale; -} - -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) -{ - vecc[0] = veca[0] + scale*vecb[0]; - vecc[1] = veca[1] + scale*vecb[1]; - vecc[2] = veca[2] + scale*vecb[2]; -} - -HSPRITE LoadSprite(const char *pszName) -{ - int i; - char sz[256]; - - if (ScreenWidth < 640) - i = 320; - else - i = 640; - - sprintf(sz, pszName, i); - - return SPR_Load(sz); -} - +/*** +* +* 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 +// +// implementation of class-less helper functions +// + +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +#include "hud.h" +#include "cl_util.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern vec3_t vec3_origin; + +double sqrt(double x); + +float Length(const float *v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +void VectorAngles( const float *forward, float *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; +} + +float VectorNormalize (float *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 ( float *v ) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (const float *in, float scale, float *out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + +HSPRITE LoadSprite(const char *pszName) +{ + int i; + char sz[256]; + + if (ScreenWidth < 640) + i = 320; + else + i = 640; + + sprintf(sz, pszName, i); + + return SPR_Load(sz); +} + diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h index d0c4e9f0..fdac17cc 100644 --- a/cl_dll/util_vector.h +++ b/cl_dll/util_vector.h @@ -1,121 +1,121 @@ -/*** -* -* 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. -* -****/ -// Vector.h -// A subset of the extdll.h in the project HL Entity DLL -// - -// 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 - -//========================================================= -// 2DVector - used for many pathfinding and many other -// operations that are treated as planar rather than 3d. -//========================================================= -class Vector2D -{ -public: - inline Vector2D(void) { } - inline Vector2D(float X, float Y) { 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 (float)sqrt(x*x + y*y ); } - - inline Vector2D Normalize ( void ) const - { - Vector2D vec2; - - float flLen = Length(); - if ( flLen == 0 ) - { - return Vector2D( (float)0, (float)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) { } - inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]) { 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 (float)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 (float)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 ); } - -#define vec3_t Vector +/*** +* +* 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. +* +****/ +// Vector.h +// A subset of the extdll.h in the project HL Entity DLL +// + +// 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 + +//========================================================= +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +//========================================================= +class Vector2D +{ +public: + inline Vector2D(void) { } + inline Vector2D(float X, float Y) { 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 (float)sqrt(x*x + y*y ); } + + inline Vector2D Normalize ( void ) const + { + Vector2D vec2; + + float flLen = Length(); + if ( flLen == 0 ) + { + return Vector2D( (float)0, (float)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) { } + inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { 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 (float)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 (float)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 ); } + +#define vec3_t Vector diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index 5c022148..d0b87c53 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -1,1692 +1,1692 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// view/refresh setup functions - -#include "hud.h" -#include "cl_util.h" -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" - -#include "entity_state.h" -#include "cl_entity.h" -#include "ref_params.h" -#include "in_defs.h" // PITCH YAW ROLL -#include "pm_movevars.h" -#include "pm_shared.h" -#include "pm_defs.h" -#include "event_api.h" -#include "pmtrace.h" -#include "screenfade.h" -#include "shake.h" -#include "hltv.h" - -// Spectator Mode -extern "C" -{ - float vecNewViewAngles[3]; - int iHasNewViewAngles; - float vecNewViewOrigin[3]; - int iHasNewViewOrigin; - int iIsSpectator; -} - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -extern "C" -{ - int CL_IsThirdPerson( void ); - void CL_CameraOffset( float *ofs ); - - void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); - - void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); - int PM_GetVisEntInfo( int ent ); - int PM_GetPhysEntInfo( int ent ); - void InterpolateAngles( float * start, float * end, float * output, float frac ); - void NormalizeAngles( float * angles ); - float Distance(const float * v1, const float * v2); - float AngleBetweenVectors( const float * v1, const float * v2 ); - - float vJumpOrigin[3]; - float vJumpAngles[3]; -} - -void V_DropPunchAngle ( float frametime, float *ev_punchangle ); -void VectorAngles( const float *forward, float *angles ); - -#include "r_studioint.h" -#include "com_model.h" - -extern engine_studio_api_t IEngineStudio; - -/* -The view is allowed to move slightly from it's true position for bobbing, -but if it exceeds 8 pixels linear distance (spherical, not box), the list of -entities sent from the server may not include everything in the pvs, especially -when crossing a water boudnary. -*/ - -extern cvar_t *cl_forwardspeed; -extern cvar_t *chase_active; -extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; -extern cvar_t *cl_vsmoothing; - -#define CAM_MODE_RELAX 1 -#define CAM_MODE_FOCUS 2 - -vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; -float v_frametime, v_lastDistance; -float v_cameraRelaxAngle = 5.0f; -float v_cameraFocusAngle = 35.0f; -int v_cameraMode = CAM_MODE_FOCUS; -qboolean v_resetCamera = 1; - -vec3_t ev_punchangle; - -cvar_t *scr_ofsx; -cvar_t *scr_ofsy; -cvar_t *scr_ofsz; - -cvar_t *v_centermove; -cvar_t *v_centerspeed; - -cvar_t *cl_bobcycle; -cvar_t *cl_bob; -cvar_t *cl_bobup; -cvar_t *cl_waterdist; -cvar_t *cl_chasedist; - -// These cvars are not registered (so users can't cheat), so set the ->value field directly -// Register these cvars in V_Init() if needed for easy tweaking -cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; -cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; -cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; -cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; -cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; -cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; - -float v_idlescale; // used by TFC for concussion grenade effect - -//============================================================================= -/* -void V_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; - } - } -} - - -=================== -V_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 V_InterpolateAngles( float *start, float *end, float *output, float frac ) -{ - int i; - float ang1, ang2; - float d; - - V_NormalizeAngles( start ); - V_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; - } - - V_NormalizeAngles( output ); -} */ - -// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear -float V_CalcBob ( struct ref_params_s *pparams ) -{ - static double bobtime; - static float bob; - float cycle; - static float lasttime; - vec3_t vel; - - - if ( pparams->onground == -1 || - pparams->time == lasttime ) - { - // just use old value - return bob; - } - - lasttime = pparams->time; - - bobtime += pparams->frametime; - cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; - cycle /= cl_bobcycle->value; - - if ( cycle < cl_bobup->value ) - { - cycle = M_PI * cycle / cl_bobup->value; - } - else - { - cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); - } - - // bob is proportional to simulated velocity in the xy plane - // (don't count Z, or jumping messes it up) - VectorCopy( pparams->simvel, vel ); - vel[2] = 0; - - bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; - bob = bob * 0.3 + bob * 0.7 * sin(cycle); - bob = min( bob, 4 ); - bob = max( bob, -7 ); - return bob; - -} - -/* -=============== -V_CalcRoll -Used by view and sv_user -=============== -*/ -float V_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; -} - -typedef struct pitchdrift_s -{ - float pitchvel; - int nodrift; - float driftmove; - double laststop; -} pitchdrift_t; - -static pitchdrift_t pd; - - -/* -=============== -V_DriftPitch - -Moves the client pitch angle towards idealpitch sent by the server. - -If the user is adjusting pitch manually, either with lookup/lookdown, -mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. -=============== -*/ - -/* -============================================================================== - VIEW RENDERING -============================================================================== -*/ - -/* -================== -V_CalcGunAngle -================== -*/ -void V_CalcGunAngle ( struct ref_params_s *pparams ) -{ - cl_entity_t *viewent; - - viewent = gEngfuncs.GetViewModel(); - if ( !viewent ) - return; - - viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; - viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; - viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - - // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. - viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); - viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; - - VectorCopy( viewent->angles, viewent->curstate.angles ); - VectorCopy( viewent->angles, viewent->latched.prevangles ); -} - -/* -============== -V_AddIdle - -Idle swaying -============== -*/ -void V_AddIdle ( struct ref_params_s *pparams ) -{ - pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; - pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; -} - - -/* -============== -V_CalcViewRoll - -Roll is induced by movement and damage -============== -*/ -void V_CalcViewRoll ( struct ref_params_s *pparams ) -{ - float side; - cl_entity_t *viewentity; - - viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( !viewentity ) - return; - - side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); - - pparams->viewangles[ROLL] += side; - - if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) - { - // only roll the view if the player is dead and the viewheight[2] is nonzero - // this is so deadcam in multiplayer will work. - pparams->viewangles[ROLL] = 80; // dead view angle - return; - } -} - - -/* -================== -V_CalcIntermissionRefdef - -================== -*/ -void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) -{ - cl_entity_t *ent, *view; - float old; - - // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); - - // view is the weapon model (only visible from inside body ) - view = gEngfuncs.GetViewModel(); - - VectorCopy ( pparams->simorg, pparams->vieworg ); - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); - - view->model = NULL; - - // allways idle in intermission - old = v_idlescale; - v_idlescale = 1; - - V_AddIdle ( pparams ); - - if ( gEngfuncs.IsSpectateOnly() ) - { - // in HLTV we must go to 'intermission' position by ourself - VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); - VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); - } - - v_idlescale = old; - - v_cl_angles = pparams->cl_viewangles; - v_origin = pparams->vieworg; - v_angles = pparams->viewangles; -} - -#define ORIGIN_BACKUP 64 -#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) - -typedef struct -{ - float Origins[ ORIGIN_BACKUP ][3]; - float OriginTime[ ORIGIN_BACKUP ]; - - float Angles[ ORIGIN_BACKUP ][3]; - float AngleTime[ ORIGIN_BACKUP ]; - - int CurrentOrigin; - int CurrentAngle; -} viewinterp_t; - -/* -================== -V_CalcRefdef - -================== -*/ -void V_CalcNormalRefdef ( struct ref_params_s *pparams ) -{ - cl_entity_t *ent, *view; - int i; - vec3_t angles; - float bob, waterOffset; - static viewinterp_t ViewInterp; - - static float oldz = 0; - static float lasttime; - - vec3_t camAngles, camForward, camRight, camUp; - cl_entity_t *pwater; - - if ( gEngfuncs.IsSpectateOnly() ) - { - ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); - } - else - { - // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); - } - - // view is the weapon model (only visible from inside body ) - view = gEngfuncs.GetViewModel(); - - // transform the view offset by the model's matrix to get the offset from - // model origin for the view - bob = V_CalcBob ( pparams ); - - // refresh position - VectorCopy ( pparams->simorg, pparams->vieworg ); - pparams->vieworg[2] += ( bob ); - VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); - - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); - - gEngfuncs.V_CalcShake(); - gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); - - // never let view origin sit exactly on a node line, because a water plane can - // dissapear when viewed with the eye exactly on it. - // FIXME, we send origin at 1/128 now, change this? - // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis - - pparams->vieworg[0] += 1.0/32; - pparams->vieworg[1] += 1.0/32; - pparams->vieworg[2] += 1.0/32; - - // Check for problems around water, move the viewer artificially if necessary - // -- this prevents drawing errors in GL due to waves - - waterOffset = 0; - if ( pparams->waterlevel >= 2 ) - { - int contents, waterDist, waterEntity; - vec3_t point; - waterDist = cl_waterdist->value; - - if ( pparams->hardware ) - { - waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); - if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) - { - pwater = gEngfuncs.GetEntityByIndex( waterEntity ); - if ( pwater && ( pwater->model != NULL ) ) - { - waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height - } - } - } - else - { - waterEntity = 0; // Don't need this in software - } - - VectorCopy( pparams->vieworg, point ); - - // Eyes are above water, make sure we're above the waves - if ( pparams->waterlevel == 2 ) - { - point[2] -= waterDist; - for ( i = 0; i < waterDist; i++ ) - { - contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents > CONTENTS_WATER ) - break; - point[2] += 1; - } - waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; - } - else - { - // eyes are under water. Make sure we're far enough under - point[2] += waterDist; - - for ( i = 0; i < waterDist; i++ ) - { - contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents <= CONTENTS_WATER ) - break; - point[2] -= 1; - } - waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; - } - } - - pparams->vieworg[2] += waterOffset; - - V_CalcViewRoll ( pparams ); - - V_AddIdle ( pparams ); - - // offsets - VectorCopy( pparams->cl_viewangles, angles ); - - AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); - - // don't allow cheats in multiplayer - if ( pparams->maxclients <= 1 ) - { - for ( i=0 ; i<3 ; i++ ) - { - pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; - } - } - - // Treating cam_ofs[2] as the distance - if( CL_IsThirdPerson() ) - { - vec3_t ofs; - - ofs[0] = ofs[1] = ofs[2] = 0.0; - - CL_CameraOffset( (float *)&ofs ); - - VectorCopy( ofs, camAngles ); - camAngles[ ROLL ] = 0; - - AngleVectors( camAngles, camForward, camRight, camUp ); - - for ( i = 0; i < 3; i++ ) - { - pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; - } - } - - // Give gun our viewangles - VectorCopy ( pparams->cl_viewangles, view->angles ); - - // set up gun position - V_CalcGunAngle ( pparams ); - - // Use predicted origin as view origin. - VectorCopy ( pparams->simorg, view->origin ); - view->origin[2] += ( waterOffset ); - VectorAdd( view->origin, pparams->viewheight, view->origin ); - - // Let the viewmodel shake at about 10% of the amplitude - gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); - - for ( i = 0; i < 3; i++ ) - { - view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; - } - view->origin[2] += bob; - - // throw in a little tilt. - view->angles[YAW] -= bob * 0.5; - view->angles[ROLL] -= bob * 1; - view->angles[PITCH] -= bob * 0.3; - - // pushing the view origin down off of the same X/Z plane as the ent's origin will give the - // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem - // with view model distortion, this may be a cause. (SJB). - view->origin[2] -= 1; - - // fudge position around to keep amount of weapon visible - // roughly equal with different FOV - if (pparams->viewsize == 110) - { - view->origin[2] += 1; - } - else if (pparams->viewsize == 100) - { - view->origin[2] += 2; - } - else if (pparams->viewsize == 90) - { - view->origin[2] += 1; - } - else if (pparams->viewsize == 80) - { - view->origin[2] += 0.5; - } - - // Add in the punchangle, if any - VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); - - // Include client side punch, too - VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); - - V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); - - // smooth out stair step ups -#if 1 - if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) - { - float steptime; - - steptime = pparams->time - lasttime; - if (steptime < 0) - //FIXME I_Error ("steptime < 0"); - steptime = 0; - - oldz += steptime * 150; - if (oldz > pparams->simorg[2]) - oldz = pparams->simorg[2]; - if (pparams->simorg[2] - oldz > 18) - oldz = pparams->simorg[2]- 18; - pparams->vieworg[2] += oldz - pparams->simorg[2]; - view->origin[2] += oldz - pparams->simorg[2]; - } - else - { - oldz = pparams->simorg[2]; - } -#endif - - { - static float lastorg[3]; - vec3_t delta; - - VectorSubtract( pparams->simorg, lastorg, delta ); - - if ( Length( delta ) != 0.0 ) - { - VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); - ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; - ViewInterp.CurrentOrigin++; - - VectorCopy( pparams->simorg, lastorg ); - } - } - - // Smooth out whole view in multiplayer when on trains, lifts - if ( cl_vsmoothing && cl_vsmoothing->value && - ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) - { - int foundidx; - float t; - - if ( cl_vsmoothing->value < 0.0 ) - { - gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); - } - - t = pparams->time - cl_vsmoothing->value; - - for ( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentOrigin - 1 - i; - if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) - break; - } - - if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) - { - // Interpolate - vec3_t delta; - double frac; - double dt; - vec3_t neworg; - - dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; - if ( dt > 0.0 ) - { - frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); - VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); - - // Dont interpolate large changes - if ( Length( delta ) < 64 ) - { - VectorSubtract( neworg, pparams->simorg, delta ); - - VectorAdd( pparams->simorg, delta, pparams->simorg ); - VectorAdd( pparams->vieworg, delta, pparams->vieworg ); - VectorAdd( view->origin, delta, view->origin ); - - } - } - } - } - - // Store off v_angles before munging for third person - v_angles = pparams->viewangles; - v_lastAngles = pparams->viewangles; -// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! - if ( CL_IsThirdPerson() ) - { - VectorCopy( camAngles, pparams->viewangles); - float pitch = camAngles[ 0 ]; - - // Normalize angles - if ( pitch > 180 ) - pitch -= 360.0; - else if ( pitch < -180 ) - pitch += 360; - - // Player pitch is inverted - pitch /= -3.0; - - // Slam local player's pitch value - ent->angles[ 0 ] = pitch; - ent->curstate.angles[ 0 ] = pitch; - ent->prevstate.angles[ 0 ] = pitch; - ent->latched.prevangles[ 0 ] = pitch; - } - - // override all previous settings if the viewent isn't the client - if ( pparams->viewentity > pparams->maxclients ) - { - cl_entity_t *viewentity; - viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( viewentity ) - { - VectorCopy( viewentity->origin, pparams->vieworg ); - VectorCopy( viewentity->angles, pparams->viewangles ); - - // Store off overridden viewangles - v_angles = pparams->viewangles; - } - } - - lasttime = pparams->time; - - v_origin = pparams->vieworg; -} - -void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) -{ - float absd,frac,d,threshhold; - - NormalizeAngles( startAngle ); - NormalizeAngles( endAngle ); - - for ( int i = 0 ; i < 3 ; i++ ) - { - d = endAngle[i] - startAngle[i]; - - if ( d > 180.0f ) - { - d -= 360.0f; - } - else if ( d < -180.0f ) - { - d += 360.0f; - } - - absd = fabs(d); - - if ( absd > 0.01f ) - { - frac = degreesPerSec * v_frametime; - - threshhold= degreesPerSec / 4; - - if ( absd < threshhold ) - { - float h = absd / threshhold; - h *= h; - frac*= h; // slow down last degrees - } - - if ( frac > absd ) - { - finalAngle[i] = endAngle[i]; - } - else - { - if ( d>0) - finalAngle[i] = startAngle[i] + frac; - else - finalAngle[i] = startAngle[i] - frac; - } - } - else - { - finalAngle[i] = endAngle[i]; - } - - } - - NormalizeAngles( finalAngle ); -} - -// Get the origin of the Observer based around the target's position and angles -void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) -{ - vec3_t vecEnd; - vec3_t forward; - vec3_t vecStart; - pmtrace_t * trace; - int maxLoops = 8; - - int ignoreent = -1; // first, ignore no entity - - cl_entity_t * ent = NULL; - - // Trace back from the target using the player's view angles - AngleVectors(angles, forward, NULL, NULL); - - VectorScale(forward,-1,forward); - - VectorCopy( origin, vecStart ); - - VectorMA(vecStart, distance , forward, vecEnd); - - while ( maxLoops > 0) - { - trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); - - // WARNING! trace->ent is is the number in physent list not the normal entity number - - if ( trace->ent <= 0) - break; // we hit the world or nothing, stop trace - - ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); - - if ( ent == NULL ) - break; - - // hit non-player solid BSP , stop here - if ( ent->curstate.solid == SOLID_BSP && !ent->player ) - break; - - // if close enought to end pos, stop, otherwise continue trace - if( Distance(trace->endpos, vecEnd ) < 1.0f ) - { - break; - } - else - { - ignoreent = trace->ent; // ignore last hit entity - VectorCopy( trace->endpos, vecStart); - } - - maxLoops--; - } - -/* if ( ent ) - { - gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); - } */ - - VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); - - v_lastDistance = Distance(trace->endpos, origin); // real distance without offset -} - -/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; - - float distance = 168.0f; - - v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back - - if ( v_resetCamera ) - v_lastDistance = 64.0f; - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - - // get new angle towards second target - if ( ent2 ) - { - VectorSubtract( ent2->origin, ent1->origin, newAngle ); - VectorAngles( newAngle, newAngle ); - newAngle[0] = -newAngle[0]; - } - else - { - // if no second target is given, look down to dead player - newAngle[0] = 90.0f; - newAngle[1] = 0.0f; - newAngle[2] = 0; - } - - // and smooth view - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); - - V_GetChaseOrigin( angle, newOrigin, distance, origin ); - - VectorCopy(angle, v_lastAngles); -}*/ - -void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - // see is target is a dead player - qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - else if ( deadPlayer ) - distance*=1.5f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - { - if ( deadPlayer ) - newOrigin[2]+= 2; //laying on ground - else - newOrigin[2]+= 17; // head level of living player - - } - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - // we have no second target, choose view direction based on - // show front of primary target - VectorCopy(ent1->angles, newAngle); - - // show dead players from front, normal players back - if ( flags & DRC_FLAG_FACEPLAYER ) - newAngle[1]+= 180.0f; - - - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic - - // if final scene (bomb), show from real high pos - if ( flags & DRC_FLAG_FINAL ) - newAngle[0] = 22.5f; - - // choose side of object/player - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; - else - newAngle[1]-=22.5f; - - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); - - // HACK, if player is dead don't clip against his dead body, can't check this - V_GetChaseOrigin( angle, newOrigin, distance, origin ); -} - -float MaxAngleBetweenAngles( float * a1, float * a2 ) -{ - float d, maxd = 0.0f; - - NormalizeAngles( a1 ); - NormalizeAngles( a2 ); - - for ( int i = 0 ; i < 3 ; i++ ) - { - d = a2[i] - a1[i]; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - d = fabs(d); - - if ( d > maxd ) - maxd=d; - } - - return maxd; -} - -void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) -{ - float newAngle[3]; float newOrigin[3]; float tempVec[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - // get new angle towards second target - VectorSubtract( ent2->origin, ent1->origin, newAngle ); - - VectorAngles( newAngle, newAngle ); - newAngle[0] = -newAngle[0]; - - // set angle diffrent in Dramtaic scenes - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic - - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; - else - newAngle[1]-=22.5f; - - float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); - - if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) - { - // difference is to small and we are in relax camera mode, keep viewangles - VectorCopy(v_lastAngles, newAngle ); - } - else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) - { - // we catched up with our target, relax again - v_cameraMode = CAM_MODE_RELAX; - } - else - { - // target move too far away, focus camera again - v_cameraMode = CAM_MODE_FOCUS; - } - - // and smooth view, if not a scene cut - if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) - { - VectorCopy( newAngle, angle ); - } - else - { - V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); - } - - V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); - - // move position up, if very close at target - if ( v_lastDistance < 64.0f ) - origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); - - // calculate angle to second target - VectorSubtract( ent2->origin, origin, tempVec ); - VectorAngles( tempVec, tempVec ); - tempVec[0] = -tempVec[0]; - - /* take middle between two viewangles - InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ - - - -} - -void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) -{ - - if ( v_resetCamera ) - { - v_lastDistance = 4096.0f; - // v_cameraMode = CAM_MODE_FOCUS; - } - - if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) - { - // we have no second target or player just died - V_GetSingleTargetCam(ent1, angle, origin); - } - else if ( ent2 ) - { - // keep both target in view - V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); - } - else - { - // second target disappeard somehow (dead) - - // keep last good viewangle - float newOrigin[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; - - float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - - if ( distance > v_lastDistance ) - distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player - else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS - - V_GetChaseOrigin( angle, newOrigin, distance, origin ); - } - - VectorCopy(angle, v_lastAngles); -} - -void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) -{ - cl_entity_t * ent = NULL; - - if ( target ) - { - ent = gEngfuncs.GetEntityByIndex( target ); - }; - - if (!ent) - { - // just copy a save in-map position - VectorCopy ( vJumpAngles, angles ); - VectorCopy ( vJumpOrigin, origin ); - return; - } - - - - if ( gHUD.m_Spectator.m_autoDirector->value ) - { - if ( g_iUser3 ) - V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), - angles, origin ); - else - V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, - angles, origin ); - } - else - { - if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) - { - VectorCopy ( ent->angles, angles); - angles[0]*=-1; - } - else - VectorCopy ( cl_angles, angles); - - - VectorCopy ( ent->origin, origin); - - origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset - - V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); - } - - v_resetCamera = false; -} - -void V_ResetChaseCam() -{ - v_resetCamera = true; -} - - -void V_GetInEyePos(int target, float * origin, float * angles ) -{ - if ( !target) - { - // just copy a save in-map position - VectorCopy ( vJumpAngles, angles ); - VectorCopy ( vJumpOrigin, origin ); - return; - }; - - - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); - - if ( !ent ) - return; - - VectorCopy ( ent->origin, origin ); - VectorCopy ( ent->angles, angles ); - - angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() - - if ( ent->curstate.solid == SOLID_NOT ) - { - angles[ROLL] = 80; // dead view angle - origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT - } - else if (ent->curstate.usehull == 1 ) - origin[2]+= 12; // VEC_DUCK_VIEW; - else - // exacty eye position can't be caluculated since it depends on - // client values like cl_bobcycle, this offset matches the default values - origin[2]+= 28; // DEFAULT_VIEWHEIGHT -} - -void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) -{ - vec3_t forward; - vec3_t zScaledTarget; - - VectorCopy(cl_angles, angles); - - // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - - zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; - zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; - zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); - - - AngleVectors(angles, forward, NULL, NULL); - - VectorNormalize(forward); - - VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); -} - -void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) -{ - vec3_t forward; - - if ( target ) - { - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); - - if ( gHUD.m_Spectator.m_autoDirector->value ) - { - // this is done to get the angles made by director mode - V_GetChasePos(target, cl_angles, origin, angles); - VectorCopy(ent->origin, origin); - - // keep fix chase angle horizontal - angles[0] = 45.0f; - } - else - { - VectorCopy(cl_angles, angles); - VectorCopy(ent->origin, origin); - - // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - } - } - else - { - // keep out roaming position, but modify angles - VectorCopy(cl_angles, angles); - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); - } - - origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); - angles[2] = 0.0f; // don't roll angle (if chased player is dead) - - AngleVectors(angles, forward, NULL, NULL); - - VectorNormalize(forward); - - VectorMA(origin, -1536, forward, origin); -} - -int V_FindViewModelByWeaponModel(int weaponindex) -{ - - static char * modelmap[][2] = { - { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, - { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, - { "models/p_egon.mdl", "models/v_egon.mdl" }, - { "models/p_gauss.mdl", "models/v_gauss.mdl" }, - { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, - { "models/p_grenade.mdl", "models/v_grenade.mdl" }, - { "models/p_hgun.mdl", "models/v_hgun.mdl" }, - { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, - { "models/p_357.mdl", "models/v_357.mdl" }, - { "models/p_rpg.mdl", "models/v_rpg.mdl" }, - { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, - { "models/p_squeak.mdl", "models/v_squeak.mdl" }, - { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, - { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, - { "models/p_satchel.mdl", "models/v_satchel.mdl" }, - { NULL, NULL } }; - - struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); - - if ( weaponModel ) - { - int len = strlen( weaponModel->name ); - int i = 0; - - while ( modelmap[i][0] != NULL ) - { - if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) - { - return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); - } - i++; - } - - return 0; - } - else - return 0; - -} - - -/* -================== -V_CalcSpectatorRefdef - -================== -*/ -void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) -{ - static vec3_t velocity ( 0.0f, 0.0f, 0.0f); - - static int lastWeaponModelIndex = 0; - static int lastViewModelIndex = 0; - - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); - - pparams->onlyClientDraw = false; - - // refresh position - VectorCopy ( pparams->simorg, v_sim_org ); - - // get old values - VectorCopy ( pparams->cl_viewangles, v_cl_angles ); - VectorCopy ( pparams->viewangles, v_angles ); - VectorCopy ( pparams->vieworg, v_origin ); - - if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) - { - // calculate player velocity - float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; - - if ( timeDiff > 0 ) - { - vec3_t distance; - VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); - VectorScale(distance, 1/timeDiff, distance ); - - velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; - velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; - velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; - - VectorCopy(velocity, pparams->simvel); - } - - // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) - if ( gEngfuncs.IsSpectateOnly() ) - { - V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); - - pparams->health = 1; - - cl_entity_t * gunModel = gEngfuncs.GetViewModel(); - - if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) - { - // weapon model changed - - lastWeaponModelIndex = ent->curstate.weaponmodel; - lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); - if ( lastViewModelIndex ) - { - gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation - } - else - { - // model not found - gunModel->model = NULL; // disable weapon model - lastWeaponModelIndex = lastViewModelIndex = 0; - } - } - - if ( lastViewModelIndex ) - { - gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); - gunModel->curstate.modelindex = lastViewModelIndex; - gunModel->curstate.frame = 0; - gunModel->curstate.colormap = 0; - gunModel->index = g_iUser2; - } - else - { - gunModel->model = NULL; // disable weaopn model - } - } - else - { - // only get viewangles from entity - VectorCopy ( ent->angles, pparams->cl_viewangles ); - pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() - } - } - - v_frametime = pparams->frametime; - - if ( pparams->nextView == 0 ) - { - // first renderer cycle, full screen - - switch ( g_iUser1 ) - { - case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - break; - - case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); - VectorCopy (v_sim_org, v_origin); - break; - - case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); - break; - - case OBS_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case OBS_MAP_CHASE : pparams->onlyClientDraw = true; - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - } - - if ( gHUD.m_Spectator.m_pip->value ) - pparams->nextView = 1; // force a second renderer view - - gHUD.m_Spectator.m_iDrawCycle = 0; - - } - else - { - // second renderer cycle, inset window - - // set inset parameters - pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window - pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); - pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); - pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); - pparams->nextView = 0; // on further view - - // override some settings in certain modes - switch ( (int)gHUD.m_Spectator.m_pip->value ) - { - case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); - break; - - case INSET_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case INSET_MAP_CHASE : pparams->onlyClientDraw = true; - - if ( g_iUser1 == OBS_ROAMING ) - V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); - else - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - - break; - } - - gHUD.m_Spectator.m_iDrawCycle = 1; - } - - // write back new values into pparams - VectorCopy ( v_cl_angles, pparams->cl_viewangles ); - VectorCopy ( v_angles, pparams->viewangles ) - VectorCopy ( v_origin, pparams->vieworg ); - -} - - - -void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) -{ - // intermission / finale rendering - if ( pparams->intermission ) - { - V_CalcIntermissionRefdef ( pparams ); - } - else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode - { - V_CalcSpectatorRefdef ( pparams ); - } - else if ( !pparams->paused ) - { - V_CalcNormalRefdef ( pparams ); - } - -/* -// Example of how to overlay the whole screen with red at 50 % alpha -#define SF_TEST -#if defined SF_TEST - { - screenfade_t sf; - gEngfuncs.pfnGetScreenFade( &sf ); - - sf.fader = 255; - sf.fadeg = 0; - sf.fadeb = 0; - sf.fadealpha = 128; - sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; - - gEngfuncs.pfnSetScreenFade( &sf ); - } -#endif -*/ -} - -/* -============= -V_DropPunchAngle - -============= -*/ -void V_DropPunchAngle ( float frametime, float *ev_punchangle ) -{ - float len; - - len = VectorNormalize ( ev_punchangle ); - len -= (10.0 + len * 0.5) * frametime; - len = max( len, 0.0 ); - VectorScale ( ev_punchangle, len, ev_punchangle ); -} - -/* -============= -V_PunchAxis - -Client side punch effect -============= -*/ -void V_PunchAxis( int axis, float punch ) -{ - ev_punchangle[ axis ] = punch; -} - -/* -============= -V_Init -============= -*/ -void V_Init (void) -{ - - scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); - scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); - scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); - - v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); - v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); - - cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) - cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) - cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); - cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); - cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); -} - - -//#define TRACE_TEST -#if defined( TRACE_TEST ) - -extern float in_fov; -/* -==================== -CalcFov -==================== -*/ -float CalcFov (float fov_x, float width, float height) -{ - float a; - float x; - - if (fov_x < 1 || fov_x > 179) - fov_x = 90; // error, set to 90 - - x = width/tan(fov_x/360*M_PI); - - a = atan (height/x); - - a = a*360/M_PI; - - return a; -} - -int hitent = -1; - -void V_Move( int mx, int my ) -{ - float fov; - float fx, fy; - float dx, dy; - float c_x, c_y; - float dX, dY; - vec3_t forward, up, right; - vec3_t newangles; - - vec3_t farpoint; - pmtrace_t tr; - - fov = CalcFov( in_fov, (float)ScreenWidth, (float)ScreenHeight ); - - c_x = (float)ScreenWidth / 2.0; - c_y = (float)ScreenHeight / 2.0; - - dx = (float)mx - c_x; - dy = (float)my - c_y; - - // Proportion we moved in each direction - fx = dx / c_x; - fy = dy / c_y; - - dX = fx * in_fov / 2.0 ; - dY = fy * fov / 2.0; - - newangles = v_angles; - - newangles[ YAW ] -= dX; - newangles[ PITCH ] += dY; - - // Now rotate v_forward around that point - AngleVectors ( newangles, forward, right, up ); - - farpoint = v_origin + 8192 * forward; - - // Trace - tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); - - if ( tr.fraction != 1.0 && tr.ent != 0 ) - { - hitent = PM_GetPhysEntInfo( tr.ent ); - PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); - } - else - { - hitent = -1; - } -} - -#endif +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// view/refresh setup functions + +#include "hud.h" +#include "cl_util.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" + +#include "entity_state.h" +#include "cl_entity.h" +#include "ref_params.h" +#include "in_defs.h" // PITCH YAW ROLL +#include "pm_movevars.h" +#include "pm_shared.h" +#include "pm_defs.h" +#include "event_api.h" +#include "pmtrace.h" +#include "screenfade.h" +#include "shake.h" +#include "hltv.h" + +// Spectator Mode +extern "C" +{ + float vecNewViewAngles[3]; + int iHasNewViewAngles; + float vecNewViewOrigin[3]; + int iHasNewViewOrigin; + int iIsSpectator; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern "C" +{ + int CL_IsThirdPerson( void ); + void CL_CameraOffset( float *ofs ); + + void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); + + void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); + int PM_GetVisEntInfo( int ent ); + int PM_GetPhysEntInfo( int ent ); + void InterpolateAngles( float * start, float * end, float * output, float frac ); + void NormalizeAngles( float * angles ); + float Distance(const float * v1, const float * v2); + float AngleBetweenVectors( const float * v1, const float * v2 ); + + float vJumpOrigin[3]; + float vJumpAngles[3]; +} + +void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void VectorAngles( const float *forward, float *angles ); + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +/* +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. +*/ + +extern cvar_t *cl_forwardspeed; +extern cvar_t *chase_active; +extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; +extern cvar_t *cl_vsmoothing; + +#define CAM_MODE_RELAX 1 +#define CAM_MODE_FOCUS 2 + +vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; +float v_frametime, v_lastDistance; +float v_cameraRelaxAngle = 5.0f; +float v_cameraFocusAngle = 35.0f; +int v_cameraMode = CAM_MODE_FOCUS; +qboolean v_resetCamera = 1; + +vec3_t ev_punchangle; + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + +cvar_t *cl_bobcycle; +cvar_t *cl_bob; +cvar_t *cl_bobup; +cvar_t *cl_waterdist; +cvar_t *cl_chasedist; + +// These cvars are not registered (so users can't cheat), so set the ->value field directly +// Register these cvars in V_Init() if needed for easy tweaking +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; + +float v_idlescale; // used by TFC for concussion grenade effect + +//============================================================================= +/* +void V_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; + } + } +} + + +=================== +V_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 V_InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + V_NormalizeAngles( start ); + V_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; + } + + V_NormalizeAngles( output ); +} */ + +// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear +float V_CalcBob ( struct ref_params_s *pparams ) +{ + static double bobtime; + static float bob; + float cycle; + static float lasttime; + vec3_t vel; + + + if ( pparams->onground == -1 || + pparams->time == lasttime ) + { + // just use old value + return bob; + } + + lasttime = pparams->time; + + bobtime += pparams->frametime; + cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + + if ( cycle < cl_bobup->value ) + { + cycle = M_PI * cycle / cl_bobup->value; + } + else + { + cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); + } + + // bob is proportional to simulated velocity in the xy plane + // (don't count Z, or jumping messes it up) + VectorCopy( pparams->simvel, vel ); + vel[2] = 0; + + bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; + bob = bob * 0.3 + bob * 0.7 * sin(cycle); + bob = min( bob, 4 ); + bob = max( bob, -7 ); + return bob; + +} + +/* +=============== +V_CalcRoll +Used by view and sv_user +=============== +*/ +float V_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; +} + +typedef struct pitchdrift_s +{ + float pitchvel; + int nodrift; + float driftmove; + double laststop; +} pitchdrift_t; + +static pitchdrift_t pd; + + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. +=============== +*/ + +/* +============================================================================== + VIEW RENDERING +============================================================================== +*/ + +/* +================== +V_CalcGunAngle +================== +*/ +void V_CalcGunAngle ( struct ref_params_s *pparams ) +{ + cl_entity_t *viewent; + + viewent = gEngfuncs.GetViewModel(); + if ( !viewent ) + return; + + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; + viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. + viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); + viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle ( struct ref_params_s *pparams ) +{ + pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll ( struct ref_params_s *pparams ) +{ + float side; + cl_entity_t *viewentity; + + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( !viewentity ) + return; + + side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + + pparams->viewangles[ROLL] += side; + + if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + { + // only roll the view if the player is dead and the viewheight[2] is nonzero + // this is so deadcam in multiplayer will work. + pparams->viewangles[ROLL] = 80; // dead view angle + return; + } +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + float old; + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + VectorCopy ( pparams->simorg, pparams->vieworg ); + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + view->model = NULL; + + // allways idle in intermission + old = v_idlescale; + v_idlescale = 1; + + V_AddIdle ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV we must go to 'intermission' position by ourself + VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); + VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); + } + + v_idlescale = old; + + v_cl_angles = pparams->cl_viewangles; + v_origin = pparams->vieworg; + v_angles = pparams->viewangles; +} + +#define ORIGIN_BACKUP 64 +#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) + +typedef struct +{ + float Origins[ ORIGIN_BACKUP ][3]; + float OriginTime[ ORIGIN_BACKUP ]; + + float Angles[ ORIGIN_BACKUP ][3]; + float AngleTime[ ORIGIN_BACKUP ]; + + int CurrentOrigin; + int CurrentAngle; +} viewinterp_t; + +/* +================== +V_CalcRefdef + +================== +*/ +void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + vec3_t camAngles, camForward, camRight, camUp; + cl_entity_t *pwater; + + if ( gEngfuncs.IsSpectateOnly() ) + { + ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + } + else + { + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + } + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // transform the view offset by the model's matrix to get the offset from + // model origin for the view + bob = V_CalcBob ( pparams ); + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += ( bob ); + VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + // never let view origin sit exactly on a node line, because a water plane can + // dissapear when viewed with the eye exactly on it. + // FIXME, we send origin at 1/128 now, change this? + // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + + pparams->vieworg[0] += 1.0/32; + pparams->vieworg[1] += 1.0/32; + pparams->vieworg[2] += 1.0/32; + + // Check for problems around water, move the viewer artificially if necessary + // -- this prevents drawing errors in GL due to waves + + waterOffset = 0; + if ( pparams->waterlevel >= 2 ) + { + int contents, waterDist, waterEntity; + vec3_t point; + waterDist = cl_waterdist->value; + + if ( pparams->hardware ) + { + waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); + if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + { + pwater = gEngfuncs.GetEntityByIndex( waterEntity ); + if ( pwater && ( pwater->model != NULL ) ) + { + waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height + } + } + } + else + { + waterEntity = 0; // Don't need this in software + } + + VectorCopy( pparams->vieworg, point ); + + // Eyes are above water, make sure we're above the waves + if ( pparams->waterlevel == 2 ) + { + point[2] -= waterDist; + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents > CONTENTS_WATER ) + break; + point[2] += 1; + } + waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + } + else + { + // eyes are under water. Make sure we're far enough under + point[2] += waterDist; + + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents <= CONTENTS_WATER ) + break; + point[2] -= 1; + } + waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + } + } + + pparams->vieworg[2] += waterOffset; + + V_CalcViewRoll ( pparams ); + + V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + // don't allow cheats in multiplayer + if ( pparams->maxclients <= 1 ) + { + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + } + + // Treating cam_ofs[2] as the distance + if( CL_IsThirdPerson() ) + { + vec3_t ofs; + + ofs[0] = ofs[1] = ofs[2] = 0.0; + + CL_CameraOffset( (float *)&ofs ); + + VectorCopy( ofs, camAngles ); + camAngles[ ROLL ] = 0; + + AngleVectors( camAngles, camForward, camRight, camUp ); + + for ( i = 0; i < 3; i++ ) + { + pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + } + } + + // Give gun our viewangles + VectorCopy ( pparams->cl_viewangles, view->angles ); + + // set up gun position + V_CalcGunAngle ( pparams ); + + // Use predicted origin as view origin. + VectorCopy ( pparams->simorg, view->origin ); + view->origin[2] += ( waterOffset ); + VectorAdd( view->origin, pparams->viewheight, view->origin ); + + // Let the viewmodel shake at about 10% of the amplitude + gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); + + for ( i = 0; i < 3; i++ ) + { + view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + } + view->origin[2] += bob; + + // throw in a little tilt. + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; + view->angles[PITCH] -= bob * 0.3; + + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the + // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem + // with view model distortion, this may be a cause. (SJB). + view->origin[2] -= 1; + + // fudge position around to keep amount of weapon visible + // roughly equal with different FOV + if (pparams->viewsize == 110) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 100) + { + view->origin[2] += 2; + } + else if (pparams->viewsize == 90) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 80) + { + view->origin[2] += 0.5; + } + + // Add in the punchangle, if any + VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + + // Include client side punch, too + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + + V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) + { + int foundidx; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + v_lastAngles = pparams->viewangles; +// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! + if ( CL_IsThirdPerson() ) + { + VectorCopy( camAngles, pparams->viewangles); + float pitch = camAngles[ 0 ]; + + // Normalize angles + if ( pitch > 180 ) + pitch -= 360.0; + else if ( pitch < -180 ) + pitch += 360; + + // Player pitch is inverted + pitch /= -3.0; + + // Slam local player's pitch value + ent->angles[ 0 ] = pitch; + ent->curstate.angles[ 0 ] = pitch; + ent->prevstate.angles[ 0 ] = pitch; + ent->latched.prevangles[ 0 ] = pitch; + } + + // override all previous settings if the viewent isn't the client + if ( pparams->viewentity > pparams->maxclients ) + { + cl_entity_t *viewentity; + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( viewentity ) + { + VectorCopy( viewentity->origin, pparams->vieworg ); + VectorCopy( viewentity->angles, pparams->viewangles ); + + // Store off overridden viewangles + v_angles = pparams->viewangles; + } + } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; +} + +void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) +{ + float absd,frac,d,threshhold; + + NormalizeAngles( startAngle ); + NormalizeAngles( endAngle ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = endAngle[i] - startAngle[i]; + + if ( d > 180.0f ) + { + d -= 360.0f; + } + else if ( d < -180.0f ) + { + d += 360.0f; + } + + absd = fabs(d); + + if ( absd > 0.01f ) + { + frac = degreesPerSec * v_frametime; + + threshhold= degreesPerSec / 4; + + if ( absd < threshhold ) + { + float h = absd / threshhold; + h *= h; + frac*= h; // slow down last degrees + } + + if ( frac > absd ) + { + finalAngle[i] = endAngle[i]; + } + else + { + if ( d>0) + finalAngle[i] = startAngle[i] + frac; + else + finalAngle[i] = startAngle[i] - frac; + } + } + else + { + finalAngle[i] = endAngle[i]; + } + + } + + NormalizeAngles( finalAngle ); +} + +// Get the origin of the Observer based around the target's position and angles +void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) +{ + vec3_t vecEnd; + vec3_t forward; + vec3_t vecStart; + pmtrace_t * trace; + int maxLoops = 8; + + int ignoreent = -1; // first, ignore no entity + + cl_entity_t * ent = NULL; + + // Trace back from the target using the player's view angles + AngleVectors(angles, forward, NULL, NULL); + + VectorScale(forward,-1,forward); + + VectorCopy( origin, vecStart ); + + VectorMA(vecStart, distance , forward, vecEnd); + + while ( maxLoops > 0) + { + trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); + + // WARNING! trace->ent is is the number in physent list not the normal entity number + + if ( trace->ent <= 0) + break; // we hit the world or nothing, stop trace + + ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); + + if ( ent == NULL ) + break; + + // hit non-player solid BSP , stop here + if ( ent->curstate.solid == SOLID_BSP && !ent->player ) + break; + + // if close enought to end pos, stop, otherwise continue trace + if( Distance(trace->endpos, vecEnd ) < 1.0f ) + { + break; + } + else + { + ignoreent = trace->ent; // ignore last hit entity + VectorCopy( trace->endpos, vecStart); + } + + maxLoops--; + } + +/* if ( ent ) + { + gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); + } */ + + VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); + + v_lastDistance = Distance(trace->endpos, origin); // real distance without offset +} + +/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + float distance = 168.0f; + + v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back + + if ( v_resetCamera ) + v_lastDistance = 64.0f; + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + + // get new angle towards second target + if ( ent2 ) + { + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + } + else + { + // if no second target is given, look down to dead player + newAngle[0] = 90.0f; + newAngle[1] = 0.0f; + newAngle[2] = 0; + } + + // and smooth view + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + + VectorCopy(angle, v_lastAngles); +}*/ + +void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + // see is target is a dead player + qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + else if ( deadPlayer ) + distance*=1.5f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + { + if ( deadPlayer ) + newOrigin[2]+= 2; //laying on ground + else + newOrigin[2]+= 17; // head level of living player + + } + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // we have no second target, choose view direction based on + // show front of primary target + VectorCopy(ent1->angles, newAngle); + + // show dead players from front, normal players back + if ( flags & DRC_FLAG_FACEPLAYER ) + newAngle[1]+= 180.0f; + + + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + // if final scene (bomb), show from real high pos + if ( flags & DRC_FLAG_FINAL ) + newAngle[0] = 22.5f; + + // choose side of object/player + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + // HACK, if player is dead don't clip against his dead body, can't check this + V_GetChaseOrigin( angle, newOrigin, distance, origin ); +} + +float MaxAngleBetweenAngles( float * a1, float * a2 ) +{ + float d, maxd = 0.0f; + + NormalizeAngles( a1 ); + NormalizeAngles( a2 ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = a2[i] - a1[i]; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + d = fabs(d); + + if ( d > maxd ) + maxd=d; + } + + return maxd; +} + +void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; float tempVec[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // get new angle towards second target + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + + // set angle diffrent in Dramtaic scenes + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); + + if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) + { + // difference is to small and we are in relax camera mode, keep viewangles + VectorCopy(v_lastAngles, newAngle ); + } + else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) + { + // we catched up with our target, relax again + v_cameraMode = CAM_MODE_RELAX; + } + else + { + // target move too far away, focus camera again + v_cameraMode = CAM_MODE_FOCUS; + } + + // and smooth view, if not a scene cut + if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) + { + VectorCopy( newAngle, angle ); + } + else + { + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); + } + + V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); + + // move position up, if very close at target + if ( v_lastDistance < 64.0f ) + origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); + + // calculate angle to second target + VectorSubtract( ent2->origin, origin, tempVec ); + VectorAngles( tempVec, tempVec ); + tempVec[0] = -tempVec[0]; + + /* take middle between two viewangles + InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ + + + +} + +void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + + if ( v_resetCamera ) + { + v_lastDistance = 4096.0f; + // v_cameraMode = CAM_MODE_FOCUS; + } + + if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) + { + // we have no second target or player just died + V_GetSingleTargetCam(ent1, angle, origin); + } + else if ( ent2 ) + { + // keep both target in view + V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); + } + else + { + // second target disappeard somehow (dead) + + // keep last good viewangle + float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + } + + VectorCopy(angle, v_lastAngles); +} + +void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) +{ + cl_entity_t * ent = NULL; + + if ( target ) + { + ent = gEngfuncs.GetEntityByIndex( target ); + }; + + if (!ent) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + } + + + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + if ( g_iUser3 ) + V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), + angles, origin ); + else + V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, + angles, origin ); + } + else + { + if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) + { + VectorCopy ( ent->angles, angles); + angles[0]*=-1; + } + else + VectorCopy ( cl_angles, angles); + + + VectorCopy ( ent->origin, origin); + + origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset + + V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); + } + + v_resetCamera = false; +} + +void V_ResetChaseCam() +{ + v_resetCamera = true; +} + + +void V_GetInEyePos(int target, float * origin, float * angles ) +{ + if ( !target) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + }; + + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( !ent ) + return; + + VectorCopy ( ent->origin, origin ); + VectorCopy ( ent->angles, angles ); + + angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + + if ( ent->curstate.solid == SOLID_NOT ) + { + angles[ROLL] = 80; // dead view angle + origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + } + else if (ent->curstate.usehull == 1 ) + origin[2]+= 12; // VEC_DUCK_VIEW; + else + // exacty eye position can't be caluculated since it depends on + // client values like cl_bobcycle, this offset matches the default values + origin[2]+= 28; // DEFAULT_VIEWHEIGHT +} + +void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) +{ + vec3_t forward; + vec3_t zScaledTarget; + + VectorCopy(cl_angles, angles); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; + zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; + zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); + + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); +} + +void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) +{ + vec3_t forward; + + if ( target ) + { + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + // this is done to get the angles made by director mode + V_GetChasePos(target, cl_angles, origin, angles); + VectorCopy(ent->origin, origin); + + // keep fix chase angle horizontal + angles[0] = 45.0f; + } + else + { + VectorCopy(cl_angles, angles); + VectorCopy(ent->origin, origin); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + } + else + { + // keep out roaming position, but modify angles + VectorCopy(cl_angles, angles); + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + + origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); + angles[2] = 0.0f; // don't roll angle (if chased player is dead) + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(origin, -1536, forward, origin); +} + +int V_FindViewModelByWeaponModel(int weaponindex) +{ + + static char * modelmap[][2] = { + { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, + { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, + { "models/p_egon.mdl", "models/v_egon.mdl" }, + { "models/p_gauss.mdl", "models/v_gauss.mdl" }, + { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, + { "models/p_grenade.mdl", "models/v_grenade.mdl" }, + { "models/p_hgun.mdl", "models/v_hgun.mdl" }, + { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, + { "models/p_357.mdl", "models/v_357.mdl" }, + { "models/p_rpg.mdl", "models/v_rpg.mdl" }, + { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, + { "models/p_squeak.mdl", "models/v_squeak.mdl" }, + { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, + { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, + { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { NULL, NULL } }; + + struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); + + if ( weaponModel ) + { + int len = strlen( weaponModel->name ); + int i = 0; + + while ( modelmap[i][0] != NULL ) + { + if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) + { + return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); + } + i++; + } + + return 0; + } + else + return 0; + +} + + +/* +================== +V_CalcSpectatorRefdef + +================== +*/ +void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) +{ + static vec3_t velocity ( 0.0f, 0.0f, 0.0f); + + static int lastWeaponModelIndex = 0; + static int lastViewModelIndex = 0; + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + + pparams->onlyClientDraw = false; + + // refresh position + VectorCopy ( pparams->simorg, v_sim_org ); + + // get old values + VectorCopy ( pparams->cl_viewangles, v_cl_angles ); + VectorCopy ( pparams->viewangles, v_angles ); + VectorCopy ( pparams->vieworg, v_origin ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) + { + // calculate player velocity + float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; + + if ( timeDiff > 0 ) + { + vec3_t distance; + VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); + VectorScale(distance, 1/timeDiff, distance ); + + velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; + velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; + velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; + + VectorCopy(velocity, pparams->simvel); + } + + // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) + if ( gEngfuncs.IsSpectateOnly() ) + { + V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); + + pparams->health = 1; + + cl_entity_t * gunModel = gEngfuncs.GetViewModel(); + + if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) + { + // weapon model changed + + lastWeaponModelIndex = ent->curstate.weaponmodel; + lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); + if ( lastViewModelIndex ) + { + gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation + } + else + { + // model not found + gunModel->model = NULL; // disable weapon model + lastWeaponModelIndex = lastViewModelIndex = 0; + } + } + + if ( lastViewModelIndex ) + { + gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); + gunModel->curstate.modelindex = lastViewModelIndex; + gunModel->curstate.frame = 0; + gunModel->curstate.colormap = 0; + gunModel->index = g_iUser2; + } + else + { + gunModel->model = NULL; // disable weaopn model + } + } + else + { + // only get viewangles from entity + VectorCopy ( ent->angles, pparams->cl_viewangles ); + pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + } + } + + v_frametime = pparams->frametime; + + if ( pparams->nextView == 0 ) + { + // first renderer cycle, full screen + + switch ( g_iUser1 ) + { + case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + break; + + case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case OBS_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case OBS_MAP_CHASE : pparams->onlyClientDraw = true; + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + } + + if ( gHUD.m_Spectator.m_pip->value ) + pparams->nextView = 1; // force a second renderer view + + gHUD.m_Spectator.m_iDrawCycle = 0; + + } + else + { + // second renderer cycle, inset window + + // set inset parameters + pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window + pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); + pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); + pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); + pparams->nextView = 0; // on further view + + // override some settings in certain modes + switch ( (int)gHUD.m_Spectator.m_pip->value ) + { + case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case INSET_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case INSET_MAP_CHASE : pparams->onlyClientDraw = true; + + if ( g_iUser1 == OBS_ROAMING ) + V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); + else + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + + break; + } + + gHUD.m_Spectator.m_iDrawCycle = 1; + } + + // write back new values into pparams + VectorCopy ( v_cl_angles, pparams->cl_viewangles ); + VectorCopy ( v_angles, pparams->viewangles ) + VectorCopy ( v_origin, pparams->vieworg ); + +} + + + +void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) +{ + // intermission / finale rendering + if ( pparams->intermission ) + { + V_CalcIntermissionRefdef ( pparams ); + } + else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode + { + V_CalcSpectatorRefdef ( pparams ); + } + else if ( !pparams->paused ) + { + V_CalcNormalRefdef ( pparams ); + } + +/* +// Example of how to overlay the whole screen with red at 50 % alpha +#define SF_TEST +#if defined SF_TEST + { + screenfade_t sf; + gEngfuncs.pfnGetScreenFade( &sf ); + + sf.fader = 255; + sf.fadeg = 0; + sf.fadeb = 0; + sf.fadealpha = 128; + sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; + + gEngfuncs.pfnSetScreenFade( &sf ); + } +#endif +*/ +} + +/* +============= +V_DropPunchAngle + +============= +*/ +void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +{ + float len; + + len = VectorNormalize ( ev_punchangle ); + len -= (10.0 + len * 0.5) * frametime; + len = max( len, 0.0 ); + VectorScale ( ev_punchangle, len, ev_punchangle ); +} + +/* +============= +V_PunchAxis + +Client side punch effect +============= +*/ +void V_PunchAxis( int axis, float punch ) +{ + ev_punchangle[ axis ] = punch; +} + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); + + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); + cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); +} + + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern float in_fov; +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + fov_x = 90; // error, set to 90 + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; + + return a; +} + +int hitent = -1; + +void V_Move( int mx, int my ) +{ + float fov; + float fx, fy; + float dx, dy; + float c_x, c_y; + float dX, dY; + vec3_t forward, up, right; + vec3_t newangles; + + vec3_t farpoint; + pmtrace_t tr; + + fov = CalcFov( in_fov, (float)ScreenWidth, (float)ScreenHeight ); + + c_x = (float)ScreenWidth / 2.0; + c_y = (float)ScreenHeight / 2.0; + + dx = (float)mx - c_x; + dy = (float)my - c_y; + + // Proportion we moved in each direction + fx = dx / c_x; + fy = dy / c_y; + + dX = fx * in_fov / 2.0 ; + dY = fy * fov / 2.0; + + newangles = v_angles; + + newangles[ YAW ] -= dX; + newangles[ PITCH ] += dY; + + // Now rotate v_forward around that point + AngleVectors ( newangles, forward, right, up ); + + farpoint = v_origin + 8192 * forward; + + // Trace + tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + if ( tr.fraction != 1.0 && tr.ent != 0 ) + { + hitent = PM_GetPhysEntInfo( tr.ent ); + PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); + } + else + { + hitent = -1; + } +} + +#endif diff --git a/cl_dll/view.h b/cl_dll/view.h index acd0bfb0..1afbe38e 100644 --- a/cl_dll/view.h +++ b/cl_dll/view.h @@ -1,15 +1,15 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined ( VIEWH ) -#define VIEWH -#pragma once - -void V_StartPitchDrift( void ); -void V_StopPitchDrift( void ); - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( VIEWH ) +#define VIEWH +#pragma once + +void V_StartPitchDrift( void ); +void V_StopPitchDrift( void ); + #endif // !VIEWH \ No newline at end of file diff --git a/common/beamdef.h b/common/beamdef.h index ebb2a525..3b8c553a 100644 --- a/common/beamdef.h +++ b/common/beamdef.h @@ -1,60 +1,60 @@ -/*** -* -* 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 BEAMDEF_H -#define BEAMDEF_H - -#define FBEAM_STARTENTITY 0x00000001 -#define FBEAM_ENDENTITY 0x00000002 -#define FBEAM_FADEIN 0x00000004 -#define FBEAM_FADEOUT 0x00000008 -#define FBEAM_SINENOISE 0x00000010 -#define FBEAM_SOLID 0x00000020 -#define FBEAM_SHADEIN 0x00000040 -#define FBEAM_SHADEOUT 0x00000080 -#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? -#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? -#define FBEAM_ISACTIVE 0x40000000 -#define FBEAM_FOREVER 0x80000000 - -typedef struct beam_s BEAM; -struct beam_s -{ - BEAM *next; - int type; - int flags; - vec3_t source; - vec3_t target; - vec3_t delta; - float t; // 0 .. 1 over lifetime of beam - float freq; - float die; - float width; - float amplitude; - float r, g, b; - float brightness; - float speed; - float frameRate; - float frame; - int segments; - int startEntity; - int endEntity; - int modelIndex; - int frameCount; - struct model_s *pFollowModel; - struct particle_s *particles; -}; - +/*** +* +* 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 BEAMDEF_H +#define BEAMDEF_H + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +typedef struct beam_s BEAM; +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + #endif//BEAMDEF_H \ No newline at end of file diff --git a/common/bspfile.h b/common/bspfile.h index c06eae6a..51452cd6 100644 --- a/common/bspfile.h +++ b/common/bspfile.h @@ -1,246 +1,246 @@ -/* -bspfile.h - BSP format included q1, hl1 support -Copyright (C) 2010 Uncle Mike - -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. -*/ - -#ifndef BSPFILE_H -#define BSPFILE_H - -/* -============================================================================== - -BRUSH MODELS - -.bsp contain level static geometry with including PVS and lightning info -============================================================================== -*/ - -// header -#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28) -#define HLBSP_VERSION 30 // half-life regular version -#define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit - -#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH" -#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT - -#define DELUXEMAP_VERSION 1 -#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT" - -// worldcraft predefined angles -#define ANGLE_UP -1 -#define ANGLE_DOWN -2 - -// bmodel limits -#define MAX_MAP_HULLS 4 // MAX_HULLS - -#define SURF_NOCULL BIT( 0 ) // two-sided polygon (e.g. 'water4b') -#define SURF_PLANEBACK BIT( 1 ) // plane should be negated -#define SURF_DRAWSKY BIT( 2 ) // sky surface -#define SURF_WATERCSG BIT( 3 ) // culled by csg (was SURF_DRAWSPRITE) -#define SURF_DRAWTURB BIT( 4 ) // warp surface -#define SURF_DRAWTILED BIT( 5 ) // face without lighmap -#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND) -#define SURF_UNDERWATER BIT( 7 ) // caustics -#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP) - -#define SURF_REFLECT BIT( 31 ) // reflect surface (mirror) - -// lightstyle management -#define LM_STYLES 4 // MAXLIGHTMAPS -#define LS_NORMAL 0x00 -#define LS_UNUSED 0xFE -#define LS_NONE 0xFF - -#define MAX_MAP_MODELS 1024 // can be increased up to 2048 if needed -#define MAX_MAP_BRUSHES 32768 // unsigned short limit -#define MAX_MAP_ENTITIES 8192 // can be increased up to 32768 if needed -#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough -#define MAX_MAP_PLANES 65536 // can be increased without problems -#define MAX_MAP_NODES 32767 // because negative shorts are leafs -#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents -#define MAX_MAP_LEAFS 32767 // signed short limit -#define MAX_MAP_VERTS 65535 // unsigned short limit -#define MAX_MAP_FACES 65535 // unsigned short limit -#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit -#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo -#define MAX_MAP_EDGES 0x100000 // can be increased but not needed -#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed -#define MAX_MAP_TEXTURES 2048 // can be increased but not needed -#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data -#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps) -#define MAX_MAP_VISIBILITY 0x800000 // 8 Mb visdata - -// quake lump ordering -#define LUMP_ENTITIES 0 -#define LUMP_PLANES 1 -#define LUMP_TEXTURES 2 // internal textures -#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 // internal submodels -#define HEADER_LUMPS 15 - -// version 31 -#define LUMP_CLIPNODES2 15 // hull0 goes into LUMP_NODES, hull1 goes into LUMP_CLIPNODES, -#define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3 -#define HEADER_LUMPS_31 17 - -#define LUMP_FACES_EXTRADATA 0 // extension of dface_t -#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t -#define LUMP_CUBEMAPS 2 // cubemap description - -#define EXTRA_LUMPS 8 // g-cont. just for future expansions - -// texture flags -#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision - -// ambient sound types -enum -{ - AMBIENT_WATER = 0, // waterfall - AMBIENT_SKY, // wind - AMBIENT_SLIME, // never used in quake - AMBIENT_LAVA, // never used in quake - NUM_AMBIENTS, // automatic ambient sounds -}; - -// -// BSP File Structures -// - -typedef struct -{ - int fileofs; - int filelen; -} dlump_t; - -typedef struct -{ - int version; - dlump_t lumps[HEADER_LUMPS]; -} dheader_t; - -typedef struct -{ - int version; - dlump_t lumps[HEADER_LUMPS_31]; -} dheader31_t; - -typedef struct -{ - int id; // must be little endian XASH - int version; - dlump_t lumps[EXTRA_LUMPS]; -} dextrahdr_t; - -typedef struct -{ - vec3_t mins; - vec3_t maxs; - vec3_t origin; // for sounds or lights - int headnode[MAX_MAP_HULLS]; - int visleafs; // not including the solid leaf 0 - int firstface; - int numfaces; -} dmodel_t; - -typedef struct -{ - int nummiptex; - int dataofs[4]; // [nummiptex] -} dmiptexlump_t; - -typedef struct -{ - vec3_t point; -} dvertex_t; - -typedef struct -{ - vec3_t normal; - float dist; - int type; // PLANE_X - PLANE_ANYZ ? -} dplane_t; - -typedef struct -{ - int planenum; - short children[2]; // negative numbers are -(leafs + 1), not nodes - short mins[3]; // for sphere culling - short maxs[3]; - word firstface; - word numfaces; // counting both sides -} dnode_t; - -// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas -// all other leafs need visibility info -typedef struct -{ - int contents; - int visofs; // -1 = no visibility info - - short mins[3]; // for frustum culling - short maxs[3]; - word firstmarksurface; - word nummarksurfaces; - - // automatic ambient sounds - byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255) -} dleaf_t; - -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; - -typedef struct -{ - float vecs[2][4]; // texmatrix [s/t][xyz offset] - int miptex; - int flags; -} dtexinfo_t; - -typedef word dmarkface_t; // leaf marksurfaces indexes -typedef int dsurfedge_t; // map surfedges - -// NOTE: that edge 0 is never used, because negative edge nums -// are used for counterclockwise use of the edge in a face -typedef struct -{ - word v[2]; // vertex numbers -} dedge_t; - -typedef struct -{ - word planenum; - short side; - - int firstedge; // we must support > 64k edges - short numedges; - short texinfo; - - // lighting info - byte styles[LM_STYLES]; - int lightofs; // start of [numstyles*surfsize] samples -} dface_t; - +/* +bspfile.h - BSP format included q1, hl1 support +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef BSPFILE_H +#define BSPFILE_H + +/* +============================================================================== + +BRUSH MODELS + +.bsp contain level static geometry with including PVS and lightning info +============================================================================== +*/ + +// header +#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28) +#define HLBSP_VERSION 30 // half-life regular version +#define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit + +#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH" +#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT + +#define DELUXEMAP_VERSION 1 +#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT" + +// worldcraft predefined angles +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +// bmodel limits +#define MAX_MAP_HULLS 4 // MAX_HULLS + +#define SURF_NOCULL BIT( 0 ) // two-sided polygon (e.g. 'water4b') +#define SURF_PLANEBACK BIT( 1 ) // plane should be negated +#define SURF_DRAWSKY BIT( 2 ) // sky surface +#define SURF_WATERCSG BIT( 3 ) // culled by csg (was SURF_DRAWSPRITE) +#define SURF_DRAWTURB BIT( 4 ) // warp surface +#define SURF_DRAWTILED BIT( 5 ) // face without lighmap +#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND) +#define SURF_UNDERWATER BIT( 7 ) // caustics +#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP) + +#define SURF_REFLECT BIT( 31 ) // reflect surface (mirror) + +// lightstyle management +#define LM_STYLES 4 // MAXLIGHTMAPS +#define LS_NORMAL 0x00 +#define LS_UNUSED 0xFE +#define LS_NONE 0xFF + +#define MAX_MAP_MODELS 1024 // can be increased up to 2048 if needed +#define MAX_MAP_BRUSHES 32768 // unsigned short limit +#define MAX_MAP_ENTITIES 8192 // can be increased up to 32768 if needed +#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough +#define MAX_MAP_PLANES 65536 // can be increased without problems +#define MAX_MAP_NODES 32767 // because negative shorts are leafs +#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents +#define MAX_MAP_LEAFS 32767 // signed short limit +#define MAX_MAP_VERTS 65535 // unsigned short limit +#define MAX_MAP_FACES 65535 // unsigned short limit +#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit +#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo +#define MAX_MAP_EDGES 0x100000 // can be increased but not needed +#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed +#define MAX_MAP_TEXTURES 2048 // can be increased but not needed +#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data +#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps) +#define MAX_MAP_VISIBILITY 0x800000 // 8 Mb visdata + +// quake lump ordering +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 // internal textures +#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 // internal submodels +#define HEADER_LUMPS 15 + +// version 31 +#define LUMP_CLIPNODES2 15 // hull0 goes into LUMP_NODES, hull1 goes into LUMP_CLIPNODES, +#define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3 +#define HEADER_LUMPS_31 17 + +#define LUMP_FACES_EXTRADATA 0 // extension of dface_t +#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t +#define LUMP_CUBEMAPS 2 // cubemap description + +#define EXTRA_LUMPS 8 // g-cont. just for future expansions + +// texture flags +#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision + +// ambient sound types +enum +{ + AMBIENT_WATER = 0, // waterfall + AMBIENT_SKY, // wind + AMBIENT_SLIME, // never used in quake + AMBIENT_LAVA, // never used in quake + NUM_AMBIENTS, // automatic ambient sounds +}; + +// +// BSP File Structures +// + +typedef struct +{ + int fileofs; + int filelen; +} dlump_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + int version; + dlump_t lumps[HEADER_LUMPS_31]; +} dheader31_t; + +typedef struct +{ + int id; // must be little endian XASH + int version; + dlump_t lumps[EXTRA_LUMPS]; +} dextrahdr_t; + +typedef struct +{ + vec3_t mins; + vec3_t maxs; + vec3_t origin; // for sounds or lights + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface; + int numfaces; +} dmodel_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +typedef struct +{ + vec3_t point; +} dvertex_t; + +typedef struct +{ + vec3_t normal; + float dist; + int type; // PLANE_X - PLANE_ANYZ ? +} dplane_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs + 1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + word firstface; + word numfaces; // counting both sides +} dnode_t; + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + word firstmarksurface; + word nummarksurfaces; + + // automatic ambient sounds + byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255) +} dleaf_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +typedef struct +{ + float vecs[2][4]; // texmatrix [s/t][xyz offset] + int miptex; + int flags; +} dtexinfo_t; + +typedef word dmarkface_t; // leaf marksurfaces indexes +typedef int dsurfedge_t; // map surfedges + +// NOTE: that edge 0 is never used, because negative edge nums +// are used for counterclockwise use of the edge in a face +typedef struct +{ + word v[2]; // vertex numbers +} dedge_t; + +typedef struct +{ + word planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + + // lighting info + byte styles[LM_STYLES]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + #endif//BSPFILE_H \ No newline at end of file diff --git a/common/cl_entity.h b/common/cl_entity.h index 533106b8..02f84e35 100644 --- a/common/cl_entity.h +++ b/common/cl_entity.h @@ -1,105 +1,105 @@ -/*** -* -* 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 CL_ENTITY_H -#define CL_ENTITY_H - -typedef struct efrag_s -{ - struct mleaf_s *leaf; - struct efrag_s *leafnext; - struct cl_entity_s *entity; - struct efrag_s *entnext; -} efrag_t; - -typedef struct -{ - byte mouthopen; // 0 = mouth closed, 255 = mouth agape - byte sndcount; // counter for running average - int sndavg; // running average -} mouth_t; - -typedef struct -{ - float prevanimtime; - float sequencetime; - byte prevseqblending[2]; - vec3_t prevorigin; - vec3_t prevangles; - - int prevsequence; - float prevframe; - - byte prevcontroller[4]; - byte prevblending[2]; -} latchedvars_t; - -typedef struct -{ - // Time stamp for this movement - float animtime; - - vec3_t origin; - vec3_t angles; -} position_history_t; - -typedef struct cl_entity_s cl_entity_t; - -#define HISTORY_MAX 64 // Must be power of 2 -#define HISTORY_MASK ( HISTORY_MAX - 1 ) - -#include "entity_state.h" -#include "event_args.h" - -struct cl_entity_s -{ - int index; // Index into cl_entities ( should match actual slot, but not necessarily ) - qboolean player; // True if this entity is a "player" - - entity_state_t baseline; // The original state from which to delta during an uncompressed message - entity_state_t prevstate; // The state information from the penultimate message received from the server - entity_state_t curstate; // The state information from the last message received from server - - int current_position; // Last received history update index - position_history_t ph[HISTORY_MAX]; // History of position and angle updates for this player - - mouth_t mouth; // For synchronizing mouth movements. - - latchedvars_t latched; // Variables used by studio model rendering routines - - // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. - // - float lastmove; - - // Actual render position and angles - vec3_t origin; - vec3_t angles; - - // Attachment points - vec3_t attachment[4]; - - // Other entity local information - int trivial_accept; - - struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model - struct efrag_s *efrag; // linked list of efrags - struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split - - float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? - int visframe; // last frame this entity was found in an active leaf - colorVec cvFloorColor; -}; - +/*** +* +* 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 CL_ENTITY_H +#define CL_ENTITY_H + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + +#include "entity_state.h" +#include "event_args.h" + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[HISTORY_MAX]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + #endif//CL_ENTITY_H \ No newline at end of file diff --git a/common/com_model.h b/common/com_model.h index 7ad79c91..709f23d9 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -1,413 +1,413 @@ -/* -com_model.h - cient model structures -Copyright (C) 2010 Uncle Mike - -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. -*/ - -#ifndef COM_MODEL_H -#define COM_MODEL_H - -#include "bspfile.h" // we need some declarations from it - -typedef vec_t vec2_t[2]; -typedef vec_t vec4_t[4]; - -/* -============================================================================== - - ENGINE MODEL FORMAT -============================================================================== -*/ -#define STUDIO_RENDER 1 -#define STUDIO_EVENTS 2 - -#define ZISCALE ((float)0x8000) - -#define MIPLEVELS 4 -#define VERTEXSIZE 7 -#define MAXLIGHTMAPS 4 -#define NUM_AMBIENTS 4 // automatic ambient sounds - -// model types -typedef enum -{ - mod_bad = -1, - mod_brush, - mod_sprite, - mod_alias, - mod_studio -} modtype_t; - -typedef struct mplane_s -{ - vec3_t normal; - float dist; - byte type; // for 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 int width, height; - int gl_texturenum; - struct msurface_s *texturechain; // for gl_texsort drawing - 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 short fb_texturenum; // auto-luma texturenum - unsigned short dt_texturenum; // detail-texture binding - unsigned int unused[3]; // reserved -} 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; - -// 73 bytes per VBO vertex -// FIXME: align to 32 bytes -typedef struct glvert_s -{ - vec3_t vertex; // position - vec3_t normal; // normal - vec2_t stcoord; // ST texture coords - vec2_t lmcoord; // ST lightmap coords - vec2_t sccoord; // ST scissor coords (decals only) - for normalmap coords migration - vec3_t tangent; // tangent - vec3_t binormal; // binormal - byte color[4]; // colors per vertex -} glvert_t; - -typedef struct glpoly_s -{ - struct glpoly_s *next; - struct glpoly_s *chain; - int numverts; - int flags; // for SURF_UNDERWATER - float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) -} glpoly_t; - -typedef struct mnode_s -{ -// common with leaf - int contents; // 0, to differentiate from leafs - int visframe; // node needs to be traversed if current - - float 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 - float dx; // local texture coordinates - float dy; // - float scale; // Pixel scale - short texture; // Decal texture - byte flags; // Decal flags FDECAL_* - short entityIndex; // Entity this is attached to -// Xash3D added - vec3_t position; // location of the decal center in world space. - vec3_t saxis; // direction of the s axis in world space - struct msurfmesh_s *mesh; // decal mesh in local space - int reserved[4]; // for future expansions -}; - -typedef struct mleaf_s -{ -// common with node - int contents; - int visframe; // node needs to be traversed if current - - float minmaxs[6]; // for bounding box culling - - struct mnode_s *parent; -// leaf specific - byte *compressed_vis; - struct efrag_s *efrags; - - msurface_t **firstmarksurface; - int nummarksurfaces; - byte *compressed_pas; - byte ambient_sound_level[NUM_AMBIENTS]; - -} mleaf_t; - -typedef struct msurface_s -{ - int visframe; // should be drawn when node is crossed - - 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 - - short texturemins[2]; - short extents[2]; - - int light_s, light_t; // gl lightmap coordinates - - glpoly_t *polys; // multiple if warped - struct msurface_s *texturechain; - - mtexinfo_t *texinfo; - - // lighting info - 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. - - int lightmaptexturenum; - byte styles[MAXLIGHTMAPS]; - int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap - struct msurface_s *lightmapchain; // for new dlights rendering (was cached_dlight) - - color24 *samples; // note: this is the actual lightmap data for this surface - decal_t *pdecals; -} msurface_t; - -typedef struct msurfmesh_s -{ - unsigned short numVerts; - unsigned short numElems; // ~ 20 000 vertex per one surface. Should be enough - unsigned int startVert; // user-variable. may be used for construct world single-VBO - unsigned int startElem; // user-variable. may be used for construct world single-VBO - - glvert_t *verts; // vertexes array - unsigned short *elems; // indices - - struct msurface_s *surf; // pointer to parent surface. Just for consistency - struct msurfmesh_s *next; // temporary chain of subdivided surfaces -} msurfmesh_t; - -// surface extradata stored in cache.data for all brushmodels -typedef struct mextrasurf_s -{ - vec3_t mins, maxs; - vec3_t origin; // surface origin - msurfmesh_t *mesh; // VBO\VA ready surface mesh. Not used by engine but can be used by mod-makers - - int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps - - int mirrortexturenum; // gl texnum - float mirrormatrix[4][4]; - struct mextrasurf_s *mirrorchain; // for gl_texsort drawing - struct mextrasurf_s *detailchain; // for detail textures drawing - color24 *deluxemap; // note: this is the actual deluxemap data for this surface - - int reserved[32]; // just for future expansions or mod-makers -} mextrasurf_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; - -#ifndef CACHE_USER -#define CACHE_USER -typedef struct cache_user_s -{ - void *data; // extradata -} cache_user_t; -#endif - -typedef struct model_s -{ - char name[64]; // model name - qboolean needload; // bmodels and sprites don't cache normally - - // shared modelinfo - modtype_t type; // model type - int numframes; // sprite's framecount - byte *mempool; // private mempool (was synctype) - int flags; // hl compatibility - -// -// volume occupied by the model -// - vec3_t mins, maxs; // bounding box at angles '0 0 0' - float radius; - - // brush model - int firstmodelsurface; - int nummodelsurfaces; - - int numsubmodels; - dmodel_t *submodels; // or studio animations - - int numplanes; - mplane_t *planes; - - int numleafs; // number of visible leafs, not counting 0 - mleaf_t *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 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; - -#define MAX_SCOREBOARDNAME 32 -#define MAX_INFO_STRING 256 - -#include "custom.h" - -typedef struct player_info_s -{ - int userid; // User id on server - char userinfo[MAX_INFO_STRING]; // User info string - char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) - int spectator; // Spectator or not, unused - - int ping; - int packet_loss; - - // skin information - char model[64]; - 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; - -// -// sprite representation in memory -// -typedef enum { SPR_SINGLE = 0, SPR_GROUP, SPR_ANGLED } spriteframetype_t; - -typedef struct mspriteframe_s -{ - int width; - int height; - float up, down, left, right; - int gl_texturenum; -} mspriteframe_t; - -typedef struct -{ - int numframes; - float *intervals; - mspriteframe_t *frames[1]; -} mspritegroup_t; - -typedef struct -{ - spriteframetype_t type; - mspriteframe_t *frameptr; -} mspriteframedesc_t; - -typedef struct -{ - short type; - short texFormat; - int maxwidth; - int maxheight; - int numframes; - int radius; - int facecull; - int synctype; - mspriteframedesc_t frames[1]; -} msprite_t; - +/* +com_model.h - cient model structures +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef COM_MODEL_H +#define COM_MODEL_H + +#include "bspfile.h" // we need some declarations from it + +typedef vec_t vec2_t[2]; +typedef vec_t vec4_t[4]; + +/* +============================================================================== + + ENGINE MODEL FORMAT +============================================================================== +*/ +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +#define ZISCALE ((float)0x8000) + +#define MIPLEVELS 4 +#define VERTEXSIZE 7 +#define MAXLIGHTMAPS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// model types +typedef enum +{ + mod_bad = -1, + mod_brush, + mod_sprite, + mod_alias, + mod_studio +} modtype_t; + +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for 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 int width, height; + int gl_texturenum; + struct msurface_s *texturechain; // for gl_texsort drawing + 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 short fb_texturenum; // auto-luma texturenum + unsigned short dt_texturenum; // detail-texture binding + unsigned int unused[3]; // reserved +} 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; + +// 73 bytes per VBO vertex +// FIXME: align to 32 bytes +typedef struct glvert_s +{ + vec3_t vertex; // position + vec3_t normal; // normal + vec2_t stcoord; // ST texture coords + vec2_t lmcoord; // ST lightmap coords + vec2_t sccoord; // ST scissor coords (decals only) - for normalmap coords migration + vec3_t tangent; // tangent + vec3_t binormal; // binormal + byte color[4]; // colors per vertex +} glvert_t; + +typedef struct glpoly_s +{ + struct glpoly_s *next; + struct glpoly_s *chain; + int numverts; + int flags; // for SURF_UNDERWATER + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} glpoly_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float 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 + float dx; // local texture coordinates + float dy; // + float scale; // Pixel scale + short texture; // Decal texture + byte flags; // Decal flags FDECAL_* + short entityIndex; // Entity this is attached to +// Xash3D added + vec3_t position; // location of the decal center in world space. + vec3_t saxis; // direction of the s axis in world space + struct msurfmesh_s *mesh; // decal mesh in local space + int reserved[4]; // for future expansions +}; + +typedef struct mleaf_s +{ +// common with node + int contents; + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; +// leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + byte *compressed_pas; + byte ambient_sound_level[NUM_AMBIENTS]; + +} mleaf_t; + +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + 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 + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + + mtexinfo_t *texinfo; + + // lighting info + 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. + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + struct msurface_s *lightmapchain; // for new dlights rendering (was cached_dlight) + + color24 *samples; // note: this is the actual lightmap data for this surface + decal_t *pdecals; +} msurface_t; + +typedef struct msurfmesh_s +{ + unsigned short numVerts; + unsigned short numElems; // ~ 20 000 vertex per one surface. Should be enough + unsigned int startVert; // user-variable. may be used for construct world single-VBO + unsigned int startElem; // user-variable. may be used for construct world single-VBO + + glvert_t *verts; // vertexes array + unsigned short *elems; // indices + + struct msurface_s *surf; // pointer to parent surface. Just for consistency + struct msurfmesh_s *next; // temporary chain of subdivided surfaces +} msurfmesh_t; + +// surface extradata stored in cache.data for all brushmodels +typedef struct mextrasurf_s +{ + vec3_t mins, maxs; + vec3_t origin; // surface origin + msurfmesh_t *mesh; // VBO\VA ready surface mesh. Not used by engine but can be used by mod-makers + + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + int mirrortexturenum; // gl texnum + float mirrormatrix[4][4]; + struct mextrasurf_s *mirrorchain; // for gl_texsort drawing + struct mextrasurf_s *detailchain; // for detail textures drawing + color24 *deluxemap; // note: this is the actual deluxemap data for this surface + + int reserved[32]; // just for future expansions or mod-makers +} mextrasurf_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; + +#ifndef CACHE_USER +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; // extradata +} cache_user_t; +#endif + +typedef struct model_s +{ + char name[64]; // model name + qboolean needload; // bmodels and sprites don't cache normally + + // shared modelinfo + modtype_t type; // model type + int numframes; // sprite's framecount + byte *mempool; // private mempool (was synctype) + int flags; // hl compatibility + +// +// volume occupied by the model +// + vec3_t mins, maxs; // bounding box at angles '0 0 0' + float radius; + + // brush model + int firstmodelsurface; + int nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; // or studio animations + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *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 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; + +#define MAX_SCOREBOARDNAME 32 +#define MAX_INFO_STRING 256 + +#include "custom.h" + +typedef struct player_info_s +{ + int userid; // User id on server + char userinfo[MAX_INFO_STRING]; // User info string + char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) + int spectator; // Spectator or not, unused + + int ping; + int packet_loss; + + // skin information + char model[64]; + 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; + +// +// sprite representation in memory +// +typedef enum { SPR_SINGLE = 0, SPR_GROUP, SPR_ANGLED } spriteframetype_t; + +typedef struct mspriteframe_s +{ + int width; + int height; + float up, down, left, right; + int gl_texturenum; +} mspriteframe_t; + +typedef struct +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +typedef struct +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +typedef struct +{ + short type; + short texFormat; + int maxwidth; + int maxheight; + int numframes; + int radius; + int facecull; + int synctype; + mspriteframedesc_t frames[1]; +} msprite_t; + #endif//COM_MODEL_H \ No newline at end of file diff --git a/common/con_nprint.h b/common/con_nprint.h index a0371933..5d87c760 100644 --- a/common/con_nprint.h +++ b/common/con_nprint.h @@ -1,25 +1,25 @@ -/*** -* -* 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 CON_NPRINT_H -#define CON_NPRINT_H - -typedef struct con_nprint_s -{ - int index; // Row # - float time_to_live; // # of seconds before it dissappears - float color[3]; // RGB colors ( 0.0 -> 1.0 scale ) -} con_nprint_t; - +/*** +* +* 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 CON_NPRINT_H +#define CON_NPRINT_H + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[3]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + #endif//CON_NPRINT_H \ No newline at end of file diff --git a/common/const.h b/common/const.h index 846dfe85..28a31a3f 100644 --- a/common/const.h +++ b/common/const.h @@ -1,780 +1,780 @@ -/*** -* -* 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 CONST_H -#define CONST_H -// -// Constants shared by the engine and dlls -// This header file included by engine files and DLL files. -// Most came from server.h - -// edict->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_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 -#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water -#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection - -// UNDONE: Do we need these? -#define FL_IMMUNE_WATER (1<<17) -#define FL_IMMUNE_SLIME (1<<18) -#define FL_IMMUNE_LAVA (1<<19) - -#define FL_PROXY (1<<20) // This is a spectator proxy -#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) -#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) -#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_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 - -// Goes into globalvars_t.trace_flags -#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box -#define FTRACE_IGNORE_GLASS (1<<1) // traceline will be ignored entities with rendermode != kRenderNormal - -// 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 - -// 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_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_COMPOUND 14 // glue two entities together (simple movewith) - -// 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_CUSTOM 5 // call external callbacks for tracing - -// 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_RESPAWNABLE 3 -#define DEAD_DISCARDBODY 4 - -#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_INVLIGHT 16 // get lighting from ceiling -#define EF_NOINTERP 32 // don't interpolate the next frame -#define EF_LIGHT 64 // rocket flare glow sprite -#define EF_NODRAW 128 // don't draw entity - - - -#define EF_NOREFLECT (1<<24) // Entity won't reflecting in mirrors -#define EF_REFLECTONLY (1<<25) // Entity will be drawing only in mirrors -#define EF_NOWATERCSG (1<<26) // Do not remove sides for func_water entity -#define EF_FULLBRIGHT (1<<27) // Just get fullbright -#define EF_NOSHADOW (1<<28) // ignore shadow for this entity -#define EF_MERGE_VISIBILITY (1<<29) // this entity allowed to merge vis (e.g. env_sky or portal camera) -#define EF_REQUEST_PHS (1<<30) // This entity requested phs bitvector instead of pvsbitvector in AddToFullPack calls -// g-cont. one reserved bit here for me - -// entity flags -#define EFLAG_SLERP 1 // do studio interpolation of this entity - -// -// temp entity events -// -#define TE_BEAMPOINTS 0 // beam effect between two points -// coord coord coord (start position) -// coord coord coord (end position) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMENTPOINT 1 // beam effect between point and entity -// short (start entity) -// coord coord coord (end position) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#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 -// coord coord coord (position) -// short (sprite index) -// byte (scale in 0.1's) -// byte (framerate) -// byte (flags) -// -// The Explosion effect has some flags to control performance/aesthetic features: -#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion -#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) -#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights -#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound -#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles -#define TE_EXPLFLAG_DRAWALPHA 16 // sprite will be drawn alpha -#define TE_EXPLFLAG_ROTATE 32 // rotate the sprite randomly - -#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound -// coord coord coord (position) - -#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 -// coord, coord, coord (start) -// coord, coord, coord (end) - -#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters -// coord, coord, coord (start) -// coord, coord, coord (end) -// byte (life in 0.1's) -// byte (width in 0.1's) -// byte (amplitude in 0.01's) -// short (sprite model index) - -#define TE_BEAMENTS 8 -// short (start entity) -// short (end entity) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite -// coord coord coord (position) - -#define TE_LAVASPLASH 10 // Quake1 lava splash -// coord coord coord (position) - -#define TE_TELEPORT 11 // Quake1 teleport splash -// coord coord coord (position) - -#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound -// coord coord coord (position) -// byte (starting color) -// byte (num colors) - -#define TE_BSPDECAL 13 // Decal from the .BSP file -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// short (texture index of precached decal texture name) -// short (entity index) -// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) - -#define TE_IMPLOSION 14 // tracers moving toward a point -// coord, coord, coord (position) -// byte (radius) -// byte (count) -// byte (life in 0.1's) - -#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions -// coord, coord, coord (start) -// coord, coord, coord (end) -// short (sprite index) -// byte (count) -// byte (life in 0.1's) -// byte (scale in 0.1's) -// byte (velocity along vector in 10's) -// byte (randomness of velocity in 10's) - -#define TE_BEAM 16 // obsolete - -#define TE_SPRITE 17 // additive sprite, plays 1 cycle -// coord, coord, coord (position) -// short (sprite index) -// byte (scale in 0.1's) -// byte (brightness) - -#define TE_BEAMSPRITE 18 // A beam with a sprite at the end -// coord, coord, coord (start position) -// coord, coord, coord (end position) -// short (beam sprite index) -// short (end sprite index) - -#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime -// coord coord coord (center position) -// coord coord coord (axis and radius) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving -// short (entity:attachment to follow) -// short (sprite index) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte,byte,byte (color) -// byte (brightness) - -#define TE_GLOWSPRITE 23 -// coord, coord, coord (pos) short (model index) byte (scale / 10) - -#define TE_BEAMRING 24 // connect a beam ring to two entities -// short (start entity) -// short (end entity) -// short (sprite index) -// byte (starting frame) -// byte (frame rate in 0.1's) -// byte (life in 0.1's) -// byte (line width in 0.1's) -// byte (noise amplitude in 0.01's) -// byte,byte,byte (color) -// byte (brightness) -// byte (scroll speed in 0.1's) - -#define TE_STREAK_SPLASH 25 // oriented shower of tracers -// coord coord coord (start position) -// coord coord coord (direction vector) -// byte (color) -// short (count) -// short (base speed) -// short (random velocity) - -#define TE_BEAMHOSE 26 // obsolete - -#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect -// coord, coord, coord (pos) -// byte (radius in 10's) -// byte byte byte (color) -// byte (life in 10's) -// byte (decay rate in 10's) - -#define TE_ELIGHT 28 // point entity light, no world effect -// short (entity:attachment to follow) -// coord coord coord (initial position) -// coord (radius) -// byte byte byte (color) -// byte (life in 0.1's) -// coord (decay rate) - -#define TE_TEXTMESSAGE 29 -// short 1.2.13 x (-1 = center) -// short 1.2.13 y (-1 = center) -// byte Effect 0 = fade in/fade out -// 1 is flickery credits -// 2 is write out (training room) -// 4 bytes r,g,b,a color1 (text color) -// 4 bytes r,g,b,a color2 (effect color) -// ushort 8.8 fadein time -// ushort 8.8 fadeout time -// ushort 8.8 hold time -// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) -// string text message (512 chars max sz string) -#define TE_LINE 30 -// coord, coord, coord startpos -// coord, coord, coord endpos -// short life in 0.1 s -// 3 bytes r, g, b - -#define TE_BOX 31 -// coord, coord, coord boxmins -// coord, coord, coord boxmaxs -// short life in 0.1 s -// 3 bytes r, g, b - -#define TE_KILLBEAM 99 // kill all beams attached to entity -// short (entity) - -#define TE_LARGEFUNNEL 100 -// coord coord coord (funnel position) -// short (sprite index) -// short (flags) - -#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 -// coord coord coord (start position) -// coord coord coord (end position) - -#define TE_BLOOD 103 // particle spray -// coord coord coord (start position) -// coord coord coord (spray vector) -// byte (color) -// byte (speed) - -#define TE_DECAL 104 // Decal applied to a brush entity (not the world) -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name) -// short (entity index) - -#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards -// short (entity) -// short (sprite index) -// byte (density) - -#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// angle (initial yaw) -// short (model index) -// byte (bounce sound type) -// byte (life in 0.1's) - -#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set -// coord, coord, coord (origin) -// coord (velocity) -// short (model index) -// short (count) -// byte (life in 0.1's) - -#define TE_BREAKMODEL 108 // box of models or sprites -// coord, coord, coord (position) -// coord, coord, coord (size) -// coord, coord, coord (velocity) -// byte (random velocity in 10's) -// short (sprite or model index) -// byte (count) -// byte (life in 0.1 secs) -// byte (flags) - -#define TE_GUNSHOTDECAL 109 // decal and ricochet sound -// coord, coord, coord (position) -// short (entity index???) -// byte (decal???) - -#define TE_SPRITE_SPRAY 110 // spay of alpha sprites -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// short (sprite index) -// byte (count) -// byte (speed) -// byte (noise) - -#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. -// coord, coord, coord (position) -// byte (scale in 0.1's) - -#define TE_PLAYERDECAL 112 // ??? -// byte (playerindex) -// coord, coord, coord (position) -// short (entity???) -// byte (decal number???) -// [optional] short (model index???) - -#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards -// coord, coord, coord (min start position) -// coord, coord, coord (max start position) -// coord (float height) -// short (model index) -// byte (count) -// coord (speed) - -#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards -// coord, coord, coord (min start position) -// coord, coord, coord (max start position) -// coord (float height) -// short (model index) -// byte (count) -// coord (speed) - -#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) -// coord, coord, coord (position) -// short (sprite1 index) -// short (sprite2 index) -// byte (color) -// byte (scale) - -#define TE_WORLDDECAL 116 // Decal applied to the world brush -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name) - -#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name - 256) - -#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 -// coord, coord, coord (x,y,z), decal position (center of texture in world) -// byte (texture index of precached decal texture name - 256) -// short (entity index) - -#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) -// coord, coord, coord (position) -// coord, coord, coord (velocity) -// short (modelindex) -// byte (life) -// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). - -#define TE_SPRAY 120 // Throws a shower of sprites or models -// coord, coord, coord (position) -// coord, coord, coord (direction) -// short (modelindex) -// byte (count) -// byte (speed) -// byte (noise) -// byte (rendermode) - -#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) -// byte (playernum) -// short (sprite modelindex) -// byte (count) -// byte (variance) (0 = no variance in size) (10 = 10% variance in size) - -#define TE_PARTICLEBURST 122 // very similar to lavasplash. -// coord (origin) -// short (radius) -// byte (particle color) -// byte (duration * 10) (will be randomized a bit) - -#define TE_FIREFIELD 123 // makes a field of fire. -// coord (origin) -// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) -// short (modelindex) -// byte (count) -// byte (flags) -// byte (duration (in seconds) * 10) (will be randomized a bit) -// -// to keep network traffic low, this message has associated flags that fit into a byte: -#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate -#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) -#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. -#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque -#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. - -#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) -// byte (entity index of player) -// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) -// short (model index) -// short (life * 10 ); - -#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. -// byte (entity index of player) - -#define TE_MULTIGUNSHOT 126 // much more compact shotgun message -// This message is used to make a client approximate a 'spray' of gunfire. -// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is -// a good candidate for MULTIGUNSHOT use. (shotguns) -// -// NOTE: This effect makes the client do traces for each bullet, these client traces ignore -// entities that have studio models.Traces are 4096 long. -// -// coord (origin) -// coord (origin) -// coord (origin) -// coord (direction) -// coord (direction) -// coord (direction) -// coord (x noise * 100) -// coord (y noise * 100) -// byte (count) -// byte (bullethole decal texture index) - -#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. -// coord (origin) -// coord (origin) -// coord (origin) -// coord (velocity) -// coord (velocity) -// coord (velocity) -// byte ( life * 10 ) -// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) -// byte ( length * 10 ) - -#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 - -// 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 -// 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_TRANSLUCENT -15 - -#define CONTENTS_LADDER -16 - -#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_SLIME -4 -#define CONTENT_LAVA -5 -#define CONTENT_SKY -6 - -// channels -#define CHAN_AUTO 0 -#define CHAN_WEAPON 1 -#define CHAN_VOICE 2 -#define CHAN_ITEM 3 -#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 -#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). - -// attenuation values -#define ATTN_NONE 0 -#define ATTN_NORM (float)0.8 -#define ATTN_IDLE (float)2 -#define ATTN_STATIC (float)1.25 - -// pitch values -#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 - -// volume values -#define VOL_NORM 1.0 - -// plats -#define PLAT_LOW_TRIGGER 1 - -// Trains -#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 - -// buttons -#define IN_ATTACK (1<<0) -#define IN_JUMP (1<<1) -#define IN_DUCK (1<<2) -#define IN_FORWARD (1<<3) -#define IN_BACK (1<<4) -#define IN_USE (1<<5) -#define IN_CANCEL (1<<6) -#define IN_LEFT (1<<7) -#define IN_RIGHT (1<<8) -#define IN_MOVELEFT (1<<9) -#define IN_MOVERIGHT (1<<10) -#define IN_ATTACK2 (1<<11) -#define IN_RUN (1<<12) -#define IN_RELOAD (1<<13) -#define IN_ALT1 (1<<14) -#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down - -// Break Model Defines -#define BREAK_TYPEMASK 0x4F -#define BREAK_GLASS 0x01 -#define BREAK_METAL 0x02 -#define BREAK_FLESH 0x04 -#define BREAK_WOOD 0x08 -#define BREAK_SMOKE 0x10 -#define BREAK_TRANS 0x20 -#define BREAK_CONCRETE 0x40 -#define BREAK_2 0x80 - -// Colliding temp entity sounds -#define BOUNCE_GLASS BREAK_GLASS -#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_SHOTSHELL 0x80 - -// Temp entity bounce sound types -#define TE_BOUNCE_NULL 0 -#define TE_BOUNCE_SHELL 1 -#define TE_BOUNCE_SHOTSHELL 2 - -// Rendering constants -enum -{ - kRenderNormal, // src - kRenderTransColor, // c*a+dest*(1-a) - kRenderTransTexture, // src*a+dest*(1-a) - kRenderGlow, // src*a+dest -- No Z buffer checks - kRenderTransAlpha, // src*srca+dest*(1-srca) - kRenderTransAdd, // src*a+dest - kRenderWorldGlow, // Same as kRenderGlow but not fixed size in screen space -}; - -enum -{ - kRenderFxNone = 0, - kRenderFxPulseSlow, - kRenderFxPulseFast, - kRenderFxPulseSlowWide, - kRenderFxPulseFastWide, - kRenderFxFadeSlow, - kRenderFxFadeFast, - kRenderFxSolidSlow, - kRenderFxSolidFast, - kRenderFxStrobeSlow, - kRenderFxStrobeFast, - kRenderFxStrobeFaster, - kRenderFxFlickerSlow, - kRenderFxFlickerFast, - kRenderFxNoDissipation, - kRenderFxDistort, // Distort/scale/translate flicker - kRenderFxHologram, // kRenderFxDistort + distance fade - kRenderFxDeadPlayer, // kRenderAmt is the player index - kRenderFxExplode, // Scale up really big! - kRenderFxGlowShell, // Glowing Shell - kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) -}; - -typedef unsigned int func_t; -typedef unsigned int string_t; - -typedef unsigned char byte; -typedef unsigned short word; - -#undef true -#undef false - -#ifndef __cplusplus -typedef enum { false, true } qboolean; -#else -typedef int qboolean; -#endif - -typedef struct -{ - byte r, g, b; -} color24; - -typedef struct -{ - unsigned r, g, b, a; -} colorVec; - -typedef struct link_s -{ - struct link_s *prev, *next; -} link_t; - -typedef struct edict_s edict_t; - -typedef struct -{ - vec3_t normal; - float dist; -} plane_t; - -typedef struct -{ - 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 -} trace_t; - +/*** +* +* 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 CONST_H +#define CONST_H +// +// Constants shared by the engine and dlls +// This header file included by engine files and DLL files. +// Most came from server.h + +// edict->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_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 +#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water +#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection + +// UNDONE: Do we need these? +#define FL_IMMUNE_WATER (1<<17) +#define FL_IMMUNE_SLIME (1<<18) +#define FL_IMMUNE_LAVA (1<<19) + +#define FL_PROXY (1<<20) // This is a spectator proxy +#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#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_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 + +// Goes into globalvars_t.trace_flags +#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box +#define FTRACE_IGNORE_GLASS (1<<1) // traceline will be ignored entities with rendermode != kRenderNormal + +// 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 + +// 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_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_COMPOUND 14 // glue two entities together (simple movewith) + +// 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_CUSTOM 5 // call external callbacks for tracing + +// 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_RESPAWNABLE 3 +#define DEAD_DISCARDBODY 4 + +#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_INVLIGHT 16 // get lighting from ceiling +#define EF_NOINTERP 32 // don't interpolate the next frame +#define EF_LIGHT 64 // rocket flare glow sprite +#define EF_NODRAW 128 // don't draw entity + + + +#define EF_NOREFLECT (1<<24) // Entity won't reflecting in mirrors +#define EF_REFLECTONLY (1<<25) // Entity will be drawing only in mirrors +#define EF_NOWATERCSG (1<<26) // Do not remove sides for func_water entity +#define EF_FULLBRIGHT (1<<27) // Just get fullbright +#define EF_NOSHADOW (1<<28) // ignore shadow for this entity +#define EF_MERGE_VISIBILITY (1<<29) // this entity allowed to merge vis (e.g. env_sky or portal camera) +#define EF_REQUEST_PHS (1<<30) // This entity requested phs bitvector instead of pvsbitvector in AddToFullPack calls +// g-cont. one reserved bit here for me + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity + +// +// temp entity events +// +#define TE_BEAMPOINTS 0 // beam effect between two points +// coord coord coord (start position) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMENTPOINT 1 // beam effect between point and entity +// short (start entity) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#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 +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) +// byte (flags) +// +// The Explosion effect has some flags to control performance/aesthetic features: +#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles +#define TE_EXPLFLAG_DRAWALPHA 16 // sprite will be drawn alpha +#define TE_EXPLFLAG_ROTATE 32 // rotate the sprite randomly + +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +// coord coord coord (position) + +#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 +// coord, coord, coord (start) +// coord, coord, coord (end) + +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +// coord, coord, coord (start) +// coord, coord, coord (end) +// byte (life in 0.1's) +// byte (width in 0.1's) +// byte (amplitude in 0.01's) +// short (sprite model index) + +#define TE_BEAMENTS 8 +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +// coord coord coord (position) + +#define TE_LAVASPLASH 10 // Quake1 lava splash +// coord coord coord (position) + +#define TE_TELEPORT 11 // Quake1 teleport splash +// coord coord coord (position) + +#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound +// coord coord coord (position) +// byte (starting color) +// byte (num colors) + +#define TE_BSPDECAL 13 // Decal from the .BSP file +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// short (texture index of precached decal texture name) +// short (entity index) +// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) + +#define TE_IMPLOSION 14 // tracers moving toward a point +// coord, coord, coord (position) +// byte (radius) +// byte (count) +// byte (life in 0.1's) + +#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions +// coord, coord, coord (start) +// coord, coord, coord (end) +// short (sprite index) +// byte (count) +// byte (life in 0.1's) +// byte (scale in 0.1's) +// byte (velocity along vector in 10's) +// byte (randomness of velocity in 10's) + +#define TE_BEAM 16 // obsolete + +#define TE_SPRITE 17 // additive sprite, plays 1 cycle +// coord, coord, coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (brightness) + +#define TE_BEAMSPRITE 18 // A beam with a sprite at the end +// coord, coord, coord (start position) +// coord, coord, coord (end position) +// short (beam sprite index) +// short (end sprite index) + +#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving +// short (entity:attachment to follow) +// short (sprite index) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte,byte,byte (color) +// byte (brightness) + +#define TE_GLOWSPRITE 23 +// coord, coord, coord (pos) short (model index) byte (scale / 10) + +#define TE_BEAMRING 24 // connect a beam ring to two entities +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_STREAK_SPLASH 25 // oriented shower of tracers +// coord coord coord (start position) +// coord coord coord (direction vector) +// byte (color) +// short (count) +// short (base speed) +// short (random velocity) + +#define TE_BEAMHOSE 26 // obsolete + +#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect +// coord, coord, coord (pos) +// byte (radius in 10's) +// byte byte byte (color) +// byte (life in 10's) +// byte (decay rate in 10's) + +#define TE_ELIGHT 28 // point entity light, no world effect +// short (entity:attachment to follow) +// coord coord coord (initial position) +// coord (radius) +// byte byte byte (color) +// byte (life in 0.1's) +// coord (decay rate) + +#define TE_TEXTMESSAGE 29 +// short 1.2.13 x (-1 = center) +// short 1.2.13 y (-1 = center) +// byte Effect 0 = fade in/fade out +// 1 is flickery credits +// 2 is write out (training room) +// 4 bytes r,g,b,a color1 (text color) +// 4 bytes r,g,b,a color2 (effect color) +// ushort 8.8 fadein time +// ushort 8.8 fadeout time +// ushort 8.8 hold time +// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) +// string text message (512 chars max sz string) +#define TE_LINE 30 +// coord, coord, coord startpos +// coord, coord, coord endpos +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_BOX 31 +// coord, coord, coord boxmins +// coord, coord, coord boxmaxs +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_KILLBEAM 99 // kill all beams attached to entity +// short (entity) + +#define TE_LARGEFUNNEL 100 +// coord coord coord (funnel position) +// short (sprite index) +// short (flags) + +#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 +// coord coord coord (start position) +// coord coord coord (end position) + +#define TE_BLOOD 103 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_DECAL 104 // Decal applied to a brush entity (not the world) +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) +// short (entity index) + +#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards +// short (entity) +// short (sprite index) +// byte (density) + +#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// angle (initial yaw) +// short (model index) +// byte (bounce sound type) +// byte (life in 0.1's) + +#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set +// coord, coord, coord (origin) +// coord (velocity) +// short (model index) +// short (count) +// byte (life in 0.1's) + +#define TE_BREAKMODEL 108 // box of models or sprites +// coord, coord, coord (position) +// coord, coord, coord (size) +// coord, coord, coord (velocity) +// byte (random velocity in 10's) +// short (sprite or model index) +// byte (count) +// byte (life in 0.1 secs) +// byte (flags) + +#define TE_GUNSHOTDECAL 109 // decal and ricochet sound +// coord, coord, coord (position) +// short (entity index???) +// byte (decal???) + +#define TE_SPRITE_SPRAY 110 // spay of alpha sprites +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (sprite index) +// byte (count) +// byte (speed) +// byte (noise) + +#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. +// coord, coord, coord (position) +// byte (scale in 0.1's) + +#define TE_PLAYERDECAL 112 // ??? +// byte (playerindex) +// coord, coord, coord (position) +// short (entity???) +// byte (decal number???) +// [optional] short (model index???) + +#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) +// coord, coord, coord (position) +// short (sprite1 index) +// short (sprite2 index) +// byte (color) +// byte (scale) + +#define TE_WORLDDECAL 116 // Decal applied to the world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) + +#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) + +#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) +// short (entity index) + +#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (modelindex) +// byte (life) +// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). + +#define TE_SPRAY 120 // Throws a shower of sprites or models +// coord, coord, coord (position) +// coord, coord, coord (direction) +// short (modelindex) +// byte (count) +// byte (speed) +// byte (noise) +// byte (rendermode) + +#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) +// byte (playernum) +// short (sprite modelindex) +// byte (count) +// byte (variance) (0 = no variance in size) (10 = 10% variance in size) + +#define TE_PARTICLEBURST 122 // very similar to lavasplash. +// coord (origin) +// short (radius) +// byte (particle color) +// byte (duration * 10) (will be randomized a bit) + +#define TE_FIREFIELD 123 // makes a field of fire. +// coord (origin) +// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) +// short (modelindex) +// byte (count) +// byte (flags) +// byte (duration (in seconds) * 10) (will be randomized a bit) +// +// to keep network traffic low, this message has associated flags that fit into a byte: +#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate +#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) +#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. +#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque +#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. + +#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) +// byte (entity index of player) +// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) +// short (model index) +// short (life * 10 ); + +#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. +// byte (entity index of player) + +#define TE_MULTIGUNSHOT 126 // much more compact shotgun message +// This message is used to make a client approximate a 'spray' of gunfire. +// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is +// a good candidate for MULTIGUNSHOT use. (shotguns) +// +// NOTE: This effect makes the client do traces for each bullet, these client traces ignore +// entities that have studio models.Traces are 4096 long. +// +// coord (origin) +// coord (origin) +// coord (origin) +// coord (direction) +// coord (direction) +// coord (direction) +// coord (x noise * 100) +// coord (y noise * 100) +// byte (count) +// byte (bullethole decal texture index) + +#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. +// coord (origin) +// coord (origin) +// coord (origin) +// coord (velocity) +// coord (velocity) +// coord (velocity) +// byte ( life * 10 ) +// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) +// byte ( length * 10 ) + +#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 + +// 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 +// 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_TRANSLUCENT -15 + +#define CONTENTS_LADDER -16 + +#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_SLIME -4 +#define CONTENT_LAVA -5 +#define CONTENT_SKY -6 + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#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 +#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM (float)0.8 +#define ATTN_IDLE (float)2 +#define ATTN_STATIC (float)1.25 + +// pitch values +#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 + +// volume values +#define VOL_NORM 1.0 + +// plats +#define PLAT_LOW_TRIGGER 1 + +// Trains +#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 + +// buttons +#define IN_ATTACK (1<<0) +#define IN_JUMP (1<<1) +#define IN_DUCK (1<<2) +#define IN_FORWARD (1<<3) +#define IN_BACK (1<<4) +#define IN_USE (1<<5) +#define IN_CANCEL (1<<6) +#define IN_LEFT (1<<7) +#define IN_RIGHT (1<<8) +#define IN_MOVELEFT (1<<9) +#define IN_MOVERIGHT (1<<10) +#define IN_ATTACK2 (1<<11) +#define IN_RUN (1<<12) +#define IN_RELOAD (1<<13) +#define IN_ALT1 (1<<14) +#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down + +// Break Model Defines +#define BREAK_TYPEMASK 0x4F +#define BREAK_GLASS 0x01 +#define BREAK_METAL 0x02 +#define BREAK_FLESH 0x04 +#define BREAK_WOOD 0x08 +#define BREAK_SMOKE 0x10 +#define BREAK_TRANS 0x20 +#define BREAK_CONCRETE 0x40 +#define BREAK_2 0x80 + +// Colliding temp entity sounds +#define BOUNCE_GLASS BREAK_GLASS +#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_SHOTSHELL 0x80 + +// Temp entity bounce sound types +#define TE_BOUNCE_NULL 0 +#define TE_BOUNCE_SHELL 1 +#define TE_BOUNCE_SHOTSHELL 2 + +// Rendering constants +enum +{ + kRenderNormal, // src + kRenderTransColor, // c*a+dest*(1-a) + kRenderTransTexture, // src*a+dest*(1-a) + kRenderGlow, // src*a+dest -- No Z buffer checks + kRenderTransAlpha, // src*srca+dest*(1-srca) + kRenderTransAdd, // src*a+dest + kRenderWorldGlow, // Same as kRenderGlow but not fixed size in screen space +}; + +enum +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, // Distort/scale/translate flicker + kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! + kRenderFxGlowShell, // Glowing Shell + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) +}; + +typedef unsigned int func_t; +typedef unsigned int string_t; + +typedef unsigned char byte; +typedef unsigned short word; + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum { false, true } qboolean; +#else +typedef int qboolean; +#endif + +typedef struct +{ + byte r, g, b; +} color24; + +typedef struct +{ + unsigned r, g, b, a; +} colorVec; + +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + +typedef struct edict_s edict_t; + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + 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 +} trace_t; + #endif//CONST_H \ No newline at end of file diff --git a/common/cvardef.h b/common/cvardef.h index ee5588b6..f822cc7a 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -1,37 +1,37 @@ -/*** -* -* 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 - -typedef struct cvar_s -{ - char *name; - char *string; - int flags; - float value; - struct cvar_s *next; -} cvar_t; - +/*** +* +* 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 + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; + #endif//CVARDEF_H \ No newline at end of file diff --git a/common/demo_api.h b/common/demo_api.h index c414e4ae..fa89bbef 100644 --- a/common/demo_api.h +++ b/common/demo_api.h @@ -1,27 +1,27 @@ -/*** -* -* 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 DEMO_API_H -#define DEMO_API_H - -typedef struct demo_api_s -{ - int (*IsRecording)( void ); - int (*IsPlayingback)( void ); - int (*IsTimeDemo)( void ); - void (*WriteBuffer)( int size, unsigned char *buffer ); -} demo_api_t; - +/*** +* +* 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 DEMO_API_H +#define DEMO_API_H + +typedef struct demo_api_s +{ + int (*IsRecording)( void ); + int (*IsPlayingback)( void ); + int (*IsTimeDemo)( void ); + void (*WriteBuffer)( int size, unsigned char *buffer ); +} demo_api_t; + #endif//DEMO_API_H \ No newline at end of file diff --git a/common/dlight.h b/common/dlight.h index 848d2182..b139d582 100644 --- a/common/dlight.h +++ b/common/dlight.h @@ -1,31 +1,31 @@ -/*** -* -* 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 DLIGHT_H -#define DLIGHT_H - -typedef struct dlight_s -{ - vec3_t origin; - float radius; - color24 color; - float die; // stop lighting after this time - float decay; // drop this each second - float minlight; // don't add when contributing less - int key; - qboolean dark; // subtracts light instead of adding -} dlight_t; - +/*** +* +* 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 DLIGHT_H +#define DLIGHT_H + +typedef struct dlight_s +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + #endif//DLIGHT_H \ No newline at end of file diff --git a/common/entity_state.h b/common/entity_state.h index 2e0f129d..ef5448f1 100644 --- a/common/entity_state.h +++ b/common/entity_state.h @@ -1,186 +1,186 @@ -/*** -* -* 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 ENTITY_STATE_H -#define ENTITY_STATE_H - -// For entityType below -#define ENTITY_NORMAL (1<<0) -#define ENTITY_BEAM (1<<1) - -// Entity state is used for the baseline and for delta compression of a packet of -// entities that is sent to a client. -typedef struct entity_state_s entity_state_t; - -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; - float msg_time; - - // Message number last time the player/entity state was updated. - int messagenum; - -// Fields which can be transitted and reconstructed over the network stream - vec3_t origin; - vec3_t angles; - - int modelindex; - int sequence; - float frame; - int colormap; - short skin; - short solid; - int effects; - float scale; - byte eflags; - - // Render information - int rendermode; - int renderamt; - color24 rendercolor; - int renderfx; - - int movetype; - float animtime; - float framerate; - int body; - byte controller[4]; - byte blending[4]; - vec3_t velocity; - - // Send bbox down to client for use during prediction. - vec3_t mins; - vec3_t maxs; - - int aiment; - // If owned by a player, the index of that player ( for projectiles ). - int owner; - - // Friction, for prediction. - float friction; - // Gravity multiplier - float gravity; - -// PLAYER SPECIFIC - int team; - int playerclass; - int health; - qboolean spectator; - int weaponmodel; - int gaitsequence; - // If standing on conveyor, e.g. - vec3_t basevelocity; - // Use the crouched hull, or the regular player hull. - int usehull; - // Latched buttons last time state updated. - int oldbuttons; - // -1 = in air, else pmove entity number - int onground; - int iStepLeft; - // How fast we are falling - float flFallVelocity; - - float fov; - int weaponanim; - - // Parametric movement overrides - vec3_t startpos; - vec3_t endpos; - float impacttime; - float starttime; - - // 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; -}; - -#include "pm_info.h" - -typedef struct clientdata_s -{ - vec3_t origin; - vec3_t velocity; - - int viewmodel; - vec3_t punchangle; - int flags; - int waterlevel; - int watertype; - vec3_t view_ofs; - float health; - - int bInDuck; - int weapons; // remove? - - int flTimeStepSound; - int flDuckTime; - int flSwimTime; - int waterjumptime; - - float maxspeed; - - float fov; - int weaponanim; - - int m_iId; - int ammo_shells; - int ammo_nails; - int ammo_cells; - int ammo_rockets; - float m_flNextAttack; - - int tfstate; - int pushmsec; - int deadflag; - char physinfo[MAX_PHYSINFO_STRING]; - - // 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; - -} clientdata_t; - -#include "weaponinfo.h" - -typedef struct local_state_s -{ - entity_state_t playerstate; - clientdata_t client; - weapon_data_t weapondata[64]; -} local_state_t; - +/*** +* +* 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 ENTITY_STATE_H +#define ENTITY_STATE_H + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +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; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + +// Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // 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; +}; + +#include "pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + int pushmsec; + int deadflag; + char physinfo[MAX_PHYSINFO_STRING]; + + // 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; + +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[64]; +} local_state_t; + #endif//ENTITY_STATE_H \ No newline at end of file diff --git a/common/entity_types.h b/common/entity_types.h index fcdd4c2c..25a8fce9 100644 --- a/common/entity_types.h +++ b/common/entity_types.h @@ -1,25 +1,25 @@ -/*** -* -* 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 ENTITY_TYPES_H -#define ENTITY_TYPES_H - -#define ET_NORMAL 0 -#define ET_PLAYER 1 -#define ET_TEMPENTITY 2 -#define ET_BEAM 3 -#define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes - +/*** +* +* 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 ENTITY_TYPES_H +#define ENTITY_TYPES_H + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +#define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes + #endif//ENTITY_TYPES_H \ No newline at end of file diff --git a/common/event_api.h b/common/event_api.h index d29aac99..a7ff71b2 100644 --- a/common/event_api.h +++ b/common/event_api.h @@ -1,54 +1,54 @@ -/*** -* -* 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 EVENT_API_H -#define EVENT_API_H - -#define EVENT_API_VERSION 1 - -typedef struct event_api_s -{ - int version; - void ( *EV_PlaySound )( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); - void ( *EV_StopSound )( int ent, int channel, const char *sample ); - int ( *EV_FindModelIndex )( const char *pmodel ); - int ( *EV_IsLocal )( int playernum ); - int ( *EV_LocalPlayerDucking )( void ); - void ( *EV_LocalPlayerViewheight )( float * ); - void ( *EV_LocalPlayerBounds )( int hull, float *mins, float *maxs ); - int ( *EV_IndexFromTrace)( struct pmtrace_s *pTrace ); - struct physent_s *( *EV_GetPhysent )( int idx ); - void ( *EV_SetUpPlayerPrediction )( int dopred, int bIncludeLocalClient ); - void ( *EV_PushPMStates )( void ); - void ( *EV_PopPMStates )( void ); - void ( *EV_SetSolidPlayers )( int playernum ); - void ( *EV_SetTraceHull )( int hull ); - void ( *EV_PlayerTrace )( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); - void ( *EV_WeaponAnimation )( int sequence, int body ); - unsigned short ( *EV_PrecacheEvent )( int type, const char* psz ); - void ( *EV_PlaybackEvent )( 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 ); - const char *( *EV_TraceTexture )( int ground, float *vstart, float *vend ); - void ( *EV_StopAllSounds )( int entnum, int entchannel ); - void ( *EV_KillEvents )( int entnum, const char *eventname ); - - // Xash3D extension - unsigned short (*EV_IndexForEvent)( const char *name ); - const char *(*EV_EventForIndex)( unsigned short index ); - void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr ); - const char *(*EV_SoundForIndex)( int index ); - struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend ); -} event_api_t; - +/*** +* +* 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 EVENT_API_H +#define EVENT_API_H + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound )( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound )( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal )( int playernum ); + int ( *EV_LocalPlayerDucking )( void ); + void ( *EV_LocalPlayerViewheight )( float * ); + void ( *EV_LocalPlayerBounds )( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace)( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent )( int idx ); + void ( *EV_SetUpPlayerPrediction )( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates )( void ); + void ( *EV_PopPMStates )( void ); + void ( *EV_SetSolidPlayers )( int playernum ); + void ( *EV_SetTraceHull )( int hull ); + void ( *EV_PlayerTrace )( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation )( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent )( int type, const char* psz ); + void ( *EV_PlaybackEvent )( 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 ); + const char *( *EV_TraceTexture )( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds )( int entnum, int entchannel ); + void ( *EV_KillEvents )( int entnum, const char *eventname ); + + // Xash3D extension + unsigned short (*EV_IndexForEvent)( const char *name ); + const char *(*EV_EventForIndex)( unsigned short index ); + void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr ); + const char *(*EV_SoundForIndex)( int index ); + struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend ); +} event_api_t; + #endif//EVENT_API_H \ No newline at end of file diff --git a/common/event_args.h b/common/event_args.h index ed553aa9..d85906cc 100644 --- a/common/event_args.h +++ b/common/event_args.h @@ -1,47 +1,47 @@ -/*** -* -* 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 EVENT_ARGS_H -#define EVENT_ARGS_H - -// Event was invoked with stated origin -#define FEVENT_ORIGIN ( 1<<0 ) - -// Event was invoked with stated angles -#define FEVENT_ANGLES ( 1<<1 ) - -typedef struct event_args_s -{ - int flags; - - // Transmitted - int entindex; - - float origin[3]; - float angles[3]; - float velocity[3]; - - int ducking; - - float fparam1; - float fparam2; - - int iparam1; - int iparam2; - - int bparam1; - int bparam2; -} event_args_t; - +/*** +* +* 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 EVENT_ARGS_H +#define EVENT_ARGS_H + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + #endif//EVENT_ARGS_H \ No newline at end of file diff --git a/common/event_flags.h b/common/event_flags.h index 58460379..3c1d8fb3 100644 --- a/common/event_flags.h +++ b/common/event_flags.h @@ -1,45 +1,45 @@ -/*** -* -* 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 EVENT_FLAGS_H -#define EVENT_FLAGS_H - -// Skip local host for event send. -#define FEV_NOTHOST (1<<0) - -// Send the event reliably. You must specify the origin and angles and use -// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything -// that depends on the event origin/angles. I.e., the origin/angles are not -// taken from the invoking edict for reliable events. -#define FEV_RELIABLE (1<<1) - -// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC -// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). -#define FEV_GLOBAL (1<<2) - -// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate -// -#define FEV_UPDATE (1<<3) - -// Only send to entity specified as the invoker -#define FEV_HOSTONLY (1<<4) - -// Only send if the event was created on the server. -#define FEV_SERVER (1<<5) - -// Only issue event client side ( from shared code ) -#define FEV_CLIENT (1<<6) - +/*** +* +* 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 EVENT_FLAGS_H +#define EVENT_FLAGS_H + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + #endif//EVENT_FLAGS_H \ No newline at end of file diff --git a/common/gameinfo.h b/common/gameinfo.h index 020e920a..511b3718 100644 --- a/common/gameinfo.h +++ b/common/gameinfo.h @@ -1,49 +1,49 @@ -/* -gameinfo.h - current game info -Copyright (C) 2010 Uncle Mike - -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. -*/ - -#ifndef GAMEINFO_H -#define GAMEINFO_H - -#define GFL_NOMODELS (1<<0) - -/* -======================================================================== - -GAMEINFO stuff - -internal shared gameinfo structure (readonly for engine parts) -======================================================================== -*/ -typedef struct -{ - // filesystem info - char gamefolder[64]; // used for change game '-game x' - char startmap[64]; // map to start singleplayer game - char trainmap[64]; // map to start hazard course (if specified) - char title[64]; // Game Main Title - char version[14]; // game version (optional) - short flags; // game flags - - // about mod info - char game_url[256]; // link to a developer's site - char update_url[256]; // link to updates page - char type[64]; // single, toolkit, multiplayer etc - char date[64]; - char size[64]; // displayed mod size - - int gamemode; -} GAMEINFO; - +/* +gameinfo.h - current game info +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef GAMEINFO_H +#define GAMEINFO_H + +#define GFL_NOMODELS (1<<0) + +/* +======================================================================== + +GAMEINFO stuff + +internal shared gameinfo structure (readonly for engine parts) +======================================================================== +*/ +typedef struct +{ + // filesystem info + char gamefolder[64]; // used for change game '-game x' + char startmap[64]; // map to start singleplayer game + char trainmap[64]; // map to start hazard course (if specified) + char title[64]; // Game Main Title + char version[14]; // game version (optional) + short flags; // game flags + + // about mod info + char game_url[256]; // link to a developer's site + char update_url[256]; // link to updates page + char type[64]; // single, toolkit, multiplayer etc + char date[64]; + char size[64]; // displayed mod size + + int gamemode; +} GAMEINFO; + #endif//GAMEINFO_H \ No newline at end of file diff --git a/common/hltv.h b/common/hltv.h index f85b6241..79251910 100644 --- a/common/hltv.h +++ b/common/hltv.h @@ -1,59 +1,59 @@ -/*** -* -* 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 HLTV_H -#define HLTV_H - -#define TYPE_CLIENT 0 // client is a normal HL client (default) -#define TYPE_PROXY 1 // client is another proxy -#define TYPE_COMMENTATOR 3 // client is a commentator -#define TYPE_DEMO 4 // client is a demo file - -// sub commands of svc_hltv: -#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands -#define HLTV_STATUS 1 // send status infos about proxy -#define HLTV_LISTEN 2 // tell client to listen to a multicast stream - -// sub commands of svc_director: -#define DRC_CMD_NONE 0 // NULL director command -#define DRC_CMD_START 1 // start director mode -#define DRC_CMD_EVENT 2 // informs about director command -#define DRC_CMD_MODE 3 // switches camera modes -#define DRC_CMD_CAMERA 4 // sets camera registers -#define DRC_CMD_TIMESCALE 5 // sets time scale -#define DRC_CMD_MESSAGE 6 // send HUD centerprint -#define DRC_CMD_SOUND 7 // plays a particular sound -#define DRC_CMD_STATUS 8 // status info about broadcast -#define DRC_CMD_BANNER 9 // banner file name for HLTV gui -#define DRC_CMD_FADE 10 // send screen fade command -#define DRC_CMD_SHAKE 11 // send screen shake command -#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command - -#define DRC_CMD_LAST 12 - -// HLTV_EVENT event flags -#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) -#define DRC_FLAG_SIDE (1<<4) // -#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene -#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo -#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) -#define DRC_FLAG_INTRO (1<<8) // is a introduction scene -#define DRC_FLAG_FINAL (1<<9) // is a final scene -#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data - -#define MAX_DIRECTOR_CMD_PARAMETERS 4 -#define MAX_DIRECTOR_CMD_STRING 128 - +/*** +* +* 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 HLTV_H +#define HLTV_H + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_COMMENTATOR 3 // client is a commentator +#define TYPE_DEMO 4 // client is a demo file + +// sub commands of svc_hltv: +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_LISTEN 2 // tell client to listen to a multicast stream + +// sub commands of svc_director: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director command +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // sets camera registers +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // status info about broadcast +#define DRC_CMD_BANNER 9 // banner file name for HLTV gui +#define DRC_CMD_FADE 10 // send screen fade command +#define DRC_CMD_SHAKE 11 // send screen shake command +#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command + +#define DRC_CMD_LAST 12 + +// HLTV_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + +#define MAX_DIRECTOR_CMD_PARAMETERS 4 +#define MAX_DIRECTOR_CMD_STRING 128 + #endif//HLTV_H \ No newline at end of file diff --git a/common/ivoicetweak.h b/common/ivoicetweak.h index 9c7b6963..541a63fa 100644 --- a/common/ivoicetweak.h +++ b/common/ivoicetweak.h @@ -1,40 +1,40 @@ -/*** -* -* 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 IVOICETWEAK_H -#define IVOICETWEAK_H - -// These provide access to the voice controls. -typedef enum -{ - MicrophoneVolume = 0, // values 0-1. - OtherSpeakerScale // values 0-1. Scales how loud other players are. -} VoiceTweakControl; - -typedef struct IVoiceTweak_s -{ - // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back - // without sending to the server. - int (*StartVoiceTweakMode)( void ); // Returns 0 on error. - void (*EndVoiceTweakMode)( void ); - - // Get/set control values. - void (*SetControlFloat)( VoiceTweakControl iControl, float value ); - float (*GetControlFloat)( VoiceTweakControl iControl ); - - int (*GetSpeakingVolume)( void ); -} IVoiceTweak; - +/*** +* +* 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 IVOICETWEAK_H +#define IVOICETWEAK_H + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume = 0, // values 0-1. + OtherSpeakerScale // values 0-1. Scales how loud other players are. +} VoiceTweakControl; + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)( void ); // Returns 0 on error. + void (*EndVoiceTweakMode)( void ); + + // Get/set control values. + void (*SetControlFloat)( VoiceTweakControl iControl, float value ); + float (*GetControlFloat)( VoiceTweakControl iControl ); + + int (*GetSpeakingVolume)( void ); +} IVoiceTweak; + #endif//IVOICETWEAK_H \ No newline at end of file diff --git a/common/lightstyle.h b/common/lightstyle.h index af4add8b..8b42edac 100644 --- a/common/lightstyle.h +++ b/common/lightstyle.h @@ -1,29 +1,29 @@ -/* -lightstyle.h - lighstyle description -Copyright (C) 2011 Uncle Mike - -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. -*/ - -#ifndef LIGHTSTYLE_H -#define LIGHTSTYLE_H - -typedef struct -{ - char pattern[256]; - float map[256]; - int length; - float value; - qboolean interp; // allow to interpolate this lightstyle - float time; // local time is gurantee what new style begins from the start, not mid or end of the sequence -} lightstyle_t; - +/* +lightstyle.h - lighstyle description +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef LIGHTSTYLE_H +#define LIGHTSTYLE_H + +typedef struct +{ + char pattern[256]; + float map[256]; + int length; + float value; + qboolean interp; // allow to interpolate this lightstyle + float time; // local time is gurantee what new style begins from the start, not mid or end of the sequence +} lightstyle_t; + #endif//LIGHTSTYLE_H \ No newline at end of file diff --git a/common/mathlib.h b/common/mathlib.h index d90f5f7a..fadb97fb 100644 --- a/common/mathlib.h +++ b/common/mathlib.h @@ -1,95 +1,95 @@ -/*** -* -* 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 - -#include - -typedef float vec_t; -typedef vec_t vec2_t[2]; -typedef vec_t vec3_t[3]; -typedef vec_t vec4_t[4]; // x,y,z,w - -#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); - -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]); - -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))) +/*** +* +* 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 + +#include + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; // x,y,z,w + +#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); + +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]); + +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/common/net_api.h b/common/net_api.h index 72afdf75..00831394 100644 --- a/common/net_api.h +++ b/common/net_api.h @@ -1,97 +1,97 @@ -/*** -* -* 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 NET_API_H -#define NET_API_H - -#include "netadr.h" - -#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address -#define NETAPI_REQUEST_PING ( 1 ) -#define NETAPI_REQUEST_RULES ( 2 ) -#define NETAPI_REQUEST_PLAYERS ( 3 ) -#define NETAPI_REQUEST_DETAILS ( 4 ) - -// Set this flag for things like broadcast requests, etc. where the engine should not -// kill the request hook after receiving the first response -#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) - -typedef void (*net_api_response_func_t) ( struct net_response_s *response ); - -#define NET_SUCCESS ( 0 ) -#define NET_ERROR_TIMEOUT ( 1<<0 ) -#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) -#define NET_ERROR_UNDEFINED ( 1<<2 ) - -typedef struct net_adrlist_s -{ - struct net_adrlist_s *next; - netadr_t remote_address; -} net_adrlist_t; - -typedef struct net_response_s -{ - // NET_SUCCESS or an error code - int error; - // Context ID - int context; - // Type - int type; - // Server that is responding to the request - netadr_t remote_address; - // Response RTT ping time - double ping; - // Key/Value pair string ( separated by backlash \ characters ) - // WARNING: You must copy this buffer in the callback function, because it is freed - // by the engine right after the call!!!! - // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's - void *response; -} net_response_t; - -typedef struct net_status_s -{ - // Connected to remote server? 1 == yes, 0 otherwise - int connected; - // Client's IP address - netadr_t local_address; - // Address of remote server - netadr_t remote_address; - // Packet Loss ( as a percentage ) - int packet_loss; - // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) - double latency; - // Connection time, in seconds - double connection_time; - // Rate setting ( for incoming data ) - double rate; -} net_status_t; - -typedef struct net_api_s -{ - // APIs - void (*InitNetworking)( void ); - void (*Status )( struct net_status_s *status ); - void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); - void (*CancelRequest)( int context ); - void (*CancelAllRequests)( void ); - char *(*AdrToString)( struct netadr_s *a ); - int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b ); - int ( *StringToAdr)( char *s, struct netadr_s *a ); - const char *(*ValueForKey)( const char *s, const char *key ); - void (*RemoveKey)( char *s, const char *key ); - void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize ); -} net_api_t; - +/*** +* +* 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 NET_API_H +#define NET_API_H + +#include "netadr.h" + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +typedef void (*net_api_response_func_t) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + // Context ID + int context; + // Type + int type; + // Server that is responding to the request + netadr_t remote_address; + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void (*InitNetworking)( void ); + void (*Status )( struct net_status_s *status ); + void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void (*CancelRequest)( int context ); + void (*CancelAllRequests)( void ); + char *(*AdrToString)( struct netadr_s *a ); + int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr)( char *s, struct netadr_s *a ); + const char *(*ValueForKey)( const char *s, const char *key ); + void (*RemoveKey)( char *s, const char *key ); + void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + #endif//NET_APIH \ No newline at end of file diff --git a/common/netadr.h b/common/netadr.h index 16aafe30..dfeea8b0 100644 --- a/common/netadr.h +++ b/common/netadr.h @@ -1,37 +1,37 @@ -/*** -* -* 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 NETADR_H -#define NETADR_H - -typedef enum -{ - NA_UNUSED, - NA_LOOPBACK, - NA_BROADCAST, - NA_IP, - NA_IPX, - NA_BROADCAST_IPX -} netadrtype_t; - -typedef struct netadr_s -{ - netadrtype_t type; - unsigned char ip[4]; - unsigned char ipx[10]; - unsigned short port; -} netadr_t; - +/*** +* +* 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 NETADR_H +#define NETADR_H + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + #endif//NETADR_H \ No newline at end of file diff --git a/common/particledef.h b/common/particledef.h index a5083ee6..3f2ead66 100644 --- a/common/particledef.h +++ b/common/particledef.h @@ -1,54 +1,54 @@ -/*** -* -* 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 PARTICLEDEF_H -#define PARTICLEDEF_H - -typedef enum -{ - pt_static, - pt_grav, - pt_slowgrav, - pt_fire, - pt_explode, - pt_explode2, - pt_blob, - pt_blob2, - pt_vox_slowgrav, - pt_vox_grav, - pt_clientcustom, // Must have callback function specified - pt_tracer // Always have callback -} ptype_t; - -typedef struct particle_s -{ - vec3_t org; - short color; - short packedColor; - struct particle_s *next; - vec3_t vel; - float ramp; - float die; - ptype_t type; - void (*deathfunc)( struct particle_s *particle ); - - // for pt_clientcusttom, we'll call this function each frame - void (*callback)( struct particle_s *particle, float frametime ); - - // For deathfunc, etc. - unsigned char context; -} particle_t; - +/*** +* +* 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 PARTICLEDEF_H +#define PARTICLEDEF_H + +typedef enum +{ + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom, // Must have callback function specified + pt_tracer // Always have callback +} ptype_t; + +typedef struct particle_s +{ + vec3_t org; + short color; + short packedColor; + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // For deathfunc, etc. + unsigned char context; +} particle_t; + #endif//PARTICLEDEF_H \ No newline at end of file diff --git a/common/pmtrace.h b/common/pmtrace.h index e2779ad6..6394de56 100644 --- a/common/pmtrace.h +++ b/common/pmtrace.h @@ -1,41 +1,41 @@ -/*** -* -* 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_TRACE_H -#define PM_TRACE_H - -typedef struct -{ - vec3_t normal; - float dist; -} pmplane_t; - -typedef struct pmtrace_s pmtrace_t; - -struct pmtrace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - qboolean inopen, inwater; // End point is in empty space or in water - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - pmplane_t plane; // surface normal at impact - int ent; // entity at impact - vec3_t deltavelocity; // Change in player's velocity caused by impact. - // Only run on server. - int hitgroup; -}; - +/*** +* +* 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_TRACE_H +#define PM_TRACE_H + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + #endif//PM_TRACE_H \ No newline at end of file diff --git a/common/qfont.h b/common/qfont.h index 8489dffc..06408572 100644 --- a/common/qfont.h +++ b/common/qfont.h @@ -1,38 +1,38 @@ -/*** -* -* 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 QFONT_H -#define QFONT_H - -// Font stuff - -#define NUM_GLYPHS 256 - -typedef struct -{ - short startoffset; - short charwidth; -} charinfo; - -typedef struct qfont_s -{ - int width, height; - int rowcount; - int rowheight; - charinfo fontinfo[NUM_GLYPHS]; - byte data[4]; -} qfont_t; - +/*** +* +* 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 QFONT_H +#define QFONT_H + +// Font stuff + +#define NUM_GLYPHS 256 + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[NUM_GLYPHS]; + byte data[4]; +} qfont_t; + #endif//QFONT_H \ No newline at end of file diff --git a/common/r_efx.h b/common/r_efx.h index d21cba27..fc27bef7 100644 --- a/common/r_efx.h +++ b/common/r_efx.h @@ -1,195 +1,195 @@ -/*** -* -* 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 R_EFX_H -#define R_EFX_H - -// particle_t -#if !defined( PARTICLEDEFH ) -#include "particledef.h" -#endif - -// BEAM -#if !defined( BEAMDEFH ) -#include "beamdef.h" -#endif - -// dlight_t -#if !defined ( DLIGHTH ) -#include "dlight.h" -#endif - -// cl_entity_t -#if !defined( CL_ENTITYH ) -#include "cl_entity.h" -#endif - -/* -// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one -// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings -color24 gTracerColors[] = -{ - { 255, 255, 255 }, // White - { 255, 0, 0 }, // Red - { 0, 255, 0 }, // Green - { 0, 0, 255 }, // Blue - { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. - { 255, 167, 17 }, // Yellow-orange sparks - { 255, 130, 90 }, // Yellowish streaks (garg) - { 55, 60, 144 }, // Blue egon streak - { 255, 130, 90 }, // More Yellowish streaks (garg) - { 255, 140, 90 }, // More Yellowish streaks (garg) - { 200, 130, 90 }, // More red streaks (garg) - { 255, 120, 70 }, // Darker red streaks (garg) -}; -*/ - -// Temporary entity array -#define TENTPRIORITY_LOW 0 -#define TENTPRIORITY_HIGH 1 - -// TEMPENTITY flags -#define FTENT_NONE 0x00000000 -#define FTENT_SINEWAVE 0x00000001 -#define FTENT_GRAVITY 0x00000002 -#define FTENT_ROTATE 0x00000004 -#define FTENT_SLOWGRAVITY 0x00000008 -#define FTENT_SMOKETRAIL 0x00000010 -#define FTENT_COLLIDEWORLD 0x00000020 -#define FTENT_FLICKER 0x00000040 -#define FTENT_FADEOUT 0x00000080 -#define FTENT_SPRANIMATE 0x00000100 -#define FTENT_HITSOUND 0x00000200 -#define FTENT_SPIRAL 0x00000400 -#define FTENT_SPRCYCLE 0x00000800 -#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes -#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw -#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything -#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) -#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed -#define FTENT_SPARKSHOWER 0x00020000 -#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) -#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) -#define FTENT_SCALE 0x00100000 // An experiment - -typedef struct tempent_s TEMPENTITY; -typedef struct tempent_s -{ - int flags; - float die; - float frameMax; - float x; - float y; - float z; - float fadeSpeed; - float bounceFactor; - int hitSound; - void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ); - void (*callback)( struct tempent_s *ent, float frametime, float currenttime ); - TEMPENTITY *next; - int priority; - short clientIndex; // if attached, this is the index of the client to stick to - // if COLLIDEALL, this is the index of the client to ignore - // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! - - vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. - cl_entity_t entity; - - // baseline.origin - velocity - // baseline.renderamt - starting fadeout intensity - // baseline.angles - angle velocity -} TEMPENTITY; - -typedef struct efx_api_s efx_api_t; - -struct efx_api_s -{ - 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 ); - void (*R_BloodStream)( float *org, float *dir, int pcolor, int speed ); - void (*R_BreakModel)( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); - void (*R_Bubbles)( float *mins, float *maxs, float height, int modelIndex, int count, float speed ); - void (*R_BubbleTrail)( float *start, float *end, float height, int modelIndex, int count, float speed ); - void (*R_BulletImpactParticles)( float *pos ); - void (*R_EntityParticles)( struct cl_entity_s *ent ); - void (*R_Explosion)( float *pos, int model, float scale, float framerate, int flags ); - void (*R_FizzEffect)( struct cl_entity_s *pent, int modelIndex, int density ); - void (*R_FireField)( float *org, int radius, int modelIndex, int count, int flags, float life ); - void (*R_FlickerParticles)( float *org ); - void (*R_FunnelSprite)( float *org, int modelIndex, int reverse ); - void (*R_Implosion)( float *end, float radius, int count, float life ); - void (*R_LargeFunnel)( float *org, int reverse ); - void (*R_LavaSplash)( float *org ); - void (*R_MultiGunshot)( float *org, float *dir, float *noise, int count, int decalCount, int *decalIndices ); - void (*R_MuzzleFlash)( float *pos1, int type ); - void (*R_ParticleBox)( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); - void (*R_ParticleBurst)( float *pos, int size, int color, float life ); - void (*R_ParticleExplosion)( float *org ); - void (*R_ParticleExplosion2)( float *org, int colorStart, int colorLength ); - void (*R_ParticleLine)( float *start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); - void (*R_PlayerSprites)( int client, int modelIndex, int count, int size ); - void (*R_Projectile)( float *origin, float *velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); - void (*R_RicochetSound)( float *pos ); - void (*R_RicochetSprite)( float *pos, struct model_s *pmodel, float duration, float scale ); - void (*R_RocketFlare)( float *pos ); - void (*R_RocketTrail)( float *start, float *end, int type ); - void (*R_RunParticleEffect)( float *org, float *dir, int color, int count ); - void (*R_ShowLine)( float *start, float *end ); - void (*R_SparkEffect)( float *pos, int count, int velocityMin, int velocityMax ); - void (*R_SparkShower)( float *pos ); - void (*R_SparkStreaks)( float *pos, int count, int velocityMin, int velocityMax ); - void (*R_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int spread, int rendermode ); - void (*R_Sprite_Explode)( TEMPENTITY *pTemp, float scale, int flags ); - void (*R_Sprite_Smoke)( TEMPENTITY *pTemp, float scale ); - void (*R_Sprite_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int iRand ); - void (*R_Sprite_Trail)( int type, float *start, float *end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); - void (*R_Sprite_WallPuff)( TEMPENTITY *pTemp, float scale ); - void (*R_StreakSplash)( float *pos, float *dir, int color, int count, float speed, int velocityMin, int velocityMax ); - void (*R_TracerEffect)( float *start, float *end ); - void (*R_UserTracerParticle)( float *org, float *vel, float life, int colorIndex, float length, unsigned char deathcontext, void (*deathfunc)( struct particle_s *particle )); - particle_t *(*R_TracerParticles)( float *org, float *vel, float life ); - void (*R_TeleportSplash)( float *org ); - void (*R_TempSphereModel)( float *pos, float speed, float life, int count, int modelIndex ); - TEMPENTITY *(*R_TempModel)( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); - TEMPENTITY *(*R_DefaultSprite)( float *pos, int spriteIndex, float framerate ); - TEMPENTITY *(*R_TempSprite)( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); - int (*Draw_DecalIndex)( int id ); - int (*Draw_DecalIndexFromName)( char *name ); - void (*R_DecalShoot)( int textureIndex, int entity, int modelIndex, float *position, int flags ); - void (*R_AttachTentToPlayer)( int client, int modelIndex, float zoffset, float life ); - void (*R_KillAttachedTents)( int client ); - BEAM *(*R_BeamCirclePoints)( int type, float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *(*R_BeamEntPoint)( int startEnt, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *(*R_BeamEnts)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *(*R_BeamFollow)( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); - void (*R_BeamKill)( int deadEntity ); - BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); - BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); - dlight_t *(*CL_AllocDlight)( int key ); - dlight_t *(*CL_AllocElight)( int key ); - TEMPENTITY *(*CL_TempEntAlloc)( float *org, struct model_s *model ); - TEMPENTITY *(*CL_TempEntAllocNoModel)( float *org ); - TEMPENTITY *(*CL_TempEntAllocHigh)( float *org, struct model_s *model ); - TEMPENTITY *(*CL_TentEntAllocCustom)( float *origin, struct model_s *model, int high, void (*callback)( struct tempent_s *ent, float frametime, float currenttime )); - void (*R_GetPackedColor)( short *packed, short color ); - short (*R_LookupColor)( unsigned char r, unsigned char g, unsigned char b ); - void (*R_DecalRemoveAll)( int textureIndex ); // textureIndex points to the decal index in the array, not the actual texture index. - void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale ); -}; - +/*** +* +* 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 R_EFX_H +#define R_EFX_H + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) +#define FTENT_SCALE 0x00100000 // An experiment + +typedef struct tempent_s TEMPENTITY; +typedef struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ); + void (*callback)( struct tempent_s *ent, float frametime, float currenttime ); + TEMPENTITY *next; + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +} TEMPENTITY; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + 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 ); + void (*R_BloodStream)( float *org, float *dir, int pcolor, int speed ); + void (*R_BreakModel)( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void (*R_Bubbles)( float *mins, float *maxs, float height, int modelIndex, int count, float speed ); + void (*R_BubbleTrail)( float *start, float *end, float height, int modelIndex, int count, float speed ); + void (*R_BulletImpactParticles)( float *pos ); + void (*R_EntityParticles)( struct cl_entity_s *ent ); + void (*R_Explosion)( float *pos, int model, float scale, float framerate, int flags ); + void (*R_FizzEffect)( struct cl_entity_s *pent, int modelIndex, int density ); + void (*R_FireField)( float *org, int radius, int modelIndex, int count, int flags, float life ); + void (*R_FlickerParticles)( float *org ); + void (*R_FunnelSprite)( float *org, int modelIndex, int reverse ); + void (*R_Implosion)( float *end, float radius, int count, float life ); + void (*R_LargeFunnel)( float *org, int reverse ); + void (*R_LavaSplash)( float *org ); + void (*R_MultiGunshot)( float *org, float *dir, float *noise, int count, int decalCount, int *decalIndices ); + void (*R_MuzzleFlash)( float *pos1, int type ); + void (*R_ParticleBox)( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_ParticleBurst)( float *pos, int size, int color, float life ); + void (*R_ParticleExplosion)( float *org ); + void (*R_ParticleExplosion2)( float *org, int colorStart, int colorLength ); + void (*R_ParticleLine)( float *start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void (*R_PlayerSprites)( int client, int modelIndex, int count, int size ); + void (*R_Projectile)( float *origin, float *velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void (*R_RicochetSound)( float *pos ); + void (*R_RicochetSprite)( float *pos, struct model_s *pmodel, float duration, float scale ); + void (*R_RocketFlare)( float *pos ); + void (*R_RocketTrail)( float *start, float *end, int type ); + void (*R_RunParticleEffect)( float *org, float *dir, int color, int count ); + void (*R_ShowLine)( float *start, float *end ); + void (*R_SparkEffect)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_SparkShower)( float *pos ); + void (*R_SparkStreaks)( float *pos, int count, int velocityMin, int velocityMax ); + void (*R_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void (*R_Sprite_Explode)( TEMPENTITY *pTemp, float scale, int flags ); + void (*R_Sprite_Smoke)( TEMPENTITY *pTemp, float scale ); + void (*R_Sprite_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int iRand ); + void (*R_Sprite_Trail)( int type, float *start, float *end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void (*R_Sprite_WallPuff)( TEMPENTITY *pTemp, float scale ); + void (*R_StreakSplash)( float *pos, float *dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void (*R_TracerEffect)( float *start, float *end ); + void (*R_UserTracerParticle)( float *org, float *vel, float life, int colorIndex, float length, unsigned char deathcontext, void (*deathfunc)( struct particle_s *particle )); + particle_t *(*R_TracerParticles)( float *org, float *vel, float life ); + void (*R_TeleportSplash)( float *org ); + void (*R_TempSphereModel)( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *(*R_TempModel)( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *(*R_DefaultSprite)( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *(*R_TempSprite)( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int (*Draw_DecalIndex)( int id ); + int (*Draw_DecalIndexFromName)( char *name ); + void (*R_DecalShoot)( int textureIndex, int entity, int modelIndex, float *position, int flags ); + void (*R_AttachTentToPlayer)( int client, int modelIndex, float zoffset, float life ); + void (*R_KillAttachedTents)( int client ); + BEAM *(*R_BeamCirclePoints)( int type, float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEntPoint)( int startEnt, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamEnts)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamFollow)( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void (*R_BeamKill)( int deadEntity ); + BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *(*CL_AllocDlight)( int key ); + dlight_t *(*CL_AllocElight)( int key ); + TEMPENTITY *(*CL_TempEntAlloc)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TempEntAllocNoModel)( float *org ); + TEMPENTITY *(*CL_TempEntAllocHigh)( float *org, struct model_s *model ); + TEMPENTITY *(*CL_TentEntAllocCustom)( float *origin, struct model_s *model, int high, void (*callback)( struct tempent_s *ent, float frametime, float currenttime )); + void (*R_GetPackedColor)( short *packed, short color ); + short (*R_LookupColor)( unsigned char r, unsigned char g, unsigned char b ); + void (*R_DecalRemoveAll)( int textureIndex ); // textureIndex points to the decal index in the array, not the actual texture index. + void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale ); +}; + #endif//R_EFX_H \ No newline at end of file diff --git a/common/r_studioint.h b/common/r_studioint.h index 8c5598e1..00384a16 100644 --- a/common/r_studioint.h +++ b/common/r_studioint.h @@ -1,154 +1,154 @@ -/*** -* -* 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 R_STUDIOINT_H -#define R_STUDIOINT_H - -#define STUDIO_INTERFACE_VERSION 1 - -typedef struct engine_studio_api_s -{ - // Allocate number*size bytes and zero it - void *( *Mem_Calloc )( int number, size_t size ); - // Check to see if pointer is in the cache - void *( *Cache_Check )( struct cache_user_s *c ); - // Load file into cache ( can be swapped out on demand ) - void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); - // Retrieve model pointer for the named model - struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing ); - // Retrieve pointer to studio model data block from a model - void *( *Mod_Extradata )( struct model_s *mod ); - // Retrieve indexed model from client side model precache list - struct model_s *( *GetModelByIndex )( int index ); - // Get entity that is set for rendering - struct cl_entity_s * ( *GetCurrentEntity )( void ); - // Get referenced player_info_t - struct player_info_s *( *PlayerInfo )( int index ); - // Get most recently received player state data from network system - struct entity_state_s *( *GetPlayerState )( int index ); - // Get viewentity - struct cl_entity_s * ( *GetViewEntity )( void ); - // Get current frame count, and last two timestampes on client - void ( *GetTimes )( int *framecount, double *current, double *old ); - // Get a pointer to a cvar by name - struct cvar_s *( *GetCvar )( const char *name ); - // Get current render origin and view vectors ( up, right and vpn ) - void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv ); - // Get sprite model used for applying chrome effect - struct model_s *( *GetChromeSprite )( void ); - // Get model counters so we can incement instrumentation - void ( *GetModelCounters )( int **s, int **a ); - // Get software scaling coefficients - void ( *GetAliasScale )( float *x, float *y ); - - // Get bone, light, alias, and rotation matrices - float ****( *StudioGetBoneTransform )( void ); - float ****( *StudioGetLightTransform )( void ); - float ***( *StudioGetAliasTransform )( void ); - float ***( *StudioGetRotationMatrix )( void ); - - // Set up body part, and get submodel pointers - void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel ); - // Check if entity's bbox is in the view frustum - int ( *StudioCheckBBox )( void ); - // Apply lighting effects to model - void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight ); - void ( *StudioEntityLight )( struct alight_s *plight ); - void ( *StudioSetupLighting )( struct alight_s *plighting ); - - // Draw mesh vertices - void ( *StudioDrawPoints )( void ); - - // Draw hulls around bones - void ( *StudioDrawHulls )( void ); - // Draw bbox around studio models - void ( *StudioDrawAbsBBox )( void ); - // Draws bones - void ( *StudioDrawBones )( void ); - // Loads in appropriate texture for model - void ( *StudioSetupSkin )( void *ptexturehdr, int index ); - // Sets up for remapped colors - void ( *StudioSetRemapColors )( int top, int bottom ); - // Set's player model and returns model pointer - struct model_s *( *SetupPlayerModel )( int index ); - // Fires any events embedded in animation - void ( *StudioClientEvents )( void ); - // Retrieve/set forced render effects flags - int ( *GetForceFaceFlags )( void ); - void ( *SetForceFaceFlags )( int flags ); - // Tell engine the value of the studio model header - void ( *StudioSetHeader )( void *header ); - // Tell engine which model_t * is being renderered - void ( *SetRenderModel )( struct model_s *model ); - - // Final state setup and restore for rendering - void ( *SetupRenderer )( int rendermode ); - void ( *RestoreRenderer )( void ); - - // Set render origin for applying chrome effect - void ( *SetChromeOrigin )( void ); - - // True if using D3D/OpenGL - int ( *IsHardware )( void ); - - // Only called by hardware interface - void ( *GL_StudioDrawShadow )( void ); - void ( *GL_SetRenderMode )( int mode ); - - void ( *StudioSetRenderamt )( int iRenderamt ); - void ( *StudioSetCullState )( int iCull ); - void ( *StudioRenderShadow )( int iSprite, float *p1, float *p2, float *p3, float *p4 ); -} engine_studio_api_t; - -typedef struct server_studio_api_s -{ - // Allocate number*size bytes and zero it - void *( *Mem_Calloc )( int number, size_t size ); - // Check to see if pointer is in the cache - void *( *Cache_Check )( struct cache_user_s *c ); - // Load file into cache ( can be swapped out on demand ) - void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); - // Retrieve pointer to studio model data block from a model - void *( *Mod_Extradata )( struct model_s *mod ); -} server_studio_api_t; - -// client blending -typedef struct r_studio_interface_s -{ - int version; - int ( *StudioDrawModel )( int flags ); - int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer ); -} r_studio_interface_t; - -// server blending -#define SV_BLENDING_INTERFACE_VERSION 1 - -typedef struct sv_blending_interface_s -{ - 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 ); -} sv_blending_interface_t; - +/*** +* +* 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 R_STUDIOINT_H +#define R_STUDIOINT_H + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex )( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity )( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo )( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState )( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity )( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes )( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar )( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite )( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters )( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale )( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform )( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform )( void ); + float ***( *StudioGetRotationMatrix )( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox )( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight )( struct alight_s *plight ); + void ( *StudioSetupLighting )( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints )( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls )( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox )( void ); + // Draws bones + void ( *StudioDrawBones )( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin )( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors )( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel )( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents )( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags )( void ); + void ( *SetForceFaceFlags )( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader )( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel )( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer )( int rendermode ); + void ( *RestoreRenderer )( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin )( void ); + + // True if using D3D/OpenGL + int ( *IsHardware )( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow )( void ); + void ( *GL_SetRenderMode )( int mode ); + + void ( *StudioSetRenderamt )( int iRenderamt ); + void ( *StudioSetCullState )( int iCull ); + void ( *StudioRenderShadow )( int iSprite, float *p1, float *p2, float *p3, float *p4 ); +} engine_studio_api_t; + +typedef struct server_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); +} server_studio_api_t; + +// client blending +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel )( int flags ); + int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +// server blending +#define SV_BLENDING_INTERFACE_VERSION 1 + +typedef struct sv_blending_interface_s +{ + 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 ); +} sv_blending_interface_t; + #endif//R_STUDIOINT_H \ No newline at end of file diff --git a/common/ref_params.h b/common/ref_params.h index a544925c..0458c4f4 100644 --- a/common/ref_params.h +++ b/common/ref_params.h @@ -1,90 +1,90 @@ -/*** -* -* 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 REF_PARAMS_H -#define REF_PARAMS_H - -typedef struct ref_params_s -{ - // output - vec3_t vieworg; - vec3_t viewangles; - - vec3_t forward; - vec3_t right; - vec3_t up; - - // Client frametime; - float frametime; - // Client time - float time; - - // Misc - int intermission; - int paused; - int spectator; - int onground; - int waterlevel; - - vec3_t simvel; - vec3_t simorg; - - vec3_t viewheight; - float idealpitch; - - vec3_t cl_viewangles; - int health; - vec3_t crosshairangle; - float viewsize; - - vec3_t punchangle; - int maxclients; - int viewentity; - int playernum; - int max_entities; - int demoplayback; - int hardware; - int smoothing; - - // Last issued usercmd - struct usercmd_s *cmd; - - // Movevars - struct movevars_s *movevars; - - int viewport[4]; // the viewport coordinates x, y, width, height - int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview - // so long in cycles until this value is 0 (multiple views) - int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions -// Xash3D extension - float fov_x, fov_y; // actual fov can be overrided on nextView -} ref_params_t; - -// same as ref_params but for overview mode -typedef struct ref_overview_s -{ - vec3_t origin; - qboolean rotated; - - float xLeft; - float xRight; - float xTop; - float xBottom; - float zFar; - float zNear; - float flZoom; -} ref_overview_t; - +/*** +* +* 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 REF_PARAMS_H +#define REF_PARAMS_H + +typedef struct ref_params_s +{ + // output + vec3_t vieworg; + vec3_t viewangles; + + vec3_t forward; + vec3_t right; + vec3_t up; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + vec3_t simvel; + vec3_t simorg; + + vec3_t viewheight; + float idealpitch; + + vec3_t cl_viewangles; + int health; + vec3_t crosshairangle; + float viewsize; + + vec3_t punchangle; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x, y, width, height + int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview + // so long in cycles until this value is 0 (multiple views) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions +// Xash3D extension + float fov_x, fov_y; // actual fov can be overrided on nextView +} ref_params_t; + +// same as ref_params but for overview mode +typedef struct ref_overview_s +{ + vec3_t origin; + qboolean rotated; + + float xLeft; + float xRight; + float xTop; + float xBottom; + float zFar; + float zNear; + float flZoom; +} ref_overview_t; + #endif//REF_PARAMS_H \ No newline at end of file diff --git a/common/render_api.h b/common/render_api.h index c454bc47..7a9fcffe 100644 --- a/common/render_api.h +++ b/common/render_api.h @@ -1,261 +1,261 @@ -/* -render_api.h - Xash3D extension for client interface -Copyright (C) 2011 Uncle Mike - -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. -*/ - -#ifndef RENDER_API_H -#define RENDER_API_H - -#include "lightstyle.h" -#include "dlight.h" - -// changes for version 28 -// replace decal_t from software declaration to hardware (matched to normal HL) -// mextrasurf_t->increased limit of reserved fields (up from 7 to 32) -// replace R_StoreEfrags with him extended version -// formed group for BSP decal manipulating -// move misc functions at end of the interface -// added new export for clearing studio decals - -#define CL_RENDER_INTERFACE_VERSION 35 -#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals - -#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces)) -#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data)) - -// render info parms -#define PARM_TEX_WIDTH 1 // all parms with prefix 'TEX_' receive arg as texnum -#define PARM_TEX_HEIGHT 2 // otherwise it's not used -#define PARM_TEX_SRC_WIDTH 3 -#define PARM_TEX_SRC_HEIGHT 4 -#define PARM_TEX_SKYBOX 5 // second arg as skybox ordering num -#define PARM_TEX_SKYTEXNUM 6 // skytexturenum for quake sky -#define PARM_TEX_LIGHTMAP 7 // second arg as number 0 - 128 -#define PARM_TEX_TARGET 8 -#define PARM_TEX_TEXNUM 9 -#define PARM_TEX_FLAGS 10 -#define PARM_TEX_TYPE 11 -#define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload -#define PARM_TEX_GLFORMAT 13 // get a texture GL-format -// reserved -#define PARM_WORLD_VERSION 16 // return the version of bsp -#define PARM_SKY_SPHERE 17 // sky is quake sphere ? -#define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs -#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata -#define PARM_MAX_ENTITIES 20 -#define PARM_WIDESCREEN 21 -#define PARM_FULLSCREEN 22 -#define PARM_SCREEN_WIDTH 23 -#define PARM_SCREEN_HEIGHT 24 -#define PARM_CLIENT_INGAME 25 -#define PARM_FEATURES 26 // same as movevars->features -#define PARM_ACTIVE_TMU 27 // for debug -#define PARM_CACHEFRAME 28 -#define PARM_MAX_IMAGE_UNITS 29 -#define PARM_CLIENT_ACTIVE 30 -#define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change - -enum -{ - // skybox ordering - SKYBOX_RIGHT = 0, - SKYBOX_BACK, - SKYBOX_LEFT, - SKYBOX_FORWARD, - SKYBOX_UP, - SKYBOX_DOWN, -}; - -typedef enum -{ - TEX_INVALID = 0, // free slot - TEX_SYSTEM, // generated by engine - TEX_NOMIP, // hud pics, menu etc - TEX_BRUSH, // a map texture - TEX_SPRITE, // sprite frames - TEX_STUDIO, // studio skins - TEX_LIGHTMAP, // lightmap textures - TEX_DECAL, // decals - TEX_VGUI, // vgui fonts or images - TEX_CUBEMAP, // cubemap textures (sky) - TEX_DETAIL, // detail textures - TEX_REMAP, // local copy of remap texture - TEX_SCREENCOPY, // keep screen copy e.g. for mirror - TEX_CUSTOM, // user created texture - TEX_DEPTHMAP // shadowmap texture -} texType_t; - -typedef enum -{ - TF_NEAREST = (1<<0), // disable texfilter - TF_KEEP_RGBDATA = (1<<1), // some images keep source - TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20 - TF_KEEP_8BIT = (1<<3), // keep original 8-bit image (if present) - TF_NOPICMIP = (1<<4), // ignore r_picmip resample rules - TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory - TF_CUBEMAP = (1<<6), // it's cubemap texture - TF_DEPTHMAP = (1<<7), // custom texture filter used - TF_INTENSITY = (1<<8), // monochrome intensity image - TF_LUMINANCE = (1<<9), // force image to grayscale - TF_SKYSIDE = (1<<10), // this is a part of skybox - TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range - TF_NOMIPMAP = (1<<12), // don't build mips for this image - TF_HAS_LUMA = (1<<13), // sets by GL_UploadTexture - TF_MAKELUMA = (1<<14), // create luma from quake texture (only q1 textures contain luma-pixels) - TF_NORMALMAP = (1<<15), // is a normalmap - TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture) - TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures) - TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D - TF_BORDER = (1<<19), // zero clamp for projected textures - TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D - TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine) - TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE - TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference) - TF_IMAGE_PROGRAM = (1<<24), // enable image program support like in Doom3 - TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage - TF_FLOAT = (1<<26), // float textures - TF_NOCOMPARE = (1<<27), // disable comparing for depth textures - TF_FLOATDATA = (1<<28), // incoming dataType has type GL_FLOAT -} texFlags_t; - -typedef struct beam_s BEAM; -typedef struct particle_s particle_t; - -// 12 bytes here -typedef struct modelstate_s -{ - short sequence; - short frame; // 10 bits multiple by 4, should be enough - byte blending[2]; - byte controller[4]; - byte body; - byte skin; -} modelstate_t; - -typedef struct decallist_s -{ - vec3_t position; - char name[64]; - short entityIndex; - byte depth; - byte flags; - float scale; - - // this is the surface plane that we hit so that - // we can move certain decals across - // transitions if they hit similar geometry - vec3_t impactPlaneNormal; - - modelstate_t studio_state; // studio decals only -} decallist_t; - -typedef struct render_api_s -{ - // Get renderer info (doesn't changes engine state at all) - int (*RenderGetParm)( int parm, int arg ); // generic - void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale ); - void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha ); - lightstyle_t* (*GetLightStyle)( int number ); - dlight_t* (*GetDynamicLight)( int number ); - dlight_t* (*GetEntityLight)( int number ); - byte (*TextureToTexGamma)( byte color ); // software gamma support - void (*GetBeamChains)( BEAM ***active_beams, BEAM ***free_beams, particle_t ***free_trails ); - - // Set renderer info (tell engine about changes) - void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel - void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged - void (*GL_SetWorldviewProjectionMatrix)( const float *glmatrix ); // update viewprojection matrix (tracers uses it) - void (*R_StoreEfrags)( struct efrag_s **ppefrag, int framecount );// store efrags for static entities - - // Texture tools - int (*GL_FindTexture)( const char *name ); - const char* (*GL_TextureName)( unsigned int texnum ); - const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL - int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags ); - int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags ); - void (*GL_SetTextureType)( unsigned int texnum, unsigned int type ); - void (*GL_TextureCacheFrame)( unsigned int texnum ); - void (*GL_FreeTexture)( unsigned int texnum ); - - // Decals manipulating (draw & remove) - void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa ); - float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount ); - void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only) - - // AVIkit support - void *(*AVI_LoadVideo)( const char *filename, int ignore_hwgamma ); - int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration ); - long (*AVI_GetVideoFrameNumber)( void *Avi, float time ); - byte *(*AVI_GetVideoFrame)( void *Avi, long frame ); - void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data ); - void (*AVI_FreeVideo)( void *Avi ); - int (*AVI_IsActive)( void *Avi ); - - // glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client) - void (*GL_Bind)( int tmu, unsigned int texnum ); - void (*GL_SelectTexture)( int tmu ); - void (*GL_LoadTextureMatrix)( const float *glmatrix ); - void (*GL_TexMatrixIdentity)( void ); - void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units - void (*GL_TexGen)( unsigned int coord, unsigned int mode ); - void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture - void (*GL_TexCoordArrayMode)( unsigned int texmode ); - void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility - void (*GL_Reserved1)( void ); - void (*GL_Reserved2)( void ); - void (*GL_Reserved3)( void ); - - // Misc renderer functions - void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags ); - void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder - int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare ); - void (*Host_Error)( const char *error, ... ); // cause Host Error - int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load - void (*TessPolygon)( struct msurface_s *surf, struct model_s *mod, float tessSize ); - struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e ); - const struct ref_overview_s *( *GetOverviewParms )( void ); - void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents) - void (*SetRandomSeed)( long lSeed ); // set custom seed for RANDOM_FLOAT\RANDOM_LONG for predictable random - // static allocations - void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); - void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); - // find in files - char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); - // ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 35 -} render_api_t; - -// render callbacks -typedef struct render_interface_s -{ - int version; - // passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer) - int (*GL_RenderFrame)( const struct ref_params_s *pparams, qboolean drawWorld ); - // build all the lightmaps on new level or when gamma is changed - void (*GL_BuildLightmaps)( void ); - // setup map bounds for ortho-projection when we in dev_overview mode - void (*GL_OrthoBounds)( const float *mins, const float *maxs ); - // handle decals which hit mod_studio or mod_sprite - void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state ); - // prepare studio decals for save - int (*R_CreateStudioDecalList)( decallist_t *pList, int count, qboolean changelevel ); - // clear decals by engine request (e.g. for demo recording or vid_restart) - void (*R_ClearStudioDecals)( void ); - // grab r_speeds message - qboolean (*R_SpeedsMessage)( char *out, size_t size ); - // replace with built-in R_DrawCubemapView for make skyshots or envshots - qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size ); - // alloc or destroy studiomodel custom data - void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer ); -} render_interface_t; - +/* +render_api.h - Xash3D extension for client interface +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef RENDER_API_H +#define RENDER_API_H + +#include "lightstyle.h" +#include "dlight.h" + +// changes for version 28 +// replace decal_t from software declaration to hardware (matched to normal HL) +// mextrasurf_t->increased limit of reserved fields (up from 7 to 32) +// replace R_StoreEfrags with him extended version +// formed group for BSP decal manipulating +// move misc functions at end of the interface +// added new export for clearing studio decals + +#define CL_RENDER_INTERFACE_VERSION 35 +#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals + +#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces)) +#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data)) + +// render info parms +#define PARM_TEX_WIDTH 1 // all parms with prefix 'TEX_' receive arg as texnum +#define PARM_TEX_HEIGHT 2 // otherwise it's not used +#define PARM_TEX_SRC_WIDTH 3 +#define PARM_TEX_SRC_HEIGHT 4 +#define PARM_TEX_SKYBOX 5 // second arg as skybox ordering num +#define PARM_TEX_SKYTEXNUM 6 // skytexturenum for quake sky +#define PARM_TEX_LIGHTMAP 7 // second arg as number 0 - 128 +#define PARM_TEX_TARGET 8 +#define PARM_TEX_TEXNUM 9 +#define PARM_TEX_FLAGS 10 +#define PARM_TEX_TYPE 11 +#define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload +#define PARM_TEX_GLFORMAT 13 // get a texture GL-format +// reserved +#define PARM_WORLD_VERSION 16 // return the version of bsp +#define PARM_SKY_SPHERE 17 // sky is quake sphere ? +#define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs +#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata +#define PARM_MAX_ENTITIES 20 +#define PARM_WIDESCREEN 21 +#define PARM_FULLSCREEN 22 +#define PARM_SCREEN_WIDTH 23 +#define PARM_SCREEN_HEIGHT 24 +#define PARM_CLIENT_INGAME 25 +#define PARM_FEATURES 26 // same as movevars->features +#define PARM_ACTIVE_TMU 27 // for debug +#define PARM_CACHEFRAME 28 +#define PARM_MAX_IMAGE_UNITS 29 +#define PARM_CLIENT_ACTIVE 30 +#define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change + +enum +{ + // skybox ordering + SKYBOX_RIGHT = 0, + SKYBOX_BACK, + SKYBOX_LEFT, + SKYBOX_FORWARD, + SKYBOX_UP, + SKYBOX_DOWN, +}; + +typedef enum +{ + TEX_INVALID = 0, // free slot + TEX_SYSTEM, // generated by engine + TEX_NOMIP, // hud pics, menu etc + TEX_BRUSH, // a map texture + TEX_SPRITE, // sprite frames + TEX_STUDIO, // studio skins + TEX_LIGHTMAP, // lightmap textures + TEX_DECAL, // decals + TEX_VGUI, // vgui fonts or images + TEX_CUBEMAP, // cubemap textures (sky) + TEX_DETAIL, // detail textures + TEX_REMAP, // local copy of remap texture + TEX_SCREENCOPY, // keep screen copy e.g. for mirror + TEX_CUSTOM, // user created texture + TEX_DEPTHMAP // shadowmap texture +} texType_t; + +typedef enum +{ + TF_NEAREST = (1<<0), // disable texfilter + TF_KEEP_RGBDATA = (1<<1), // some images keep source + TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20 + TF_KEEP_8BIT = (1<<3), // keep original 8-bit image (if present) + TF_NOPICMIP = (1<<4), // ignore r_picmip resample rules + TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory + TF_CUBEMAP = (1<<6), // it's cubemap texture + TF_DEPTHMAP = (1<<7), // custom texture filter used + TF_INTENSITY = (1<<8), // monochrome intensity image + TF_LUMINANCE = (1<<9), // force image to grayscale + TF_SKYSIDE = (1<<10), // this is a part of skybox + TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range + TF_NOMIPMAP = (1<<12), // don't build mips for this image + TF_HAS_LUMA = (1<<13), // sets by GL_UploadTexture + TF_MAKELUMA = (1<<14), // create luma from quake texture (only q1 textures contain luma-pixels) + TF_NORMALMAP = (1<<15), // is a normalmap + TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture) + TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures) + TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D + TF_BORDER = (1<<19), // zero clamp for projected textures + TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D + TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine) + TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE + TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference) + TF_IMAGE_PROGRAM = (1<<24), // enable image program support like in Doom3 + TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage + TF_FLOAT = (1<<26), // float textures + TF_NOCOMPARE = (1<<27), // disable comparing for depth textures + TF_FLOATDATA = (1<<28), // incoming dataType has type GL_FLOAT +} texFlags_t; + +typedef struct beam_s BEAM; +typedef struct particle_s particle_t; + +// 12 bytes here +typedef struct modelstate_s +{ + short sequence; + short frame; // 10 bits multiple by 4, should be enough + byte blending[2]; + byte controller[4]; + byte body; + byte skin; +} modelstate_t; + +typedef struct decallist_s +{ + vec3_t position; + char name[64]; + short entityIndex; + byte depth; + byte flags; + float scale; + + // this is the surface plane that we hit so that + // we can move certain decals across + // transitions if they hit similar geometry + vec3_t impactPlaneNormal; + + modelstate_t studio_state; // studio decals only +} decallist_t; + +typedef struct render_api_s +{ + // Get renderer info (doesn't changes engine state at all) + int (*RenderGetParm)( int parm, int arg ); // generic + void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale ); + void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha ); + lightstyle_t* (*GetLightStyle)( int number ); + dlight_t* (*GetDynamicLight)( int number ); + dlight_t* (*GetEntityLight)( int number ); + byte (*TextureToTexGamma)( byte color ); // software gamma support + void (*GetBeamChains)( BEAM ***active_beams, BEAM ***free_beams, particle_t ***free_trails ); + + // Set renderer info (tell engine about changes) + void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel + void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged + void (*GL_SetWorldviewProjectionMatrix)( const float *glmatrix ); // update viewprojection matrix (tracers uses it) + void (*R_StoreEfrags)( struct efrag_s **ppefrag, int framecount );// store efrags for static entities + + // Texture tools + int (*GL_FindTexture)( const char *name ); + const char* (*GL_TextureName)( unsigned int texnum ); + const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL + int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags ); + int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags ); + void (*GL_SetTextureType)( unsigned int texnum, unsigned int type ); + void (*GL_TextureCacheFrame)( unsigned int texnum ); + void (*GL_FreeTexture)( unsigned int texnum ); + + // Decals manipulating (draw & remove) + void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa ); + float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount ); + void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only) + + // AVIkit support + void *(*AVI_LoadVideo)( const char *filename, int ignore_hwgamma ); + int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration ); + long (*AVI_GetVideoFrameNumber)( void *Avi, float time ); + byte *(*AVI_GetVideoFrame)( void *Avi, long frame ); + void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data ); + void (*AVI_FreeVideo)( void *Avi ); + int (*AVI_IsActive)( void *Avi ); + + // glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client) + void (*GL_Bind)( int tmu, unsigned int texnum ); + void (*GL_SelectTexture)( int tmu ); + void (*GL_LoadTextureMatrix)( const float *glmatrix ); + void (*GL_TexMatrixIdentity)( void ); + void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units + void (*GL_TexGen)( unsigned int coord, unsigned int mode ); + void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture + void (*GL_TexCoordArrayMode)( unsigned int texmode ); + void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility + void (*GL_Reserved1)( void ); + void (*GL_Reserved2)( void ); + void (*GL_Reserved3)( void ); + + // Misc renderer functions + void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags ); + void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder + int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare ); + void (*Host_Error)( const char *error, ... ); // cause Host Error + int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load + void (*TessPolygon)( struct msurface_s *surf, struct model_s *mod, float tessSize ); + struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e ); + const struct ref_overview_s *( *GetOverviewParms )( void ); + void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents) + void (*SetRandomSeed)( long lSeed ); // set custom seed for RANDOM_FLOAT\RANDOM_LONG for predictable random + // static allocations + void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); + // find in files + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); + // ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 35 +} render_api_t; + +// render callbacks +typedef struct render_interface_s +{ + int version; + // passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer) + int (*GL_RenderFrame)( const struct ref_params_s *pparams, qboolean drawWorld ); + // build all the lightmaps on new level or when gamma is changed + void (*GL_BuildLightmaps)( void ); + // setup map bounds for ortho-projection when we in dev_overview mode + void (*GL_OrthoBounds)( const float *mins, const float *maxs ); + // handle decals which hit mod_studio or mod_sprite + void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state ); + // prepare studio decals for save + int (*R_CreateStudioDecalList)( decallist_t *pList, int count, qboolean changelevel ); + // clear decals by engine request (e.g. for demo recording or vid_restart) + void (*R_ClearStudioDecals)( void ); + // grab r_speeds message + qboolean (*R_SpeedsMessage)( char *out, size_t size ); + // replace with built-in R_DrawCubemapView for make skyshots or envshots + qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size ); + // alloc or destroy studiomodel custom data + void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer ); +} render_interface_t; + #endif//RENDER_API_H \ No newline at end of file diff --git a/common/screenfade.h b/common/screenfade.h index 872508b2..730f729e 100644 --- a/common/screenfade.h +++ b/common/screenfade.h @@ -1,29 +1,29 @@ -/*** -* -* 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 SCREENFADE_H -#define SCREENFADE_H - -typedef struct screenfade_s -{ - float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) - float fadeEnd; // When the fading hits maximum - float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) - float fadeReset; // When to reset to not fading (for fadeout and hold) - byte fader, fadeg, fadeb, fadealpha; // Fade color - int fadeFlags; // Fading flags -} screenfade_t; - +/*** +* +* 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 SCREENFADE_H +#define SCREENFADE_H + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + #endif//SCREENFADE_H \ No newline at end of file diff --git a/common/studio_event.h b/common/studio_event.h index bd451817..29ea1f90 100644 --- a/common/studio_event.h +++ b/common/studio_event.h @@ -1,27 +1,27 @@ -/*** -* -* 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 STUDIO_EVENT_H -#define STUDIO_EVENT_H - -typedef struct mstudioevent_s -{ - int frame; - int event; - int type; - char options[64]; -} mstudioevent_t; - +/*** +* +* 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 STUDIO_EVENT_H +#define STUDIO_EVENT_H + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + #endif//STUDIO_EVENT_H \ No newline at end of file diff --git a/common/triangleapi.h b/common/triangleapi.h index d975a26e..f83c7ff0 100644 --- a/common/triangleapi.h +++ b/common/triangleapi.h @@ -1,62 +1,62 @@ -/*** -* -* 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 TRIANGLEAPI_H -#define TRIANGLEAPI_H - -typedef enum -{ - TRI_FRONT = 0, - TRI_NONE = 1, -} TRICULLSTYLE; - -#define TRI_API_VERSION 1 - -#define TRI_TRIANGLES 0 -#define TRI_TRIANGLE_FAN 1 -#define TRI_QUADS 2 -#define TRI_POLYGON 3 -#define TRI_LINES 4 -#define TRI_TRIANGLE_STRIP 5 -#define TRI_QUAD_STRIP 6 -#define TRI_POINTS 7 // Xash3D added - -typedef struct triangleapi_s -{ - int version; - - void (*RenderMode)( int mode ); - void (*Begin)( int primitiveCode ); - void (*End)( void ); - - void (*Color4f)( float r, float g, float b, float a ); - void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); - void (*TexCoord2f)( float u, float v ); - void (*Vertex3fv)( float *worldPnt ); - void (*Vertex3f)( float x, float y, float z ); - void (*Brightness)( float brightness ); - void (*CullFace)( TRICULLSTYLE style ); - int (*SpriteTexture)( struct model_s *pSpriteModel, int frame ); - int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped - void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. - void (*ScreenToWorld)( float *screen, float *world ); - void (*GetMatrix)( const int pname, float *matrix ); - int (*BoxInPVS)( float *mins, float *maxs ); - void (*LightAtPoint)( float *pos, float *value ); - void (*Color4fRendermode)( float r, float g, float b, float a, int rendermode ); - void (*FogParams)( float flDensity, int iFogSkybox ); -} triangleapi_t; - +/*** +* +* 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 TRIANGLEAPI_H +#define TRIANGLEAPI_H + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 +#define TRI_POINTS 7 // Xash3D added + +typedef struct triangleapi_s +{ + int version; + + void (*RenderMode)( int mode ); + void (*Begin)( int primitiveCode ); + void (*End)( void ); + + void (*Color4f)( float r, float g, float b, float a ); + void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void (*TexCoord2f)( float u, float v ); + void (*Vertex3fv)( float *worldPnt ); + void (*Vertex3f)( float x, float y, float z ); + void (*Brightness)( float brightness ); + void (*CullFace)( TRICULLSTYLE style ); + int (*SpriteTexture)( struct model_s *pSpriteModel, int frame ); + int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped + void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. + void (*ScreenToWorld)( float *screen, float *world ); + void (*GetMatrix)( const int pname, float *matrix ); + int (*BoxInPVS)( float *mins, float *maxs ); + void (*LightAtPoint)( float *pos, float *value ); + void (*Color4fRendermode)( float r, float g, float b, float a, int rendermode ); + void (*FogParams)( float flDensity, int iFogSkybox ); +} triangleapi_t; + #endif//TRIANGLEAPI_H \ No newline at end of file diff --git a/common/usercmd.h b/common/usercmd.h index c23b9173..96e3c91b 100644 --- a/common/usercmd.h +++ b/common/usercmd.h @@ -1,39 +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 USERCMD_H -#define USERCMD_H - -typedef struct usercmd_s -{ - short lerp_msec; // Interpolation time on client - byte msec; // Duration in ms of command - vec3_t viewangles; // Command view angles - - // intended velocities - float forwardmove; // Forward velocity - float sidemove; // Sideways velocity - float upmove; // Upward velocity - byte lightlevel; // Light level at spot where we are standing. - unsigned short buttons; // Attack and move buttons - byte impulse; // Impulse command issued - byte weaponselect; // Current weapon id - - // Experimental player impact stuff. - int impact_index; - vec3_t impact_position; -} usercmd_t; - +/*** +* +* 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 USERCMD_H +#define USERCMD_H + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles + + // intended velocities + float forwardmove; // Forward velocity + float sidemove; // Sideways velocity + float upmove; // Upward velocity + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack and move buttons + byte impulse; // Impulse command issued + byte weaponselect; // Current weapon id + + // Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + #endif//USERCMD_H \ No newline at end of file diff --git a/common/wadfile.h b/common/wadfile.h index 80d54a8f..38a08032 100644 --- a/common/wadfile.h +++ b/common/wadfile.h @@ -1,79 +1,79 @@ -/*** -* -* 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 WADFILE_H -#define WADFILE_H - -/* -======================================================================== -.WAD archive format (WhereAllData - WAD) - -List of compressed files, that can be identify only by TYPE_* - - -header: dwadinfo_t[dwadinfo_t] -file_1: byte[dwadinfo_t[num]->disksize] -file_2: byte[dwadinfo_t[num]->disksize] -file_3: byte[dwadinfo_t[num]->disksize] -... -file_n: byte[dwadinfo_t[num]->disksize] -infotable dlumpinfo_t[dwadinfo_t->numlumps] -======================================================================== -*/ - -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') - -// dlumpinfo_t->compression -#define CMP_NONE 0 // compression none -#define CMP_LZSS 1 // LZSS compression - -// dlumpinfo_t->type -#define TYP_QPAL 64 // quake palette -#define TYP_QTEX 65 // probably was never used -#define TYP_QPIC 66 // quake1 and hl pic (lmp_t) -#define TYP_MIPTEX 67 // half-life (mip_t) previous was TYP_SOUND but never used in quake1 -#define TYP_QMIP 68 // quake1 (mip_t) (replaced with TYPE_MIPTEX while loading) -#define TYP_RAW 69 // raw data -#define TYP_QFONT 70 // half-life font (qfont_t) - -/* -======================================================================== - -.LMP image format (Half-Life gfx.wad lumps) - -======================================================================== -*/ -typedef struct lmp_s -{ - unsigned int width; - unsigned int height; -} lmp_t; - -/* -======================================================================== - -.MIP image format (half-Life textures) - -======================================================================== -*/ -typedef struct mip_s -{ - char name[16]; - unsigned int width; - unsigned int height; - unsigned int offsets[4]; // four mip maps stored -} mip_t; - +/*** +* +* 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 WADFILE_H +#define WADFILE_H + +/* +======================================================================== +.WAD archive format (WhereAllData - WAD) + +List of compressed files, that can be identify only by TYPE_* + + +header: dwadinfo_t[dwadinfo_t] +file_1: byte[dwadinfo_t[num]->disksize] +file_2: byte[dwadinfo_t[num]->disksize] +file_3: byte[dwadinfo_t[num]->disksize] +... +file_n: byte[dwadinfo_t[num]->disksize] +infotable dlumpinfo_t[dwadinfo_t->numlumps] +======================================================================== +*/ + +#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') + +// dlumpinfo_t->compression +#define CMP_NONE 0 // compression none +#define CMP_LZSS 1 // LZSS compression + +// dlumpinfo_t->type +#define TYP_QPAL 64 // quake palette +#define TYP_QTEX 65 // probably was never used +#define TYP_QPIC 66 // quake1 and hl pic (lmp_t) +#define TYP_MIPTEX 67 // half-life (mip_t) previous was TYP_SOUND but never used in quake1 +#define TYP_QMIP 68 // quake1 (mip_t) (replaced with TYPE_MIPTEX while loading) +#define TYP_RAW 69 // raw data +#define TYP_QFONT 70 // half-life font (qfont_t) + +/* +======================================================================== + +.LMP image format (Half-Life gfx.wad lumps) + +======================================================================== +*/ +typedef struct lmp_s +{ + unsigned int width; + unsigned int height; +} lmp_t; + +/* +======================================================================== + +.MIP image format (half-Life textures) + +======================================================================== +*/ +typedef struct mip_s +{ + char name[16]; + unsigned int width; + unsigned int height; + unsigned int offsets[4]; // four mip maps stored +} mip_t; + #endif//WADFILE_H \ No newline at end of file diff --git a/common/weaponinfo.h b/common/weaponinfo.h index f1810a0c..ae78c645 100644 --- a/common/weaponinfo.h +++ b/common/weaponinfo.h @@ -1,50 +1,50 @@ -/*** -* -* 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 WEAPONINFO_H -#define WEAPONINFO_H - -// Info about weapons player might have in his/her possession -typedef struct weapon_data_s -{ - int m_iId; - int m_iClip; - - float m_flNextPrimaryAttack; - float m_flNextSecondaryAttack; - float m_flTimeWeaponIdle; - - int m_fInReload; - int m_fInSpecialReload; - float m_flNextReload; - float m_flPumpTime; - float m_fReloadTime; - - float m_fAimedDamage; - float m_fNextAimBonus; - int m_fInZoom; - int m_iWeaponState; - - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; -} weapon_data_t; - +/*** +* +* 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 WEAPONINFO_H +#define WEAPONINFO_H + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + #endif//WEAPONINFO_H \ No newline at end of file diff --git a/common/wrect.h b/common/wrect.h index 83bcbd75..8dd2ba2f 100644 --- a/common/wrect.h +++ b/common/wrect.h @@ -1,24 +1,24 @@ -/* -wrect.h - rectangle definition -Copyright (C) 2010 Uncle Mike - -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. -*/ - -#ifndef WRECT_H -#define WRECT_H - -typedef struct wrect_s -{ - int left, right, top, bottom; -} wrect_t; - +/* +wrect.h - rectangle definition +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef WRECT_H +#define WRECT_H + +typedef struct wrect_s +{ + int left, right, top, bottom; +} wrect_t; + #endif//WRECT_H \ No newline at end of file diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/dlls/AI_BaseNPC_Schedule.cpp index f1eb367d..468bb358 100644 --- a/dlls/AI_BaseNPC_Schedule.cpp +++ b/dlls/AI_BaseNPC_Schedule.cpp @@ -1,1514 +1,1514 @@ -/*** -* -* 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 ]; -} +/*** +* +* 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/dlls/Wxdebug.cpp b/dlls/Wxdebug.cpp index d3902d6c..26d0d381 100644 --- a/dlls/Wxdebug.cpp +++ b/dlls/Wxdebug.cpp @@ -1,395 +1,395 @@ -//==========================================================================; -// -// 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 - - +//==========================================================================; +// +// 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/dlls/activity.h b/dlls/activity.h index 37c82b6e..6fd3a188 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -1,109 +1,109 @@ -/*** -* -* 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; - char *name; -} activity_map_t; - -extern activity_map_t activity_map[]; - - -#endif //ACTIVITY_H +/*** +* +* 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; + char *name; +} activity_map_t; + +extern activity_map_t activity_map[]; + + +#endif //ACTIVITY_H diff --git a/dlls/activitymap.h b/dlls/activitymap.h index b72c4e4d..92cadae7 100644 --- a/dlls/activitymap.h +++ b/dlls/activitymap.h @@ -1,97 +1,97 @@ -/*** -* -* 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 -}; +/*** +* +* 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/dlls/aflock.cpp b/dlls/aflock.cpp index 95e3dc16..24532eeb 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -1,910 +1,910 @@ -/*** -* -* 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. -* -****/ -//========================================================= -//========================================================= -#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 - int cProcessed = 0;// keep track of how many other boids we've processed - 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; - } -} +/*** +* +* 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. +* +****/ +//========================================================= +//========================================================= +#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 + int cProcessed = 0;// keep track of how many other boids we've processed + 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/dlls/agrunt.cpp b/dlls/agrunt.cpp index ff31e8ce..b1022694 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -1,1186 +1,1186 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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() -{ - int 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 != NULL ) - { - 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 ); - } - } - - 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 != NULL ) - { - // 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 ); -} - +/*** +* +* 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. +* +****/ +//========================================================= +// 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() +{ + int 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 != NULL ) + { + 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 ); + } + } + + 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 != NULL ) + { + // 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/dlls/airtank.cpp b/dlls/airtank.cpp index 27901fc7..9a914021 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -1,118 +1,118 @@ -/*** -* -* 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 ); -} +/*** +* +* 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/dlls/animating.cpp b/dlls/animating.cpp index 6afc3956..808cdd29 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -1,318 +1,318 @@ -/*** -* -* 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 ); - } -} - +/*** +* +* 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/dlls/animation.cpp b/dlls/animation.cpp index a4658726..fa44348a 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -1,526 +1,526 @@ -/*** -* -* 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 - -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 "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; - -#pragma warning( disable : 4244 ) - - - -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; - - int events = 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; +/*** +* +* 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 + +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 "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; + +#pragma warning( disable : 4244 ) + + + +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; + + int events = 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 = 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 = 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; + + 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 = 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 = 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; } \ No newline at end of file diff --git a/dlls/animation.h b/dlls/animation.h index 77281673..174bd712 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -1,47 +1,47 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/apache.cpp b/dlls/apache.cpp index 607679bf..ee3a86a2 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -1,1050 +1,1050 @@ -/*** -* -* 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. -* -****/ -#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( &CBaseEntity::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 != NULL) - { - // 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 != NULL) - { - // 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; - static int count; - - 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( &CGrenade::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; -} - - +/*** +* +* 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. +* +****/ +#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( &CBaseEntity::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 != NULL) + { + // 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 != NULL) + { + // 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; + static int count; + + 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( &CGrenade::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/dlls/barnacle.cpp b/dlls/barnacle.cpp index 1681b5a3..dddcc50e 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -1,449 +1,449 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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_flCachedLength; // tongue cached length - 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; - - // FIXME: need a custom barnacle model with non-generic hitgroup - // otherwise we can apply to damage to tongue instead of body -#ifdef BARNACLE_FIX_VISIBILITY - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -16, -16, -m_flCachedLength ); - pev->absmax = pev->origin + Vector( 16, 16, 0 ); - } -#endif -}; -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 ), - DEFINE_FIELD( CBarnacle, m_flCachedLength, 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_flCachedLength = 32; // mins.z - 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; - -#ifdef BARNACLE_FIX_VISIBILITY - if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength )) - { - // recalc collision box here to avoid barnacle disappears bug - m_flCachedLength = (m_flAltitude + m_flTongueAdj); - UTIL_SetOrigin( pev, pev->origin ); - } -#endif - pev->nextthink = gpGlobals->time + 0.1; - - if ( m_hEnemy != NULL ) - { -// 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 != NULL && 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 != NULL ) - { - 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; -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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_flCachedLength; // tongue cached length + 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; + + // FIXME: need a custom barnacle model with non-generic hitgroup + // otherwise we can apply to damage to tongue instead of body +#ifdef BARNACLE_FIX_VISIBILITY + void SetObjectCollisionBox( void ) + { + pev->absmin = pev->origin + Vector( -16, -16, -m_flCachedLength ); + pev->absmax = pev->origin + Vector( 16, 16, 0 ); + } +#endif +}; +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 ), + DEFINE_FIELD( CBarnacle, m_flCachedLength, 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_flCachedLength = 32; // mins.z + 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; + +#ifdef BARNACLE_FIX_VISIBILITY + if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength )) + { + // recalc collision box here to avoid barnacle disappears bug + m_flCachedLength = (m_flAltitude + m_flTongueAdj); + UTIL_SetOrigin( pev, pev->origin ); + } +#endif + pev->nextthink = gpGlobals->time + 0.1; + + if ( m_hEnemy != NULL ) + { +// 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 != NULL && 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 != NULL ) + { + 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/dlls/barney.cpp b/dlls/barney.cpp index 9cfa6a37..095de85d 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -1,841 +1,841 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 != NULL && (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 != NULL ) - { - 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( &CTalkMonster::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 == NULL ) - { - // 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 ); - - CBaseEntity *pGun = 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 != NULL ) - { - // 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 == NULL && 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; - } - - 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 char *m_szPoses[3]; -}; - -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(); -} - - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL && (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 != NULL ) + { + 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( &CTalkMonster::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 == NULL ) + { + // 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 ); + + CBaseEntity *pGun = 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 != NULL ) + { + // 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 == NULL && 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; + } + + 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 char *m_szPoses[3]; +}; + +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/dlls/basemonster.h b/dlls/basemonster.h index 04fbce91..190965d9 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -1,339 +1,339 @@ -/*** -* -* 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. -* -****/ - -#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 ( 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 ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. -}; - - - -#endif // BASEMONSTER_H +/*** +* +* 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. +* +****/ + +#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 ( 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 ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. +}; + + + +#endif // BASEMONSTER_H diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index b7f999d1..d22cb464 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -1,1251 +1,1251 @@ -/*** -* -* 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. -* -****/ -#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 == NULL ) - 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 == NULL ) - 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 != NULL && (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; - float distance = vecGrenadeVel.Length(); - - // 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 +/*** +* +* 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. +* +****/ +#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 == NULL ) + 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 == NULL ) + 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 != NULL && (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; + float distance = vecGrenadeVel.Length(); + + // 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/dlls/bloater.cpp b/dlls/bloater.cpp index 889b866e..1f14840d 100644 --- a/dlls/bloater.cpp +++ b/dlls/bloater.cpp @@ -1,219 +1,219 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 -//========================================================= - +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/bmodels.cpp b/dlls/bmodels.cpp index bc788a93..15d35c7c 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -1,958 +1,958 @@ -/*** -* -* 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 = atof(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( &CBaseEntity::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 = fabs(vecAVel.x != 0 ? vecAVel.x : (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 = fabs(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 ( fabs(vecAVel.x) >= fabs(pev->movedir.x * pev->speed) && - fabs(vecAVel.y) >= fabs(pev->movedir.y * pev->speed) && - fabs(vecAVel.z) >= fabs(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, 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( &CBaseEntity::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; -} - - +/*** +* +* 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 = atof(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( &CBaseEntity::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 = fabs(vecAVel.x != 0 ? vecAVel.x : (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 = fabs(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 ( fabs(vecAVel.x) >= fabs(pev->movedir.x * pev->speed) && + fabs(vecAVel.y) >= fabs(pev->movedir.y * pev->speed) && + fabs(vecAVel.z) >= fabs(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, 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( &CBaseEntity::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/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 0e34a537..4a14f247 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -1,1275 +1,1275 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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( &CBaseEntity::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 != NULL ) - { - 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 != NULL && 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 != NULL ) - { - 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 ) -{ - int 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 != NULL && 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; - } - } - - 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 != NULL && ( 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 = NULL; - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - break; - } - } - - m_IdealMonsterState = CBaseMonster :: GetIdealState(); - - return m_IdealMonsterState; -} - +/*** +* +* 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. +* +****/ +//========================================================= +// 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( &CBaseEntity::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 != NULL ) + { + 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 != NULL && 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 != NULL ) + { + 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 ) +{ + int 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 != NULL && 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; + } + } + + 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 != NULL && ( 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 = NULL; + m_IdealMonsterState = MONSTERSTATE_ALERT; + } + break; + } + } + + m_IdealMonsterState = CBaseMonster :: GetIdealState(); + + return m_IdealMonsterState; +} + diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 8ca2ad60..5856cd11 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -1,1276 +1,1276 @@ -/*** -* -* 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" - - -#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( &CBaseEntity::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 ) -{ - 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 = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(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 == NULL ) - 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( ) -{ - 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 - -char *ButtonSound( int sound ) -{ - 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 ) -{ - 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( &CBaseButton::ButtonUse ); - } - else // touchable button - SetTouch( &CBaseButton::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) ); - - 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 ); - UpdateTarget( pev->ideal_yaw ); -} - -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; -} +/*** +* +* 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" + + +#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( &CBaseEntity::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 ) +{ + 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(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 == NULL ) + 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( ) +{ + 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 + +char *ButtonSound( int sound ) +{ + 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 ) +{ + 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( &CBaseButton::ButtonUse ); + } + else // touchable button + SetTouch( &CBaseButton::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) ); + + 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 ); + UpdateTarget( pev->ideal_yaw ); +} + +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/dlls/cbase.cpp b/dlls/cbase.cpp index 73c63ae3..e00ef46f 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -1,774 +1,774 @@ -/*** -* -* 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( 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 ); - -#ifndef _WIN32 -extern "C" { -#endif -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; -} - -#ifndef _WIN32 -} -#endif - - -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( 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; -} - - +/*** +* +* 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( 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 ); + +#ifndef _WIN32 +extern "C" { +#endif +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; +} + +#ifndef _WIN32 +} +#endif + + +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( 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/dlls/cbase.h b/dlls/cbase.h index 1aefe687..88094c39 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -1,800 +1,800 @@ -/*** -* -* 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 "saverestore.h" -#include "schedule.h" - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -// C functions for external declarations that call the appropriate C++ methods - -#include "exportdef.h" - -extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); -extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); -extern "C" EXPORT int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ); - -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, 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 _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((unsigned long)(pFunction)) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)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( 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) -#define ResetThink( ) m_pfnThink = static_cast (NULL) -#define ResetTouch( ) m_pfnTouch = static_cast (NULL) -#define ResetUse( ) m_pfnUse = static_cast (NULL) -#define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) - - -#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" - - -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 ); -}; +/*** +* +* 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 "saverestore.h" +#include "schedule.h" + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +// C functions for external declarations that call the appropriate C++ methods + +#include "exportdef.h" + +extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); +extern "C" EXPORT int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ); + +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, 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 _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((unsigned long)(pFunction)) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)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( 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) +#define ResetThink( ) m_pfnThink = static_cast (NULL) +#define ResetTouch( ) m_pfnTouch = static_cast (NULL) +#define ResetUse( ) m_pfnUse = static_cast (NULL) +#define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) + + +#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" + + +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/dlls/cdll_dll.h b/dlls/cdll_dll.h index 2293a27e..daefd1ee 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -1,46 +1,46 @@ -/*** -* -* 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 - +/*** +* +* 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 \ No newline at end of file diff --git a/dlls/client.cpp b/dlls/client.cpp index f17b6e54..02ba4582 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1,1809 +1,1809 @@ -/*** -* -* 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" - -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 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] = ""; +/*** +* +* 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" + +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 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) ); - 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; + snprintf( text, sizeof(text), "- %s has left the game\n", STRING(pEntity->v.netname) ); + 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; pPlayer->pev->iuser2 = 0; -} - -#include "voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -//// 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, *pc; - 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 - for ( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if ( !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if ( pc != NULL ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - 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 ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - 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 ); - - 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, "fire") ) - { - if ( g_flWeaponCheat != 0.0) - { - CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); - if (CMD_ARGC() > 1) - { - FireTargets(CMD_ARGV(1), pPlayer, pPlayer, USE_TOGGLE, 0); - } - else - { - TraceResult tr; - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine( - pev->origin + pev->view_ofs, - pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, - dont_ignore_monsters, pEntity, &tr - ); - - if (tr.pHit) - { - CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); - if (pHitEnt) - { - pHitEnt->Use(pPlayer, pPlayer, USE_TOGGLE, 0); - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); - } - } - } - } - } - 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" ) && (pev->flags & FL_PROXY) ) // added for proxy support - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - - edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); - } - 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 if ( FStrEq(pcmd, "VModEnable") ) - { - // clear 'Unknown command: VModEnable' in singleplayer - return; - } - 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 ); - - char text[256]; - snprintf( text, 256, "* %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 ) -{ -// ALERT( at_console, "ServerDeactivate()\n" ); - - // 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; - -// ALERT( at_console, "ServerActivate()\n" ); - - // 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 ) -{ -// ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - - entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PreThink( ); -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ -// ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - - entvars_t *pev = &pEntity->v; - 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 ) -{ -// ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - - 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 ) -{ - entvars_t *pev = &pEntity->v; - 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 ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - 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; - } - - if( pView->v.effects & EF_MERGE_VISIBILITY ) - { - if( FClassnameIs( pView, "env_sky" )) - { - org = pView->v.origin; - } - else return; // don't merge pvs - } - else - { - 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 ) ) - { - // env_sky is visible always - if( !FClassnameIs( ent, "env_sky" )) - { - 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 & 4 ) return 0; // it's a portal pass - 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 ) ); - memcpy( state->velocity, ent->v.velocity, 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 = ent->v.renderamt; - state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor.x; - state->rendercolor.g = ent->v.rendercolor.y; - state->rendercolor.b = 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; - } - } - - state->onground = 0; - if ( ent->v.groundentity ) - { - state->onground = ENTINDEX( ent->v.groundentity ); - } - - // 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 = 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, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, player_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 = ( 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 = (CBasePlayerWeapon *)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 struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) -{ - cd->flags = ent->v.flags; - cd->health = ent->v.health; - - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); - - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; - - // Vectors - cd->origin = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; - - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; - - cd->pushmsec = ent->v.pushmsec; - -#if defined( CLIENT_WEAPONS ) - if ( sendweapons ) - { - entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - - 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 = ( 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 = ( 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 ) -{ - // Parse stuff from args - int max_buffer_size = *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 ) -{ - int iret = 0; - 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; -} +} + +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + +//// 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, *pc; + 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 + for ( pc = p; pc != NULL && *pc != 0; pc++ ) + { + if ( !isspace( *pc ) ) + { + pc = NULL; // we've found an alphanumeric character, so text is valid + break; + } + } + if ( pc != NULL ) + return; // no character found, so say nothing + +// turn on color set 2 (color on, no sound) + 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 ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) + 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 ); + + 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, "fire") ) + { + if ( g_flWeaponCheat != 0.0) + { + CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); + if (CMD_ARGC() > 1) + { + FireTargets(CMD_ARGV(1), pPlayer, pPlayer, USE_TOGGLE, 0); + } + else + { + TraceResult tr; + UTIL_MakeVectors(pev->v_angle); + UTIL_TraceLine( + pev->origin + pev->view_ofs, + pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, + dont_ignore_monsters, pEntity, &tr + ); + + if (tr.pHit) + { + CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); + if (pHitEnt) + { + pHitEnt->Use(pPlayer, pPlayer, USE_TOGGLE, 0); + ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); + } + } + } + } + } + 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" ) && (pev->flags & FL_PROXY) ) // added for proxy support + { + CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + + edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); + } + 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 if ( FStrEq(pcmd, "VModEnable") ) + { + // clear 'Unknown command: VModEnable' in singleplayer + return; + } + 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 ); + + char text[256]; + snprintf( text, 256, "* %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 ) +{ +// ALERT( at_console, "ServerDeactivate()\n" ); + + // 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; + +// ALERT( at_console, "ServerActivate()\n" ); + + // 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 ) +{ +// ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + entvars_t *pev = &pEntity->v; + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->PreThink( ); +} + +/* +================ +PlayerPostThink + +Called every frame after physics are run +================ +*/ +void PlayerPostThink( edict_t *pEntity ) +{ +// ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + entvars_t *pev = &pEntity->v; + 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 ) +{ +// ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + + 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 ) +{ + entvars_t *pev = &pEntity->v; + 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 ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorConnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has left the game +================ +*/ +void SpectatorDisconnect( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + + if (pPlayer) + pPlayer->SpectatorDisconnect( ); +} + +/* +================ +SpectatorConnect + +A spectator has sent a usercmd +================ +*/ +void SpectatorThink( edict_t *pEntity ) +{ + entvars_t *pev = &pEntity->v; + 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; + } + + if( pView->v.effects & EF_MERGE_VISIBILITY ) + { + if( FClassnameIs( pView, "env_sky" )) + { + org = pView->v.origin; + } + else return; // don't merge pvs + } + else + { + 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 ) ) + { + // env_sky is visible always + if( !FClassnameIs( ent, "env_sky" )) + { + 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 & 4 ) return 0; // it's a portal pass + 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 ) ); + memcpy( state->velocity, ent->v.velocity, 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 = ent->v.renderamt; + state->renderfx = ent->v.renderfx; + state->rendercolor.r = ent->v.rendercolor.x; + state->rendercolor.g = ent->v.rendercolor.y; + state->rendercolor.b = 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; + } + } + + state->onground = 0; + if ( ent->v.groundentity ) + { + state->onground = ENTINDEX( ent->v.groundentity ); + } + + // 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 = 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, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, player_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 = ( 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 = (CBasePlayerWeapon *)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 struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + cd->flags = ent->v.flags; + cd->health = ent->v.health; + + cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + + cd->waterlevel = ent->v.waterlevel; + cd->watertype = ent->v.watertype; + cd->weapons = ent->v.weapons; + + // Vectors + cd->origin = ent->v.origin; + cd->velocity = ent->v.velocity; + cd->view_ofs = ent->v.view_ofs; + cd->punchangle = ent->v.punchangle; + + cd->bInDuck = ent->v.bInDuck; + cd->flTimeStepSound = ent->v.flTimeStepSound; + cd->flDuckTime = ent->v.flDuckTime; + cd->flSwimTime = ent->v.flSwimTime; + cd->waterjumptime = ent->v.teleport_time; + + strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); + + cd->maxspeed = ent->v.maxspeed; + cd->fov = ent->v.fov; + cd->weaponanim = ent->v.weaponanim; + + cd->pushmsec = ent->v.pushmsec; + +#if defined( CLIENT_WEAPONS ) + if ( sendweapons ) + { + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + 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 = ( 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 = ( 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 ) +{ + // Parse stuff from args + int max_buffer_size = *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 ) +{ + int iret = 0; + 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/dlls/client.h b/dlls/client.h index 2e0b38ed..1e66cc89 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -1,65 +1,65 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/combat.cpp b/dlls/combat.cpp index 9fec6047..5d7679fd 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -1,1711 +1,1711 @@ -/*** -* -* 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( &CBaseEntity::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; - BOOL fTriedDirection; - float flDot; - - fTriedDirection = FALSE; - 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 ) -{ - unsigned int cCount = 0; - BOOL fDone = FALSE; - - 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( &CBaseEntity::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( &CBaseEntity::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 == NULL || 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; - +/*** +* +* 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( &CBaseEntity::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; + BOOL fTriedDirection; + float flDot; + + fTriedDirection = FALSE; + 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 ) +{ + unsigned int cCount = 0; + BOOL fDone = FALSE; + + 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( &CBaseEntity::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( &CBaseEntity::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 == NULL || 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(!pEntity) return FALSE; if(!pEntity->pev) return FALSE; - 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, (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 ) -{ - static int tracerCount; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - float x, y, 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, (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() ); - } - } -} + 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, (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 ) +{ + static int tracerCount; + TraceResult tr; + Vector vecRight = gpGlobals->v_right; + Vector vecUp = gpGlobals->v_up; + float x, y, 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, (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/dlls/controller.cpp b/dlls/controller.cpp index 7e4dc1d0..629714d6 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -1,1427 +1,1427 @@ -/*** -* -* 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. -* -****/ -#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 != NULL) - { - 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: - { - Vector vecTmp = 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; - } - - 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_iTrail; - 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 == NULL || m_hOwner == NULL || 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 != NULL) - { - 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 +/*** +* +* 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. +* +****/ +#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 != NULL) + { + 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: + { + Vector vecTmp = 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; + } + + 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_iTrail; + 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 == NULL || m_hOwner == NULL || 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 != NULL) + { + 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/dlls/crossbow.cpp b/dlls/crossbow.cpp index 59870b87..28bd8cfd 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -1,564 +1,564 @@ -/*** -* -* 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("crossbow_bolt"); // g-cont. enable save\restore - 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( &CBaseEntity::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; - } - else if ( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) - { - Vector vecDir = pev->velocity.Normalize( ); - UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG(0,360); - pev->nextthink = gpGlobals->time + 10.0; - - // g-cont. Setup movewith feature - pev->movetype = MOVETYPE_COMPOUND; // set movewith type - pev->aiment = ENT( pOther->pev ); // set parent - } - - 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 = UTIL_WeaponTimeBase() + 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; - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - -#ifndef CLIENT_DLL - 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 = UTIL_WeaponTimeBase() + 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; - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - } -} - - - -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 ); - - - +/*** +* +* 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("crossbow_bolt"); // g-cont. enable save\restore + 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( &CBaseEntity::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; + } + else if ( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) + { + Vector vecDir = pev->velocity.Normalize( ); + UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); + pev->angles = UTIL_VecToAngles( vecDir ); + pev->solid = SOLID_NOT; + pev->velocity = Vector( 0, 0, 0 ); + pev->avelocity.z = 0; + pev->angles.z = RANDOM_LONG(0,360); + pev->nextthink = gpGlobals->time + 10.0; + + // g-cont. Setup movewith feature + pev->movetype = MOVETYPE_COMPOUND; // set movewith type + pev->aiment = ENT( pOther->pev ); // set parent + } + + 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 = UTIL_WeaponTimeBase() + 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; + Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; + Vector vecDir = gpGlobals->v_forward; + +#ifndef CLIENT_DLL + 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 = UTIL_WeaponTimeBase() + 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; + } + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } + } +} + + + +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/dlls/crowbar.cpp b/dlls/crowbar.cpp index ef21e503..7225e747 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -1,318 +1,318 @@ -/*** -* -* 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, 0.0 ); - - - if ( tr.flFraction >= 1.0 ) - { - if (fFirst) - { - // miss - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 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 = flVol * CROWBAR_WALLHIT_VOLUME; -#endif - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - - SetThink( &CCrowbar::Smack ); - pev->nextthink = UTIL_WeaponTimeBase() + 0.2; - - - } - return fDidHit; -} - - - +/*** +* +* 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, 0.0 ); + + + if ( tr.flFraction >= 1.0 ) + { + if (fFirst) + { + // miss + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 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 = flVol * CROWBAR_WALLHIT_VOLUME; +#endif + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + + SetThink( &CCrowbar::Smack ); + pev->nextthink = UTIL_WeaponTimeBase() + 0.2; + + + } + return fDidHit; +} + + + diff --git a/dlls/decals.h b/dlls/decals.h index 0f8ff4ed..95fa44f5 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -1,75 +1,75 @@ -/*** -* -* 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 -{ - char *name; - int index; -} DLL_DECALLIST; - -extern DLL_DECALLIST gDecals[]; - -#endif // DECALS_H +/*** +* +* 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 +{ + char *name; + int index; +} DLL_DECALLIST; + +extern DLL_DECALLIST gDecals[]; + +#endif // DECALS_H diff --git a/dlls/defaultai.cpp b/dlls/defaultai.cpp index efc0087e..645fa916 100644 --- a/dlls/defaultai.cpp +++ b/dlls/defaultai.cpp @@ -1,1232 +1,1232 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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; -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/defaultai.h b/dlls/defaultai.h index 271ac7aa..652d1085 100644 --- a/dlls/defaultai.h +++ b/dlls/defaultai.h @@ -1,98 +1,98 @@ -/*** -* -* 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. -* -****/ -#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 +/*** +* +* 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. +* +****/ +#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/dlls/doors.cpp b/dlls/doors.cpp index 5a5249c5..553e459b 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1,1087 +1,1087 @@ -/*** -* -* 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 = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(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 if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(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 ) -{ - 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 != NULL && 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 ) ) +/*** +* +* 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(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 if (FStrEq(pkvd->szKeyName, "locked_sound")) + { + m_bLockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(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 ) +{ + 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 != NULL && 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 != NULL ) - { - 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 ) ) + 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 != NULL ) + { + 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; - } - } + 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( &CBaseDoor::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 EXPORT MomentaryMoveDone( 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[]; - - BYTE m_bMoveSnd; // sound a door makes while moving - BYTE m_bStopSnd; // sound a door makes when it stops -}; - -LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); - -TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, 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; - } - -// 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; - } -} - -void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atof(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 ( 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( &CBaseDoor::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 EXPORT MomentaryMoveDone( 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[]; + + BYTE m_bMoveSnd; // sound a door makes while moving + BYTE m_bStopSnd; // sound a door makes when it stops +}; + +LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); + +TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = +{ + DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), + DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, 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; + } + +// 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; + } +} + +void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) +{ + + if (FStrEq(pkvd->szKeyName, "movesnd")) + { + m_bMoveSnd = atof(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; - - if ( speed != 0 ) - { - // 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 - if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - - LinearMove( move, speed ); - SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); - } - -} - -void CMomentaryDoor::MomentaryMoveDone( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving)); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); + Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); + + Vector delta = move - pev->origin; + float speed = delta.Length() * 10; + + if ( speed != 0 ) + { + // 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 + if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) + EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + + LinearMove( move, speed ); + SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); + } + +} + +void CMomentaryDoor::MomentaryMoveDone( 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/dlls/doors.h b/dlls/doors.h index 55a853fc..80088615 100644 --- a/dlls/doors.h +++ b/dlls/doors.h @@ -1,33 +1,33 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/effects.cpp b/dlls/effects.cpp index 9868aeb9..62430bcf 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -1,2268 +1,2268 @@ -/*** -* -* 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 ? pev->speed : -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( &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( &CBaseEntity::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( 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( 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( &CBaseEntity::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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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::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( &CBaseEntity::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( 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(), BloodAmount() ); - else - UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), 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(), pev->renderamt, fadeFlags ); - } - } - else - { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), 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( &CBaseEntity::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( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time; +/*** +* +* 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 ? pev->speed : -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( &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( &CBaseEntity::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( 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( 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( &CBaseEntity::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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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::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( &CBaseEntity::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( 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(), BloodAmount() ); + else + UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), 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(), pev->renderamt, fadeFlags ); + } + } + else + { + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), 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( &CBaseEntity::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( &CBaseEntity::SUB_Remove ); + pev->nextthink = gpGlobals->time; } diff --git a/dlls/effects.h b/dlls/effects.h index c95ff1b1..3c72d06a 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -1,209 +1,209 @@ -/*** -* -* 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 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 pev->renderamt; } - inline int GetFrame( void ) { return pev->frame; } - inline int GetScrollRate( void ) { return 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( &CBaseEntity::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 +/*** +* +* 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 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 pev->renderamt; } + inline int GetFrame( void ) { return pev->frame; } + inline int GetScrollRate( void ) { return 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( &CBaseEntity::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/dlls/egon.cpp b/dlls/egon.cpp index 98d246a7..b5333cd7 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -1,568 +1,568 @@ -/*** -* -* 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; - - 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( 255 - (timeBlend*180) ); - m_pBeam->SetWidth( 40 - (timeBlend*20) ); - - if ( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - else - m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 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 > UTIL_WeaponTimeBase()) - 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 ); - +/*** +* +* 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; + + 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( 255 - (timeBlend*180) ); + m_pBeam->SetWidth( 40 - (timeBlend*20) ); + + if ( m_fireMode == FIRE_WIDE ) + m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + else + m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 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 > UTIL_WeaponTimeBase()) + 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 \ No newline at end of file diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index aad3724d..a8b21b27 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -1,158 +1,158 @@ -/*** -* -* 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 -#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 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 ) - +/*** +* +* 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 +#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 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 \ No newline at end of file diff --git a/dlls/explode.cpp b/dlls/explode.cpp index c884fa54..4e5f1c15 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -1,273 +1,273 @@ -/*** -* -* 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 ); -} +/*** +* +* 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/dlls/explode.h b/dlls/explode.h index 3d8c4107..3feb011c 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -1,32 +1,32 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/exportdef.h b/dlls/exportdef.h index 77a46734..90268c44 100644 --- a/dlls/exportdef.h +++ b/dlls/exportdef.h @@ -1,18 +1,18 @@ -#ifndef EXPORTDEF_H -#define EXPORTDEF_H -#if defined _WIN32 || defined __CYGWIN__ - #ifdef __GNUC__ - #define EXPORT __attribute__ ((dllexport)) - #else - #define EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. - #endif -#else - #if __GNUC__ >= 4 - #define EXPORT __attribute__ ((visibility ("default"))) - #else - #define EXPORT - #endif -#endif -#define DLLEXPORT EXPORT -#define _DLLEXPORT EXPORT -#endif // EXPORTDEF_H +#ifndef EXPORTDEF_H +#define EXPORTDEF_H +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define EXPORT __attribute__ ((dllexport)) + #else + #define EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. + #endif +#else + #if __GNUC__ >= 4 + #define EXPORT __attribute__ ((visibility ("default"))) + #else + #define EXPORT + #endif +#endif +#define DLLEXPORT EXPORT +#define _DLLEXPORT EXPORT +#endif // EXPORTDEF_H diff --git a/dlls/extdll.h b/dlls/extdll.h index 3ffd5833..a368a2ff 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -1,88 +1,88 @@ -/*** -* -* 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 -#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 - -// 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 -#define FALSE 0 -#define TRUE (!FALSE) -typedef unsigned long ULONG; -typedef unsigned char BYTE; -typedef int BOOL; -#define MAX_PATH PATH_MAX -#include -#include -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#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 +/*** +* +* 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 +#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 + +// 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 +#define FALSE 0 +#define TRUE (!FALSE) +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef int BOOL; +#define MAX_PATH PATH_MAX +#include +#include +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#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/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp index 9a0774f8..0b361ba6 100644 --- a/dlls/flyingmonster.cpp +++ b/dlls/flyingmonster.cpp @@ -1,281 +1,281 @@ -/*** -* -* 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. -* -****/ -#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; -} - +/*** +* +* 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. +* +****/ +#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/dlls/flyingmonster.h b/dlls/flyingmonster.h index 752f56ec..616194db 100644 --- a/dlls/flyingmonster.h +++ b/dlls/flyingmonster.h @@ -1,53 +1,53 @@ -/*** -* -* 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. -* -****/ -// 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 - +/*** +* +* 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. +* +****/ +// 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/dlls/func_break.cpp b/dlls/func_break.cpp index 5d682dcb..ff63ef56 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -1,1005 +1,1005 @@ -/*** -* -* 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 < 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; - - 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; - } - 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; - 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; - } - } - - 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 - CBaseEntity *pEntity = NULL; - 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) + (fabs(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; - } - - - 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( &CBaseEntity::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 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 ); - -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 = ( 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 = atof(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; - } - - // g-cont. fix pushable acceleration bug (reverted as it used in mods) - if ( pOther->IsPlayer() ) - { - // Don't push unless the player is pushing forward and NOT use (pull) - if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) - 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; -} - +/*** +* +* 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 < 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; + + 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; + } + 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; + 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; + } + } + + 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 + CBaseEntity *pEntity = NULL; + 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) + (fabs(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; + } + + + 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( &CBaseEntity::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 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 ); + +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 = ( 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 = atof(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; + } + + // g-cont. fix pushable acceleration bug (reverted as it used in mods) + if ( pOther->IsPlayer() ) + { + // Don't push unless the player is pushing forward and NOT use (pull) + if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) + 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/dlls/func_break.h b/dlls/func_break.h index 2441f756..9bb281d6 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -1,74 +1,74 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/func_tank.cpp b/dlls/func_tank.cpp index 459d21af..2997e943 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -1,1039 +1,1039 @@ -/*** -* -* 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 > 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; - - Vector offset = pevTest->origin - pev->origin; - - 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, lineOfSight; - Vector angles, direction, targetPosition, barrelEnd; - edict_t *pTarget; - - // 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 ); - - lineOfSight = FALSE; - // No line of sight, don't track - if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) - { - lineOfSight = TRUE; - - 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, pev->rendercolor.x, pev->rendercolor.y, 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 = (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 = (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 = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - CBaseEntity *pRocket = 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 = (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(); -} +/*** +* +* 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 > 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; + + Vector offset = pevTest->origin - pev->origin; + + 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, lineOfSight; + Vector angles, direction, targetPosition, barrelEnd; + edict_t *pTarget; + + // 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 ); + + lineOfSight = FALSE; + // No line of sight, don't track + if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) + { + lineOfSight = TRUE; + + 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, pev->rendercolor.x, pev->rendercolor.y, 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 = (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 = (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 = (gpGlobals->time - m_fireLast) * m_fireRate; + if ( bulletCount > 0 ) + { + for ( i = 0; i < bulletCount; i++ ) + { + CBaseEntity *pRocket = 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 = (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/dlls/game.cpp b/dlls/game.cpp index b4b6da75..1017da1b 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -1,887 +1,887 @@ -/*** -* -* 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 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 (&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" ); -} - +/*** +* +* 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 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 (&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/dlls/game.h b/dlls/game.h index 7bd9dce4..58e7e759 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -1,45 +1,45 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/gamerules.cpp b/dlls/gamerules.cpp index 34bb491c..829cae0f 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -1,347 +1,347 @@ -/*** -* -* 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; - } - } -} - - - +/*** +* +* 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/dlls/gamerules.h b/dlls/gamerules.h index 2e853045..76b35155 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -1,360 +1,360 @@ -/*** -* -* 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; +/*** +* +* 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/dlls/gargantua.cpp b/dlls/gargantua.cpp index 3dc763da..c54779c8 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -1,1368 +1,1368 @@ -/*** -* -* 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. -* -****/ -#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 -#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime - -// 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 * STOMP_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 + (STOMP_FRAMETIME) * pev->framerate; - pev->framerate = pev->framerate + (STOMP_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( &CBaseEntity::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; - static float offset[2] = { 60, -60 }; - 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() -{ - int 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( &CBaseEntity::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( &CBaseEntity::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; -} - - - +/*** +* +* 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. +* +****/ +#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 +#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime + +// 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 * STOMP_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 + (STOMP_FRAMETIME) * pev->framerate; + pev->framerate = pev->framerate + (STOMP_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( &CBaseEntity::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; + static float offset[2] = { 60, -60 }; + 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() +{ + int 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( &CBaseEntity::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( &CBaseEntity::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/dlls/gauss.cpp b/dlls/gauss.cpp index 45cdda8e..2830c9a9 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -1,621 +1,621 @@ -/*** -* -* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = ( 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; - - Vector vecSrc = vecOrigSrc; - Vector vecDest = vecSrc + vecDir * 8192; - edict_t *pentIgnore; - TraceResult tr, beam_tr; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - - pentIgnore = ENT( m_pPlayer->pev ); - -#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; - } - 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 +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = ( 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; + + Vector vecSrc = vecOrigSrc; + Vector vecDest = vecSrc + vecDir * 8192; + edict_t *pentIgnore; + TraceResult tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + + pentIgnore = ENT( m_pPlayer->pev ); + +#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; + } + 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/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 8f40be61..88bef689 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -1,140 +1,140 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 NULL; -} - -//========================================================= -// 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 -//========================================================= +/*** +* +* 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. +* +****/ +//========================================================= +// 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 NULL; +} + +//========================================================= +// 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/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 6cf34576..09c2f617 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -1,488 +1,488 @@ -/*** -* -* 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( (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( (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, 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, 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( &CBaseEntity::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 - +/*** +* +* 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( (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( (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, 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, 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( &CBaseEntity::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/dlls/globals.cpp b/dlls/globals.cpp index be31ef9f..ef657c2d 100644 --- a/dlls/globals.cpp +++ b/dlls/globals.cpp @@ -1,39 +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. -* -****/ -/* - -===== 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; +/*** +* +* 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/dlls/glock.cpp b/dlls/glock.cpp index 769ab4ac..ee3fa5da 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -1,274 +1,274 @@ -/*** -* -* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 ); - - - - - - - - - - - - - - - +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/gman.cpp b/dlls/gman.cpp index 77a1bd8a..be6e2745 100644 --- a/dlls/gman.cpp +++ b/dlls/gman.cpp @@ -1,237 +1,237 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 NULL; -} - -//========================================================= -// 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 == NULL) - { - 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 != NULL) - { - 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 != NULL && 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; -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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 NULL; +} + +//========================================================= +// 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 == NULL) + { + 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 != NULL) + { + 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 != NULL && 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/dlls/h_ai.cpp b/dlls/h_ai.cpp index f24a988e..73a5064a 100644 --- a/dlls/h_ai.cpp +++ b/dlls/h_ai.cpp @@ -1,199 +1,199 @@ -/*** -* -* 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; -} - - +/*** +* +* 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/dlls/h_battery.cpp b/dlls/h_battery.cpp index b8a3e7b0..11b8c064 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -1,200 +1,200 @@ -/*** -* -* 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 = 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 = gSkillData.suitchargerCapacity; - pev->frame = 0; - SetThink( &CBaseEntity::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 = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink( &CRecharge::Recharge); - } - else - SetThink( &CBaseEntity::SUB_DoNothing ); +/*** +* +* 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 = 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 = gSkillData.suitchargerCapacity; + pev->frame = 0; + SetThink( &CBaseEntity::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 = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink( &CRecharge::Recharge); + } + else + SetThink( &CBaseEntity::SUB_DoNothing ); } diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp index d25902a2..9bb7b2c2 100644 --- a/dlls/h_cine.cpp +++ b/dlls/h_cine.cpp @@ -1,241 +1,241 @@ -/*** -* -* 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. -* -****/ -/* - -===== 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( 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( 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( &CBaseEntity::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 -} - +/*** +* +* 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. +* +****/ +/* + +===== 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( 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( 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( &CBaseEntity::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/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index e7d5109b..df2e30b9 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -1,471 +1,471 @@ -/*** -* -* 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(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(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( &CBasePlayerItem::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 = 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(); -} +/*** +* +* 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(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(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( &CBasePlayerItem::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 = 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/dlls/h_export.cpp b/dlls/h_export.cpp index a2e533c5..cae7e59f 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -1,55 +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. -* -****/ -/* - -===== 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; -server_physics_api_t g_physfuncs; - -#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^M - -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -{ - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; -} +/*** +* +* 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; +server_physics_api_t g_physfuncs; + +#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/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 56ce9ee6..61285526 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -1,233 +1,233 @@ -/*** -* -* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 ); - } -} - - - - +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/hassassin.cpp b/dlls/hassassin.cpp index da8f677a..e5d84182 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -1,1015 +1,1015 @@ -/*** -* -* 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. -* -****/ -#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 == NULL) - { - 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 != NULL ) - { - 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 == NULL || 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; - } - - 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 ); -} - +/*** +* +* 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. +* +****/ +#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 == NULL) + { + 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 != NULL ) + { + 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 == NULL || 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; + } + + 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 \ No newline at end of file diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 8796769a..243faf8f 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -1,555 +1,555 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 != NULL) - { - 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 != NULL ) - return slHCRangeAttack1Fast; - break; - - case SCHED_RANGE_ATTACK1: - { - return slHCRangeAttack1Fast; - } - break; - } - - return CHeadCrab::GetScheduleOfType( Type ); -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL) + { + 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 != NULL ) + return slHCRangeAttack1Fast; + break; + + case SCHED_RANGE_ATTACK1: + { + return slHCRangeAttack1Fast; + } + break; + } + + return CHeadCrab::GetScheduleOfType( Type ); +} diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 87b9a221..bee988a0 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -1,264 +1,264 @@ -/*** -* -* 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 = 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 = gSkillData.healthchargerCapacity; - pev->frame = 0; - SetThink( &CBaseEntity::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 = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink( &CWallHealth::Recharge ); - } - else - SetThink( &CBaseEntity::SUB_DoNothing ); +/*** +* +* 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 = 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 = gSkillData.healthchargerCapacity; + pev->frame = 0; + SetThink( &CBaseEntity::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 = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) + { + pev->nextthink = pev->ltime + m_iReactivate; + SetThink( &CWallHealth::Recharge ); + } + else + SetThink( &CBaseEntity::SUB_DoNothing ); } diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 86544534..e0330696 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -1,2517 +1,2517 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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, -} HGRUNT_SENTENCE_TYPES; - -//========================================================= -// 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 != NULL ) - { - 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; - - if ( m_hEnemy != NULL ) - { - 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 == NULL) - { - 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 == NULL) - { - 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; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - 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 != NULL) && m_hEnemy->IsPlayer()) - // player - SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - else if ((m_hEnemy != NULL) && - (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 != NULL ) - { - // 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 ); - } - } - } - - // 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 != NULL ) - { - // 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( &CBaseEntity::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 char *m_szPoses[3]; -}; - -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(); -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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, +} HGRUNT_SENTENCE_TYPES; + +//========================================================= +// 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 != NULL ) + { + 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; + + if ( m_hEnemy != NULL ) + { + 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 == NULL) + { + 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 == NULL) + { + 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; + void *pmodel = GET_MODEL_PTR( ENT(pev) ); + + 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 != NULL) && m_hEnemy->IsPlayer()) + // player + SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + else if ((m_hEnemy != NULL) && + (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 != NULL ) + { + // 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 ); + } + } + } + + // 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 != NULL ) + { + // 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( &CBaseEntity::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 char *m_szPoses[3]; +}; + +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/dlls/hornet.cpp b/dlls/hornet.cpp index 5e64f4ef..b61fbd87 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -1,419 +1,419 @@ -/*** -* -* 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( &CBaseEntity::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( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - // UNDONE: The player pointer should come back after returning from another level - if ( m_hEnemy == NULL ) - {// enemy is dead. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if ( m_hEnemy != NULL && 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 != NULL && !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( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! -} - +/*** +* +* 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( &CBaseEntity::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( &CBaseEntity::SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + return; + } + + // UNDONE: The player pointer should come back after returning from another level + if ( m_hEnemy == NULL ) + {// enemy is dead. + Look( 512 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if ( m_hEnemy != NULL && 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 != NULL && !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( &CBaseEntity::SUB_Remove ); + pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! +} + diff --git a/dlls/hornet.h b/dlls/hornet.h index f069c3dd..98d1710f 100644 --- a/dlls/hornet.h +++ b/dlls/hornet.h @@ -1,58 +1,58 @@ -/*** -* -* 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; -}; - +/*** +* +* 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/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 8eb58431..f6cc2e44 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -1,305 +1,305 @@ -/*** -* -* 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 = m_flNextPrimaryAttack + 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 ); -} - +/*** +* +* 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 = m_flNextPrimaryAttack + 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 \ No newline at end of file diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index 5b9e0126..aa99cc68 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -1,1304 +1,1304 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 ) -{ - int 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; - } - - 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; - } - } - - return CSquadMonster :: GetSchedule(); -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ) +{ + int 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; + } + + 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; + } + } + + return CSquadMonster :: GetSchedule(); +} diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index f4cc3888..281dfd00 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -1,1108 +1,1108 @@ -/*** -* -* 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. -* -****/ -#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 != NULL && 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 ); - } - - 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 == NULL) - { - 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( ) -{ - int retValue = 0; - - 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 == NULL || 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); -} - +/*** +* +* 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. +* +****/ +#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 != NULL && 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 ); + } + + 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 == NULL) + { + 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( ) +{ + int retValue = 0; + + 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 == NULL || 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/dlls/islave.cpp b/dlls/islave.cpp index 037001c3..9c3964e3 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -1,866 +1,866 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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( 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( 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 != NULL ) - { - 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 != NULL) - { - 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 != NULL) - { - 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 ); - CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); - 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 != NULL) - 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() -{ - int 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; - } - 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 ) -{ - Vector vecDest; - float flDist = 1.0; - - 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" ); -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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( 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( 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 != NULL ) + { + 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 != NULL) + { + 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 != NULL) + { + 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 ); + CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); + 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 != NULL) + 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() +{ + int 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; + } + 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 ) +{ + Vector vecDest; + float flDist = 1.0; + + 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/dlls/items.cpp b/dlls/items.cpp index 930b187d..693d2022 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -1,342 +1,342 @@ -/*** -* -* 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\n", 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 ); +/*** +* +* 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\n", 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/dlls/items.h b/dlls/items.h index 04905fc4..e9852966 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -1,29 +1,29 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/leech.cpp b/dlls/leech.cpp index 390588db..3ced19ca 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -1,723 +1,723 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 ) -{ - int 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 ); -} - - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ) +{ + int 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/dlls/lights.cpp b/dlls/lights.cpp index 147dfdf1..312aa30a 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -1,199 +1,199 @@ -/*** -* -* 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, (char *)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, (char *)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.0); - g = g * (v / 255.0); - b = b * (v / 255.0); - } - - // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling - r = pow( r / 114.0, 0.6 ) * 264; - g = pow( g / 114.0, 0.6 ) * 264; - b = pow( b / 114.0, 0.6 ) * 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( ); -} +/*** +* +* 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, (char *)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, (char *)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.0); + g = g * (v / 255.0); + b = b * (v / 255.0); + } + + // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling + r = pow( r / 114.0, 0.6 ) * 264; + g = pow( g / 114.0, 0.6 ) * 264; + b = pow( b / 114.0, 0.6 ) * 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/dlls/maprules.cpp b/dlls/maprules.cpp index 9402f319..f6d13343 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -1,918 +1,918 @@ -/*** -* -* 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 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 pev->frags; } - inline int LimitValue( void ) { return 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 ); - } -} - - +/*** +* +* 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 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 pev->frags; } + inline int LimitValue( void ) { return 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/dlls/maprules.h b/dlls/maprules.h index 975dafa1..57f9939b 100644 --- a/dlls/maprules.h +++ b/dlls/maprules.h @@ -1,22 +1,22 @@ -/*** -* -* 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 - +/*** +* +* 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/dlls/monsterevent.h b/dlls/monsterevent.h index 58357e18..46c5624a 100644 --- a/dlls/monsterevent.h +++ b/dlls/monsterevent.h @@ -1,34 +1,34 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index 72e44575..dcfe42db 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -1,292 +1,292 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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( &CBaseEntity::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; - } -} - - +/*** +* +* 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. +* +****/ +//========================================================= +// 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( &CBaseEntity::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/dlls/monsters.cpp b/dlls/monsters.cpp index 1e6191d1..21901b0c 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -1,3448 +1,3448 @@ -/*** -* -* 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. -* -****/ -/* - -===== 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 == NULL ) - 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 != NULL) - { - 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 != NULL && 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] == NULL) // 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] != NULL) - { - 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 ( 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\n", 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 != NULL ) - 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 != NULL && 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 == NULL && PopEnemy( )) - { - if ( m_pSchedule ) - { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) - { - SetConditions(bits_COND_NEW_ENEMY); - } - } - } - - if ( m_hEnemy != NULL ) - { - // monster has an enemy. - return TRUE; - } - - return FALSE;// monster has no enemy -} - - -//========================================================= -// DropItem - dead monster drops named item -//========================================================= -CBaseEntity* CBaseMonster :: DropItem ( 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; -} +/*** +* +* 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. +* +****/ +/* + +===== 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 == NULL ) + 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 != NULL) + { + 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 != NULL && 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] == NULL) // 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] != NULL) + { + 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 ( 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\n", 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 != NULL ) + 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 != NULL && 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 == NULL && PopEnemy( )) + { + if ( m_pSchedule ) + { + if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + { + SetConditions(bits_COND_NEW_ENEMY); + } + } + } + + if ( m_hEnemy != NULL ) + { + // monster has an enemy. + return TRUE; + } + + return FALSE;// monster has no enemy +} + + +//========================================================= +// DropItem - dead monster drops named item +//========================================================= +CBaseEntity* CBaseMonster :: DropItem ( 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/dlls/monsters.h b/dlls/monsters.h index 75c945fd..f7f1a03f 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -1,183 +1,183 @@ -/*** -* -* 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. -* -****/ -#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 +/*** +* +* 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. +* +****/ +#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/dlls/monsterstate.cpp b/dlls/monsterstate.cpp index aca95b35..14518e1c 100644 --- a/dlls/monsterstate.cpp +++ b/dlls/monsterstate.cpp @@ -1,234 +1,234 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 != NULL ) - { - m_hEnemy = NULL;// not allowed to have an enemy anymore. - ALERT ( at_aiconsole, "Stripped\n" ); - } - 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 != NULL ) - { - 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 == NULL ) - { - 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; - } - - return m_IdealMonsterState; -} - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL ) + { + m_hEnemy = NULL;// not allowed to have an enemy anymore. + ALERT ( at_aiconsole, "Stripped\n" ); + } + 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 != NULL ) + { + 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 == NULL ) + { + 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; + } + + return m_IdealMonsterState; +} + diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index e9e47630..43d68d42 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -1,323 +1,323 @@ -/*** -* -* 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( &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 ); -} +/*** +* +* 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( &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/dlls/mp5.cpp b/dlls/mp5.cpp index 8ee2ce89..789c264e 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -1,385 +1,385 @@ -/*** -* -* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 ); - - - - - - - - - - - - - - - - - - +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index bd5ee369..29d2ef30 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -1,264 +1,264 @@ -/*** -* -* 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( &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 = ( 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; -} +/*** +* +* 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( &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 = ( 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; +} diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index fb3d3e18..d79a4128 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1,1698 +1,1698 @@ -/*** -* -* 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" - -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() ) - { - // dedicated server - char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); - - if ( servercfgfile && servercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing dedicated server config file\n" ); - sprintf( szCommand, "exec %s\n", servercfgfile ); - SERVER_COMMAND( szCommand ); - } - } - 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 = 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 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( 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( 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( 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 *Killer = 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 - char *tau = "tau_cannon"; - 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 ); -} - - +/*** +* +* 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" + +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() ) + { + // dedicated server + char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + + if ( servercfgfile && servercfgfile[0] ) + { + char szCommand[256]; + + ALERT( at_console, "Executing dedicated server config file\n" ); + sprintf( szCommand, "exec %s\n", servercfgfile ); + SERVER_COMMAND( szCommand ); + } + } + 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 = 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 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( 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( 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( 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 *Killer = 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 + char *tau = "tau_cannon"; + 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/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 9456fad7..cacb61a2 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -1,1837 +1,1837 @@ -/*** -* -* 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. -* -****/ -#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 != NULL) - { - 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] != NULL && !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] == NULL) - { - 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] != NULL) - { - 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 == NULL && 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 != NULL) - { - // 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 != NULL && !m_hEnemy->IsAlive()) - { - m_hEnemy = NULL; - } - - if (m_flLastSeen + 15 < gpGlobals->time) - { - m_hEnemy = NULL; - } - - if (m_hEnemy == NULL) - { - Look( 4096 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if (m_hEnemy != NULL && 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 != NULL && m_hRecharger == NULL) - { - 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; - - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // 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] != NULL) - { - 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] != NULL) - { - 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 ) -{ +/*** +* +* 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. +* +****/ +#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 != NULL) + { + 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; - CBaseMonster *pSphere; - for (i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != NULL) - { - pSphere = m_hSphere[i]->MyMonsterPointer(); - if (pSphere->m_hEnemy == NULL) - 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 != NULL) - { - 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 != NULL) - { - 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 != NULL) - { - if (!EmitSphere( )) - { - m_hRecharger = NULL; - } - } - } - 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 != NULL) - { - 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 && m_hEnemy != NULL ) - pTouch->Touch( m_hEnemy ); - } - 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 != NULL) - { - 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 == NULL || 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 == NULL || !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 != NULL) - m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - - if ( m_hTouch != NULL && m_hEnemy != NULL ) - 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 != NULL) - m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - - if (m_hTouch != NULL && 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 != NULL) - { - 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(); -} - - - + + for (i = 0; i < 3; i++) + { + if (m_hFriend[i] != NULL && !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] == NULL) + { + 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] != NULL) + { + 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 == NULL && 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 != NULL) + { + // 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 != NULL && !m_hEnemy->IsAlive()) + { + m_hEnemy = NULL; + } + + if (m_flLastSeen + 15 < gpGlobals->time) + { + m_hEnemy = NULL; + } + + if (m_hEnemy == NULL) + { + Look( 4096 ); + m_hEnemy = BestVisibleEnemy( ); + } + + if (m_hEnemy != NULL && 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 != NULL && m_hRecharger == NULL) + { + 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; + + float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); + + // 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] != NULL) + { + 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] != NULL) + { + 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 ) +{ + int i; + CBaseMonster *pSphere; + for (i = 0; i < N_SPHERES; i++) + { + if (m_hSphere[i] != NULL) + { + pSphere = m_hSphere[i]->MyMonsterPointer(); + if (pSphere->m_hEnemy == NULL) + 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 != NULL) + { + 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 != NULL) + { + 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 != NULL) + { + if (!EmitSphere( )) + { + m_hRecharger = NULL; + } + } + } + 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 != NULL) + { + 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 && m_hEnemy != NULL ) + pTouch->Touch( m_hEnemy ); + } + 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 != NULL) + { + 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 == NULL || 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 == NULL || !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 != NULL) + m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); + + if ( m_hTouch != NULL && m_hEnemy != NULL ) + 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 != NULL) + m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); + + if (m_hTouch != NULL && 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 != NULL) + { + 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/dlls/nodes.cpp b/dlls/nodes.cpp index 0debc5c0..18c145dd 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -1,3649 +1,3649 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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" - -#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 -#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 ) -{ - edict_t *pentWorld; - 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; - } - pentWorld = NULL; - -// 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; - signed char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; - - // Until we decode the next best node - // - while (nCount > 0) - { - signed 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; - - 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 - { - int i; - 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. - // - 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 ( 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", j ); - 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( &CBaseEntity::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 cMaxInitialLinks = 0; - int cMaxValidLinks = 0; - - int iPoolIndex = 0; - 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( &CBaseEntity::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"); - } - - 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: %d 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 = (signed char *)calloc( sizeof(signed 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( signed 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 iPrime, iZone; - 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. - // - 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 i, iNodeCnt = 0; - 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) -{ - int i; - 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; - } - 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) -{ - int i, j; - 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. - // - // - 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++) - { - 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 iFrom; - 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]; - signed char *pRoute = new signed 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. - // - 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; - signed 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 - { - signed char *Tmp = (signed char *)calloc(sizeof(signed 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 = (signed char *)calloc(sizeof(signed 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 i; - 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; - 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 ( 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 (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++; - } -} - - +/*** +* +* 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. +* +****/ +//========================================================= +// 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" + +#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 +#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 ) +{ + edict_t *pentWorld; + 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; + } + pentWorld = NULL; + +// 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; + signed char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; + + // Until we decode the next best node + // + while (nCount > 0) + { + signed 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; + + 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 + { + int i; + 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. + // + 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 ( 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", j ); + 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( &CBaseEntity::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 cMaxInitialLinks = 0; + int cMaxValidLinks = 0; + + int iPoolIndex = 0; + 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( &CBaseEntity::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"); + } + + 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: %d 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 = (signed char *)calloc( sizeof(signed 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( signed 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 iPrime, iZone; + 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. + // + 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 i, iNodeCnt = 0; + 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) +{ + int i; + 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; + } + 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) +{ + int i, j; + 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. + // + // + 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++) + { + 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 iFrom; + 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]; + signed char *pRoute = new signed 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. + // + 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; + signed 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 + { + signed char *Tmp = (signed char *)calloc(sizeof(signed 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 = (signed char *)calloc(sizeof(signed 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 i; + 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; + 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 ( 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 (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/dlls/nodes.h b/dlls/nodes.h index cc1b6e20..67ac2139 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -1,374 +1,374 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 - signed 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; +/*** +* +* 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. +* +****/ +//========================================================= +// 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 + signed 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; diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index 309d4354..97c3513f 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -1,805 +1,805 @@ -/*** -* -* 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. -* -****/ -#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] == NULL || !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] == NULL || !m_hGrunt[i]->IsAlive()) - { - if (m_hGrunt[i] != NULL && 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( &CBaseEntity::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] != NULL && 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 ); - } -} - - - - - +/*** +* +* 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. +* +****/ +#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] == NULL || !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] == NULL || !m_hGrunt[i]->IsAlive()) + { + if (m_hGrunt[i] != NULL && 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( &CBaseEntity::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] != NULL && 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/dlls/pathcorner.cpp b/dlls/pathcorner.cpp index 498550de..3516ec08 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -1,428 +1,428 @@ -/*** -* -* 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 - +/*** +* +* 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/dlls/physcallback.h b/dlls/physcallback.h index 21296c63..4471e05c 100644 --- a/dlls/physcallback.h +++ b/dlls/physcallback.h @@ -1,33 +1,33 @@ -/*** -* -* 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 PHYSCALLBACK_H -#define PHYSCALLBACK_H -#pragma once - -#include "physint.h" - -// Must be provided by user of this code -extern server_physics_api_t g_physfuncs; - -// The actual physic callbacks -#define LINK_ENTITY (*g_physfuncs.pfnLinkEdict) -#define PHYSICS_TIME (*g_physfuncs.pfnGetServerTime) -#define HOST_FRAMETIME (*g_physfuncs.pfnGetFrameTime) -#define MODEL_HANDLE (*g_physfuncs.pfnGetModel) -#define GET_AREANODE (*g_physfuncs.pfnGetHeadnode) -#define GET_SERVER_STATE (*g_physfuncs.pfnServerState) -#define HOST_ERROR (*g_physfuncs.pfnHost_Error) - +/*** +* +* 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 PHYSCALLBACK_H +#define PHYSCALLBACK_H +#pragma once + +#include "physint.h" + +// Must be provided by user of this code +extern server_physics_api_t g_physfuncs; + +// The actual physic callbacks +#define LINK_ENTITY (*g_physfuncs.pfnLinkEdict) +#define PHYSICS_TIME (*g_physfuncs.pfnGetServerTime) +#define HOST_FRAMETIME (*g_physfuncs.pfnGetFrameTime) +#define MODEL_HANDLE (*g_physfuncs.pfnGetModel) +#define GET_AREANODE (*g_physfuncs.pfnGetHeadnode) +#define GET_SERVER_STATE (*g_physfuncs.pfnServerState) +#define HOST_ERROR (*g_physfuncs.pfnHost_Error) + #endif //PHYSCALLBACK_H \ No newline at end of file diff --git a/dlls/plane.cpp b/dlls/plane.cpp index ff5518c7..39a91c32 100644 --- a/dlls/plane.cpp +++ b/dlls/plane.cpp @@ -1,60 +1,60 @@ -/*** -* -* 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; -} - +/*** +* +* 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/dlls/plane.h b/dlls/plane.h index a54f2457..af70f1cc 100644 --- a/dlls/plane.h +++ b/dlls/plane.h @@ -1,43 +1,43 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/plats.cpp b/dlls/plats.cpp index 64151f47..d2ca1aa0 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1,2285 +1,2285 @@ -/*** -* -* 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 = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atof(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()) - 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 + (fabs(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 = 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( &CFuncPlat::CallHitBottom ); - m_toggle_state = TS_GOING_DOWN; - AngularMove( m_start, pev->speed ); - } - else - { - CFuncPlat :: GoDown(); - SetMoveDone( &CFuncPlat::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( &CFuncPlat::CallHitTop ); - AngularMove( m_end, pev->speed ); - } - else - { - // If ROTMOVE, move & rotate - CFuncPlat :: GoUp(); - SetMoveDone( &CFuncPlat::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 == NULL ) - return; - pev->health = pev->max_health; - Next(); - } -} - - - +/*** +* +* 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 = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "stopsnd")) + { + m_bStopSnd = atof(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()) + 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 + (fabs(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 = 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( &CFuncPlat::CallHitBottom ); + m_toggle_state = TS_GOING_DOWN; + AngularMove( m_start, pev->speed ); + } + else + { + CFuncPlat :: GoDown(); + SetMoveDone( &CFuncPlat::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( &CFuncPlat::CallHitTop ); + AngularMove( m_end, pev->speed ); + } + else + { + // If ROTMOVE, move & rotate + CFuncPlat :: GoUp(); + SetMoveDone( &CFuncPlat::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 == NULL ) + return; + pev->health = pev->max_health; + Next(); + } +} + + + diff --git a/dlls/player.cpp b/dlls/player.cpp index 7dee887d..54d4e8c5 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1,4791 +1,4791 @@ - /*** -* -* 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 "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( "HudText", -1 ); - 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 = 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, NULL, 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; - - 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 != NULL ) - { - 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 += 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(); - } - -// 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 ); - StartObserver( pSpot->v.origin, 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 ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; - } -} - -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) -{ - m_afPhysicsFlags |= PFLAG_OBSERVER; - - 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; - pev->modelindex = 0; - UTIL_SetOrigin( pev, vecPosition ); -} - -// -// PlayerUse - handles USE keypress -// -#define PLAYER_SEARCH_RADIUS (float)64 - -void CBasePlayer::PlayerUse ( void ) -{ - // 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 != NULL ) - { - // 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(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 = -pev->frags; // Sum will be 0 - } - } - } - - pev->frags += score; - - MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(edict()) ); - WRITE_SHORT( 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 ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); - newSBarState[ SBAR_ID_TARGETARMOR ] = 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(); - - 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(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; - - static float gtbdPrev = 0.0; - - if (!(m_bitsDamageType & DMG_TIMEBASED)) - return; - - // only check for time based damage approx. every 2 seconds - if ( fabs( 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(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 = 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 -= 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 -= 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 -= 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 != NULL ) - { // 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, 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(); - - // Track button info so we can detect 'pressed' and 'released' buttons next frame - m_afButtonLast = pev->button; - -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; - } - - -#else - return; -#endif -} - - -// 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_flFlashLightTime = 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, 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( &CBaseEntity::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, 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() -{ - static int fInSelect = FALSE; - - // check if the player is using a tank - if ( m_pTank != NULL ) - 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; - 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) - { - int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent - - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); - WRITE_BYTE( iHealth ); - MESSAGE_END(); - - m_iClientHealth = pev->health; - } - - - if (pev->armorvalue != m_iClientBattery) - { - m_iClientBattery = 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( pev->dmg_save ); - WRITE_BYTE( 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 = m_vecAutoAim.x; - m_lasty = 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 ) - { - g_pGameRules->GetNextBestWeapon( this, pWeapon ); - - 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 char *m_szPoses[4]; -}; - -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(), 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 ); - + /*** +* +* 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 "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( "HudText", -1 ); + 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 = 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, NULL, 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; + + 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 != NULL ) + { + 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 += 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(); + } + +// 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 ); + StartObserver( pSpot->v.origin, 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 ); + StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); + return; + } +} + +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) +{ + m_afPhysicsFlags |= PFLAG_OBSERVER; + + 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; + pev->modelindex = 0; + UTIL_SetOrigin( pev, vecPosition ); +} + +// +// PlayerUse - handles USE keypress +// +#define PLAYER_SEARCH_RADIUS (float)64 + +void CBasePlayer::PlayerUse ( void ) +{ + // 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 != NULL ) + { + // 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(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 = -pev->frags; // Sum will be 0 + } + } + } + + pev->frags += score; + + MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX(edict()) ); + WRITE_SHORT( 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 ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); + newSBarState[ SBAR_ID_TARGETARMOR ] = 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(); + + 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(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; + + static float gtbdPrev = 0.0; + + if (!(m_bitsDamageType & DMG_TIMEBASED)) + return; + + // only check for time based damage approx. every 2 seconds + if ( fabs( 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(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 = 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 -= 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 -= 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 -= 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 != NULL ) + { // 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, 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(); + + // Track button info so we can detect 'pressed' and 'released' buttons next frame + m_afButtonLast = pev->button; + +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; + } + + +#else + return; +#endif +} + + +// 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_flFlashLightTime = 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, 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( &CBaseEntity::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, 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() +{ + static int fInSelect = FALSE; + + // check if the player is using a tank + if ( m_pTank != NULL ) + 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; + 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) + { + int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent + + // send "health" update message + MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); + WRITE_BYTE( iHealth ); + MESSAGE_END(); + + m_iClientHealth = pev->health; + } + + + if (pev->armorvalue != m_iClientBattery) + { + m_iClientBattery = 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( pev->dmg_save ); + WRITE_BYTE( 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 = m_vecAutoAim.x; + m_lasty = 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 ) + { + g_pGameRules->GetNextBestWeapon( this, pWeapon ); + + 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 char *m_szPoses[4]; +}; + +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(), 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/dlls/player.h b/dlls/player.h index 56e535fb..a11d0754 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -1,324 +1,324 @@ -/*** -* -* 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: - 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, char *szName, int iMax ); - void SendAmmoUpdate(void); - - void WaterMove( void ); - void EXPORT PlayerDeathThink( void ); - void PlayerUse( void ); - - void CheckSuitUpdate(); - void SetSuitUpdate(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 +/*** +* +* 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: + 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, char *szName, int iMax ); + void SendAmmoUpdate(void); + + void WaterMove( void ); + void EXPORT PlayerDeathThink( void ); + void PlayerUse( void ); + + void CheckSuitUpdate(); + void SetSuitUpdate(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/dlls/playermonster.cpp b/dlls/playermonster.cpp index bb0a86ac..6497ea6e 100644 --- a/dlls/playermonster.cpp +++ b/dlls/playermonster.cpp @@ -1,122 +1,122 @@ -//========= Copyright © 1996-2002, 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 -//========================================================= +//========= Copyright © 1996-2002, 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/dlls/python.cpp b/dlls/python.cpp index 37574488..0e2a4c06 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -1,320 +1,320 @@ -/*** -* -* 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_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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_WeaponTimeBase() + 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 - - if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) - { - m_flSoundDelay = 1.5; - } -} - - -void CPython::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); - m_flSoundDelay = 0; - } - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0f, 1.0f ); - if (flRand <= 0.5) - { - iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (70.0/30.0); - } - else if (flRand <= 0.7) - { - iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/30.0); - } - else if (flRand <= 0.9) - { - iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (88.0/30.0); - } - else - { - iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (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 ); - - +/*** +* +* 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_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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_WeaponTimeBase() + 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 + + if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) + { + m_flSoundDelay = 1.5; + } +} + + +void CPython::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); + if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) + { + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); + m_flSoundDelay = 0; + } + + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0f, 1.0f ); + if (flRand <= 0.5) + { + iAnim = PYTHON_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (70.0/30.0); + } + else if (flRand <= 0.7) + { + iAnim = PYTHON_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/30.0); + } + else if (flRand <= 0.9) + { + iAnim = PYTHON_IDLE3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (88.0/30.0); + } + else + { + iAnim = PYTHON_FIDGET; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (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 \ No newline at end of file diff --git a/dlls/rat.cpp b/dlls/rat.cpp index 0d4c8fb6..88b1ad2d 100644 --- a/dlls/rat.cpp +++ b/dlls/rat.cpp @@ -1,98 +1,98 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 -//========================================================= +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/roach.cpp b/dlls/roach.cpp index 32ec66ae..c92a5dfe 100644 --- a/dlls/roach.cpp +++ b/dlls/roach.cpp @@ -1,460 +1,460 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) - { - 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 -//========================================================= - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) + { + 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/dlls/rpg.cpp b/dlls/rpg.cpp index b435b5cb..a6773dcf 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -1,618 +1,618 @@ -/*** -* -* 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( &CGrenade::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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 1.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - else - { - PlayEmptySound( ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; - } - 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 ); - +/*** +* +* 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( &CGrenade::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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; + } + else + { + PlayEmptySound( ); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; + } + 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/dlls/satchel.cpp b/dlls/satchel.cpp index 9eeb1abb..ee74a3df 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -1,494 +1,494 @@ -/*** -* -* 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( &CGrenade::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 ) -{ - entvars_t *pevOther = pOther->pev; - - // 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 = UTIL_WeaponTimeBase() + 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] ) - { - Vector vecSrc = m_pPlayer->pev->origin; - - Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; - -#ifndef CLIENT_DLL - 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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" ); - } -} - +/*** +* +* 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( &CGrenade::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 ) +{ + entvars_t *pevOther = pOther->pev; + + // 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 = UTIL_WeaponTimeBase() + 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] ) + { + Vector vecSrc = m_pPlayer->pev->origin; + + Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; + +#ifndef CLIENT_DLL + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/saverestore.h b/dlls/saverestore.h index c774b62d..8623601f 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -1,169 +1,169 @@ -/*** -* -* 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 ); - ~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 ); -}; - - -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, const int *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; -}; - -extern CGlobalState gGlobalState; - -#endif //SAVERESTORE_H +/*** +* +* 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 ); + ~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 ); +}; + + +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, const int *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; +}; + +extern CGlobalState gGlobalState; + +#endif //SAVERESTORE_H diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index f1eb367d..468bb358 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -1,1514 +1,1514 @@ -/*** -* -* 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 ]; -} +/*** +* +* 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/dlls/schedule.h b/dlls/schedule.h index f73e8953..82cbdeb7 100644 --- a/dlls/schedule.h +++ b/dlls/schedule.h @@ -1,290 +1,290 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 +/*** +* +* 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. +* +****/ +//========================================================= +// 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/dlls/scientist.cpp b/dlls/scientist.cpp index f7e991ad..b021b1d7 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -1,1428 +1,1428 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 != NULL ) - 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 == NULL ) - { - 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; - } - - 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( &CTalkMonster::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; - } - - 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 = NULL; - return m_IdealMonsterState; - } - // Follow if only scared a little - if ( m_hTargetEnt != NULL ) - { - 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; - } - - return CTalkMonster::GetIdealState(); -} - - -BOOL CScientist::CanHeal( void ) -{ - if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (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 char *m_szPoses[7]; -}; -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; -} +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL ) + 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 == NULL ) + { + 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; + } + + 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( &CTalkMonster::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; + } + + 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 = NULL; + return m_IdealMonsterState; + } + // Follow if only scared a little + if ( m_hTargetEnt != NULL ) + { + 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; + } + + return CTalkMonster::GetIdealState(); +} + + +BOOL CScientist::CanHeal( void ) +{ + if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (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 char *m_szPoses[7]; +}; +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/dlls/scripted.cpp b/dlls/scripted.cpp index fbe56fd9..d68c967f 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -1,1260 +1,1260 @@ -/*** -* -* 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. -* -****/ -/* - - -===== 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( &CBaseEntity::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( &CBaseEntity::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 == NULL || !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 NULL; - } - - 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( &CBaseEntity::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; -} - - +/*** +* +* 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. +* +****/ +/* + + +===== 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( &CBaseEntity::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( &CBaseEntity::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 == NULL || !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 NULL; + } + + 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( &CBaseEntity::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/dlls/scripted.h b/dlls/scripted.h index 67a2eb13..dee12d72 100644 --- a/dlls/scripted.h +++ b/dlls/scripted.h @@ -1,107 +1,107 @@ -/*** -* -* 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. -* -****/ -#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 +/*** +* +* 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. +* +****/ +#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/dlls/scriptevent.h b/dlls/scriptevent.h index 9a02bd64..42377cf0 100644 --- a/dlls/scriptevent.h +++ b/dlls/scriptevent.h @@ -1,29 +1,29 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/shotgun.cpp b/dlls/shotgun.cpp index dfa084b8..f0575482 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -1,401 +1,401 @@ -/*** -* -* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 ); - - +/*** +* +* 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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 = UTIL_WeaponTimeBase() + 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/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index b71b96a1..398b8cc7 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -1,328 +1,328 @@ -/*** -* -* 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; -} +/*** +* +* 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/dlls/skill.cpp b/dlls/skill.cpp index 7c0b8529..d82a607b 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -1,47 +1,47 @@ -/*** -* -* 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( char *pName ) -{ - int iCount; - float flValue; - char szBuffer[ 64 ]; - - iCount = 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; -} - +/*** +* +* 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( char *pName ) +{ + int iCount; + float flValue; + char szBuffer[ 64 ]; + + iCount = 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/dlls/skill.h b/dlls/skill.h index 44340711..5ec320c2 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -1,147 +1,147 @@ -/*** -* -* 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( char *pName ); - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SKILL_EASY 1 -#define SKILL_MEDIUM 2 -#define SKILL_HARD 3 +/*** +* +* 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( char *pName ); + +extern DLL_GLOBAL int g_iSkillLevel; + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 diff --git a/dlls/sound.cpp b/dlls/sound.cpp index f61086a5..6c5bfc90 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1,1978 +1,1978 @@ -/*** -* -* 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" - - -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( &CBaseEntity::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 = 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 = 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) - 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 = 0; - - 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]; - 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 ) -{ - char* szSoundFile = (char*) 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( &CBaseEntity::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 ) -{ - char* szSoundFile; - 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 ); +/*** +* +* 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" + + +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( &CBaseEntity::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 = 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 = 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) + 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 = 0; + + 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]; + 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 ) +{ + char* szSoundFile = (char*) 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( &CBaseEntity::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 ) +{ + char* szSoundFile; + 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/dlls/soundent.cpp b/dlls/soundent.cpp index c3d169f1..c567d7a5 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -1,379 +1,379 @@ -/*** -* -* 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; - 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; +/*** +* +* 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; + 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/dlls/soundent.h b/dlls/soundent.h index 2393cb40..150daac7 100644 --- a/dlls/soundent.h +++ b/dlls/soundent.h @@ -1,95 +1,95 @@ -/*** -* -* 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 ]; -}; +/*** +* +* 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/dlls/spectator.cpp b/dlls/spectator.cpp index 9d6bef9d..5f91731e 100644 --- a/dlls/spectator.cpp +++ b/dlls/spectator.cpp @@ -1,149 +1,149 @@ -/*** -* -* 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; -} +/*** +* +* 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/dlls/spectator.h b/dlls/spectator.h index f832621a..d459a384 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -1,27 +1,27 @@ -/*** -* -* 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); +/*** +* +* 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); }; \ No newline at end of file diff --git a/dlls/squad.h b/dlls/squad.h index 5f9f2499..9acfccb2 100644 --- a/dlls/squad.h +++ b/dlls/squad.h @@ -1,20 +1,20 @@ -//========= Copyright © 1996-2002, 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 ) +//========= Copyright © 1996-2002, 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 ) \ No newline at end of file diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp index d0a65ba1..993e877c 100644 --- a/dlls/squadmonster.cpp +++ b/dlls/squadmonster.cpp @@ -1,623 +1,623 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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] == NULL) - { - 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 != NULL) - { - // 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 != NULL ) - { - 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 ) -{ - 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: - case MONSTERSTATE_ALERT: - if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) - { - SquadMakeEnemy ( m_hEnemy ); - } - 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 != NULL && 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 ); - } -} - +/*** +* +* 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. +* +****/ +//========================================================= +// 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] == NULL) + { + 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 != NULL) + { + // 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 != NULL ) + { + 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 ) +{ + 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: + case MONSTERSTATE_ALERT: + if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) + { + SquadMakeEnemy ( m_hEnemy ); + } + 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 != NULL && 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/dlls/squadmonster.h b/dlls/squadmonster.h index f5297876..3c18b937 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -1,120 +1,120 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 != NULL; } - 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 ); -}; - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 != NULL; } + 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/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 5dd718a4..fa6c94b2 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -1,601 +1,601 @@ -/*** -* -* 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 != NULL) - { - 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( &CBaseEntity::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 != NULL) - 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 != NULL) - 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; - - CBaseEntity *pOther = NULL; - Vector vecDir; - TraceResult tr; - - Vector vecFlat = pev->velocity; - vecFlat.z = 0; - vecFlat = vecFlat.Normalize( ); - - UTIL_MakeVectors( pev->angles ); - - if (m_hEnemy == NULL || !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 != NULL) - { - 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 != NULL) - 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 = UTIL_WeaponTimeBase() + 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 ); -} - +/*** +* +* 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 != NULL) + { + 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( &CBaseEntity::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 != NULL) + 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 != NULL) + 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; + + CBaseEntity *pOther = NULL; + Vector vecDir; + TraceResult tr; + + Vector vecFlat = pev->velocity; + vecFlat.z = 0; + vecFlat = vecFlat.Normalize( ); + + UTIL_MakeVectors( pev->angles ); + + if (m_hEnemy == NULL || !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 != NULL) + { + 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 != NULL) + 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 = UTIL_WeaponTimeBase() + 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/dlls/stats.cpp b/dlls/stats.cpp index 3323c1ca..2f50395c 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -1,156 +1,156 @@ -//========= Copyright © 1996-2002, 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 -} - +//========= Copyright © 1996-2002, 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/dlls/subs.cpp b/dlls/subs.cpp index 3de64d9a..d3560bd5 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -1,559 +1,559 @@ -/*** -* -* 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 ) -{ - 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; - } - - +/*** +* +* 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 ) +{ + 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/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index ee0b0407..a6b88a57 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -1,1472 +1,1472 @@ -/*** -* -* 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. -* -****/ -#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 -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 != NULL) - { - 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 != NULL) - { - // 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 != NULL) - { - // 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 != NULL) - { - 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; - 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 == NULL || !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; - 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 ) -{ - int pitch = GetVoicePitch(); - - // 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 != NULL && 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 - int pitch; - 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); - - } - - pitch = GetVoicePitch(); - - // 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 ); - 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 = NULL; - if ( clearSchedule ) - ClearSchedule(); - if ( m_hEnemy != NULL ) - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } -} - - -void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) -{ - if ( m_pCine ) - m_pCine->CancelScript(); - - if ( m_hEnemy != NULL ) - 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 ); -} - +/*** +* +* 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. +* +****/ +#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 +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 != NULL) + { + 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 != NULL) + { + // 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 != NULL) + { + // 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 != NULL) + { + 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; + 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 == NULL || !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; + 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 ) +{ + int pitch = GetVoicePitch(); + + // 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 != NULL && 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 + int pitch; + 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); + + } + + pitch = GetVoicePitch(); + + // 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 ); + 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 = NULL; + if ( clearSchedule ) + ClearSchedule(); + if ( m_hEnemy != NULL ) + m_IdealMonsterState = MONSTERSTATE_COMBAT; + } +} + + +void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) +{ + if ( m_pCine ) + m_pCine->CancelScript(); + + if ( m_hEnemy != NULL ) + 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/dlls/talkmonster.h b/dlls/talkmonster.h index d59c55f4..00f2bbaa 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -1,183 +1,183 @@ -/*** -* -* 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. -* -****/ -#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 != NULL && 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 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 +/*** +* +* 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. +* +****/ +#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 != NULL && 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 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/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index db99778f..9bc7830e 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -1,630 +1,630 @@ -/*** -* -* 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 = 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; - - int slot = atoi( CMD_ARGV(1) ); - - // 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 ); - int clientIndex = pPlayer->entindex(); - 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( 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] += 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(); - } - } - } - } -} +/*** +* +* 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 = 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; + + int slot = atoi( CMD_ARGV(1) ); + + // 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 ); + int clientIndex = pPlayer->entindex(); + 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( 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] += 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/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index c7c351e6..5d4246bd 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -1,57 +1,57 @@ -/*** -* -* 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]; -}; +/*** +* +* 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/dlls/tempmonster.cpp b/dlls/tempmonster.cpp index 1f2cd7ed..8c996248 100644 --- a/dlls/tempmonster.cpp +++ b/dlls/tempmonster.cpp @@ -1,117 +1,117 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 //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. +* +****/ +//========================================================= +// 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 //0 diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index 016e850f..2fd7f057 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -1,1044 +1,1044 @@ -/*** -* -* 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. -* -****/ -#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 (m_flSoundTime < gpGlobals->time) - { - // play "I hear new something" sound - 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); - } - 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 - char *sound; - - 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 ) -{ - char *sound; - - 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"); -} - +/*** +* +* 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. +* +****/ +#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 (m_flSoundTime < gpGlobals->time) + { + // play "I hear new something" sound + 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); + } + 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 + char *sound; + + 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 ) +{ + char *sound; + + 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/dlls/trains.h b/dlls/trains.h index 4ee44112..87aec763 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -1,127 +1,127 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/triggers.cpp b/dlls/triggers.cpp index 871a1ecc..515900f8 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1,2434 +1,2434 @@ -/*** -* -* 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( &CBaseTrigger::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 pause\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( &CBaseTrigger::HurtTouch ); - - if ( !FStringNull ( pev->targetname ) ) - { - SetUse( &CBaseTrigger::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( &CBaseTrigger::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( &CBaseEntity::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( &CBaseTrigger::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 = NULL; - 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\n", 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; - LEVELLIST levels[16]; - - 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; - - // this flag was changed and flying barrels on c2a5 stay broken - if ( FStrEq( STRING( gpGlobals->mapname ), "c2a5" ) && pev->spawnflags & 4) - pev->spawnflags |= SF_TRIG_PUSH_ONCE; - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - SetUse( &CBaseTrigger::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( &CBaseTrigger::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 == NULL ) - { - 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 == NULL) - return; - - if (m_hTarget == NULL || 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)); -} +/*** +* +* 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( &CBaseTrigger::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 pause\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( &CBaseTrigger::HurtTouch ); + + if ( !FStringNull ( pev->targetname ) ) + { + SetUse( &CBaseTrigger::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( &CBaseTrigger::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( &CBaseEntity::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( &CBaseTrigger::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 = NULL; + 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\n", 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; + LEVELLIST levels[16]; + + 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; + + // this flag was changed and flying barrels on c2a5 stay broken + if ( FStrEq( STRING( gpGlobals->mapname ), "c2a5" ) && pev->spawnflags & 4) + pev->spawnflags |= SF_TRIG_PUSH_ONCE; + + if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. + pev->solid = SOLID_NOT; + + SetUse( &CBaseTrigger::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( &CBaseTrigger::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 == NULL ) + { + 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 == NULL) + return; + + if (m_hTarget == NULL || 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/dlls/tripmine.cpp b/dlls/tripmine.cpp index 11a6d959..1c780ed3 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -1,526 +1,526 @@ -/*** -* -* 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 == NULL) - { - // 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( &CBaseEntity::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( &CBaseEntity::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.0, 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 == NULL) - 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( &CBaseEntity::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 *pEnt = 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 = UTIL_WeaponTimeBase() + 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 ); -} - - - - +/*** +* +* 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 == NULL) + { + // 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( &CBaseEntity::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( &CBaseEntity::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.0, 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 == NULL) + 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( &CBaseEntity::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 *pEnt = 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 = UTIL_WeaponTimeBase() + 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/dlls/turret.cpp b/dlls/turret.cpp index 2077e87d..10a0c839 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -1,1305 +1,1305 @@ -/*** -* -* 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. -* -****/ -/* - -===== 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( &CBaseTurret::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( &CBaseTurret::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( &CBaseEntity::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 == NULL)) - { - 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( &CBaseEntity::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( &CBaseTurret::ActiveThink); - m_iStartSpin = 0; - m_iSpin = 1; - } - else - { - pev->framerate += 0.075; - } - } - - if (m_iSpin) - { - SetThink( &CBaseTurret::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; - } - //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 != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - - // Acquire Target - if (m_hEnemy == NULL) - { - Look(TURRET_RANGE); - m_hEnemy = BestVisibleEnemy(); - } - - // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != NULL) - { - 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 != NULL) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - // Acquire Target - - if (m_hEnemy == NULL) - { - Look( TURRET_RANGE ); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != NULL) - { - SetThink( &CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } -} - - -void CBaseTurret :: TurretDeath( void ) -{ - BOOL iActive = FALSE; - - 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( &CBaseTurret::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( &CBaseTurret::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 ) -{ - BOOL iActive = FALSE; - - 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 ); - } -} - +/*** +* +* 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. +* +****/ +/* + +===== 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( &CBaseTurret::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( &CBaseTurret::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( &CBaseEntity::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 == NULL)) + { + 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( &CBaseEntity::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( &CBaseTurret::ActiveThink); + m_iStartSpin = 0; + m_iSpin = 1; + } + else + { + pev->framerate += 0.075; + } + } + + if (m_iSpin) + { + SetThink( &CBaseTurret::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; + } + //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 != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + + // Acquire Target + if (m_hEnemy == NULL) + { + Look(TURRET_RANGE); + m_hEnemy = BestVisibleEnemy(); + } + + // If we've found a target, spin up the barrel and start to attack + if (m_hEnemy != NULL) + { + 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 != NULL) + { + if (!m_hEnemy->IsAlive() ) + m_hEnemy = NULL;// Dead enemy forces a search for new one + } + + // Acquire Target + + if (m_hEnemy == NULL) + { + Look( TURRET_RANGE ); + m_hEnemy = BestVisibleEnemy(); + } + + if (m_hEnemy != NULL) + { + SetThink( &CBaseTurret::Deploy); + EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + } +} + + +void CBaseTurret :: TurretDeath( void ) +{ + BOOL iActive = FALSE; + + 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( &CBaseTurret::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( &CBaseTurret::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 ) +{ + BOOL iActive = FALSE; + + 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/dlls/util.h b/dlls/util.h index cda974e4..b478b781 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -1,548 +1,548 @@ -/*** -* -* 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. -* -****/ -// -// Misc utility code -// -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -#ifndef PHYSCALLBACK_H -#include "physcallback.h" -#endif - - -#include -#include -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 + (int)offset) - -#if !defined __amd64__ || defined(CLIENT_DLL) -#define MAKE_STRING(str) ((int)str - (int)STRING(0)) -#else -#define MAKE_STRING ALLOC_STRING -#endif - -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 -#define M_PI 3.14159265358979323846 - -// Keeps clutter down a bit, when declaring external entity/global method prototypes -#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) -#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) - -// 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" EXPORT 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) -{ -#if _DEBUG - if ( !pent ) - ALERT( at_error, "Bad ent in OFFSET()\n" ); -#endif - return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); -} -inline EOFFSET OFFSET(entvars_t *pev) -{ -#if _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); -enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; -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( 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 < 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 ); +/*** +* +* 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. +* +****/ +// +// Misc utility code +// +#ifndef ACTIVITY_H +#include "activity.h" +#endif + +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif + +#ifndef PHYSCALLBACK_H +#include "physcallback.h" +#endif + + +#include +#include +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 + (int)offset) + +#if !defined __amd64__ || defined(CLIENT_DLL) +#define MAKE_STRING(str) ((int)str - (int)STRING(0)) +#else +#define MAKE_STRING ALLOC_STRING +#endif + +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 +#define M_PI 3.14159265358979323846 + +// Keeps clutter down a bit, when declaring external entity/global method prototypes +#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName( void ) +#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) + +// 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" EXPORT 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) +{ +#if _DEBUG + if ( !pent ) + ALERT( at_error, "Bad ent in OFFSET()\n" ); +#endif + return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); +} +inline EOFFSET OFFSET(entvars_t *pev) +{ +#if _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); +enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; +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( 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 < 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/dlls/vector.h b/dlls/vector.h index c498c835..efc49838 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -1,112 +1,112 @@ -/*** -* -* 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) { } - inline Vector2D(float X, float Y) { 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 - { - Vector2D vec2; - - 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) { } - inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]) { 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 ); } - - - +/*** +* +* 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) { } + inline Vector2D(float X, float Y) { 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 + { + Vector2D vec2; + + 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) { } + inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { 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 \ No newline at end of file diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index e82d1006..84ad017d 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1,1580 +1,1580 @@ -/*** -* -* 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_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( &CBaseEntity::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Kill( void ) -{ - SetTouch( NULL ); - SetThink( &CBaseEntity::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 ); - SetThink( 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( char *szViewModel, char *szWeaponModel, int iAnim, 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; - - 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( &CBaseEntity::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } - } - else if (gEvilImpulse101) - { - // evil impulse 101 hack, kill always - SetTouch( NULL ); - SetThink( &CBaseEntity::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; - - 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 ); -} - -//********************************************************* -// 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( &CBaseEntity::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, 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 ); - +/*** +* +* 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_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( &CBaseEntity::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; +} + +void CBasePlayerItem::Kill( void ) +{ + SetTouch( NULL ); + SetThink( &CBaseEntity::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 ); + SetThink( 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( char *szViewModel, char *szWeaponModel, int iAnim, 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; + + 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( &CBaseEntity::SUB_Remove); + pev->nextthink = gpGlobals->time + .1; + } + } + else if (gEvilImpulse101) + { + // evil impulse 101 hack, kill always + SetTouch( NULL ); + SetThink( &CBaseEntity::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; + + 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 ); +} + +//********************************************************* +// 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( &CBaseEntity::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, 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/dlls/weapons.h b/dlls/weapons.h index 38ba9794..8194a4d3 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -1,1015 +1,1015 @@ -/*** -* -* 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 +/*** +* +* 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/dlls/world.cpp b/dlls/world.cpp index 1206824b..d56a3fcf 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -1,860 +1,860 @@ -/*** -* -* 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" -#include "physcallback.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( &CBaseEntity::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( &CBaseEntity::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 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( ); -} - -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 < 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 ); - - // g-cont. moved here to right restore global WaveHeight on save\restore level - CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); - - 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 ); - - pev->spawnflags &= ~SF_WORLD_DARK; // g-cont. don't apply fade after save\restore - - if ( pev->spawnflags & SF_WORLD_TITLE ) - gDisplayTitle = TRUE; // display the game title if this key is set - else - gDisplayTitle = FALSE; - - pev->spawnflags &= ~SF_WORLD_TITLE; // g-cont. don't show logo after save\restore - - if ( pev->spawnflags & SF_WORLD_FORCETEAM ) - { - CVAR_SET_FLOAT( "mp_defaultteam", 1 ); - } - else - { - CVAR_SET_FLOAT( "mp_defaultteam", 0 ); - } - - // g-cont. moved here so cheats will working on restore level - g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? -} - - -// -// 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; - } - 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 ); -} - -// -// Xash3D physics interface -// - -typedef void ( *LINK_ENTITY_FN)( entvars_t *pev ); - -// -// attempt to create custom entity when default method is failed -// 0 - attempt to create, -1 - reject to create -// -int DispatchCreateEntity( edict_t *pent, const char *szName ) -{ -/* -#ifdef CREATE_ENTITY_TEST - // quake armor entities. we just replaced it with item_battery... - if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" )) - { - LINK_ENTITY_FN SpawnEdict; - - // ugly method to get acess with himself exports - SpawnEdict = (LINK_ENTITY_FN)GetProcAddress( GetModuleHandle( "hl" ), "item_battery" ); - - if( SpawnEdict != NULL ) // found the valid spawn - { - // BUGBUG: old classname hanging in memory - pent->v.classname = ALLOC_STRING( "item_battery" ); - -// ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); - - SpawnEdict( &pent->v ); - return 0; // handled - } - } -#endif -*/ - return -1; -} - -// -// run custom physics for each entity -// return 0 to use built-in engine physic -// -int DispatchPhysicsEntity( edict_t *pEdict ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pEdict); - - if( !pEntity ) - { -// ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); - return 0; // not initialized - } - - // NOTE: at this point pEntity assume to be valid -/* -#ifdef CUSTOM_PHYSICS_TEST - // test alien controller without physics, thinking only - if( FClassnameIs( pEntity->pev, "monster_alien_controller" )) - { - float thinktime; - - thinktime = pEntity->pev->nextthink; - if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime ) - return 1; - - if( thinktime < PHYSICS_TIME( )) - thinktime = PHYSICS_TIME(); // don't let things stay in the past. - // it is possible to start that way - // by a trigger with a local time. - pEntity->pev->nextthink = 0.0f; - gpGlobals->time = thinktime; - - DispatchThink( pEdict ); - -#ifdef GRAVITY_TEST - // stupid fake gravity test - pEntity->pev->origin.z -= 1; - LINK_ENTITY( pEdict, true ); -#endif - - return 1; // handled - } -#endif -*/ - return 0; -} - -static physics_interface_t gPhysicsInterface = -{ - SV_PHYSICS_INTERFACE_VERSION, - DispatchCreateEntity, - DispatchPhysicsEntity, -}; - -int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ) -{ - if ( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) - { - return FALSE; - } - - // copy new physics interface - memcpy(&g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t)); - - // fill engine callbacks - memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) ); - - return TRUE; +/*** +* +* 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" +#include "physcallback.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( &CBaseEntity::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( &CBaseEntity::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 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( ); +} + +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 < 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 ); + + // g-cont. moved here to right restore global WaveHeight on save\restore level + CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); + + 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 ); + + pev->spawnflags &= ~SF_WORLD_DARK; // g-cont. don't apply fade after save\restore + + if ( pev->spawnflags & SF_WORLD_TITLE ) + gDisplayTitle = TRUE; // display the game title if this key is set + else + gDisplayTitle = FALSE; + + pev->spawnflags &= ~SF_WORLD_TITLE; // g-cont. don't show logo after save\restore + + if ( pev->spawnflags & SF_WORLD_FORCETEAM ) + { + CVAR_SET_FLOAT( "mp_defaultteam", 1 ); + } + else + { + CVAR_SET_FLOAT( "mp_defaultteam", 0 ); + } + + // g-cont. moved here so cheats will working on restore level + g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? +} + + +// +// 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; + } + 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 ); +} + +// +// Xash3D physics interface +// + +typedef void ( *LINK_ENTITY_FN)( entvars_t *pev ); + +// +// attempt to create custom entity when default method is failed +// 0 - attempt to create, -1 - reject to create +// +int DispatchCreateEntity( edict_t *pent, const char *szName ) +{ +/* +#ifdef CREATE_ENTITY_TEST + // quake armor entities. we just replaced it with item_battery... + if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" )) + { + LINK_ENTITY_FN SpawnEdict; + + // ugly method to get acess with himself exports + SpawnEdict = (LINK_ENTITY_FN)GetProcAddress( GetModuleHandle( "hl" ), "item_battery" ); + + if( SpawnEdict != NULL ) // found the valid spawn + { + // BUGBUG: old classname hanging in memory + pent->v.classname = ALLOC_STRING( "item_battery" ); + +// ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); + + SpawnEdict( &pent->v ); + return 0; // handled + } + } +#endif +*/ + return -1; +} + +// +// run custom physics for each entity +// return 0 to use built-in engine physic +// +int DispatchPhysicsEntity( edict_t *pEdict ) +{ + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pEdict); + + if( !pEntity ) + { +// ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); + return 0; // not initialized + } + + // NOTE: at this point pEntity assume to be valid +/* +#ifdef CUSTOM_PHYSICS_TEST + // test alien controller without physics, thinking only + if( FClassnameIs( pEntity->pev, "monster_alien_controller" )) + { + float thinktime; + + thinktime = pEntity->pev->nextthink; + if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime ) + return 1; + + if( thinktime < PHYSICS_TIME( )) + thinktime = PHYSICS_TIME(); // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + pEntity->pev->nextthink = 0.0f; + gpGlobals->time = thinktime; + + DispatchThink( pEdict ); + +#ifdef GRAVITY_TEST + // stupid fake gravity test + pEntity->pev->origin.z -= 1; + LINK_ENTITY( pEdict, true ); +#endif + + return 1; // handled + } +#endif +*/ + return 0; +} + +static physics_interface_t gPhysicsInterface = +{ + SV_PHYSICS_INTERFACE_VERSION, + DispatchCreateEntity, + DispatchPhysicsEntity, +}; + +int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ) +{ + if ( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) + { + return FALSE; + } + + // copy new physics interface + memcpy(&g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t)); + + // fill engine callbacks + memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) ); + + return TRUE; } diff --git a/dlls/wxdebug.h b/dlls/wxdebug.h index 321b1bcd..026039ae 100644 --- a/dlls/wxdebug.h +++ b/dlls/wxdebug.h @@ -1,137 +1,137 @@ -#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__ - - +#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/dlls/xen.cpp b/dlls/xen.cpp index a52ea6b5..c7f9ebc4 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -1,584 +1,584 @@ -/*** -* -* 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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 < 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 ) -{ - float flInterval = StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - -#if 0 - DispatchAnimEvents( flInterval ); - - switch( GetActivity() ) - { - default: - case ACT_IDLE: - break; - - } -#endif -} - - +/*** +* +* 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, 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 < 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 ) +{ + float flInterval = StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + +#if 0 + DispatchAnimEvents( flInterval ); + + switch( GetActivity() ) + { + default: + case ACT_IDLE: + break; + + } +#endif +} + + diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 234eafca..89dc8231 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -1,346 +1,346 @@ -/*** -* -* 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. -* -****/ -//========================================================= -// 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 ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - // 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() -{ - int 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; - +/*** +* +* 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. +* +****/ +//========================================================= +// 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 ) +{ + int pitch = 95 + RANDOM_LONG(0,9); + + // 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() +{ + int 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; + } \ No newline at end of file diff --git a/engine/anorms.h b/engine/anorms.h index c90f8d6f..d147aea0 100644 --- a/engine/anorms.h +++ b/engine/anorms.h @@ -1,177 +1,177 @@ -/*** -* -* 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}, +/*** +* +* 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/engine/cdll_exp.h b/engine/cdll_exp.h index 07227057..bf43654c 100644 --- a/engine/cdll_exp.h +++ b/engine/cdll_exp.h @@ -1,69 +1,69 @@ -/* -cdll_exp.h - exports for client -Copyright (C) 2013 Uncle Mike - -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. -*/ -#ifndef CDLL_EXP_H -#define CDLL_EXP_H - -// NOTE: ordering is important! -typedef struct cldll_func_s -{ - int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion ); - void (*pfnInit)( void ); - int (*pfnVidInit)( void ); - int (*pfnRedraw)( float flTime, int intermission ); - int (*pfnUpdateClientData)( client_data_t *cdata, float flTime ); - void (*pfnReset)( void ); - void (*pfnPlayerMove)( struct playermove_s *ppmove, int server ); - void (*pfnPlayerMoveInit)( struct playermove_s *ppmove ); - char (*pfnPlayerMoveTexture)( char *name ); - void (*IN_ActivateMouse)( void ); - void (*IN_DeactivateMouse)( void ); - void (*IN_MouseEvent)( int mstate ); - void (*IN_ClearStates)( void ); - void (*IN_Accumulate)( void ); - void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active ); - int (*CL_IsThirdPerson)( void ); - void (*CL_CameraOffset)( float *ofs ); - void *(*KB_Find)( const char *name ); - void (*CAM_Think)( void ); // camera stuff - void (*pfnCalcRefdef)( ref_params_t *pparams ); - int (*pfnAddEntity)( int type, cl_entity_t *ent, const char *modelname ); - void (*pfnCreateEntities)( void ); - void (*pfnDrawNormalTriangles)( void ); - void (*pfnDrawTransparentTriangles)( void ); - void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity ); - void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed ); - void (*pfnShutdown)( void ); - void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client ); - void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src ); - void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd ); - void (*pfnDemo_ReadBuffer)( int size, byte *buffer ); - int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size ); - int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs ); - void (*pfnFrame)( double time ); - int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding ); - void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp )); - cl_entity_t *(*pfnGetUserEntity)( int index ); - void (*pfnVoiceStatus)( int entindex, qboolean bTalking ); - void (*pfnDirectorMessage)( int iSize, void *pbuf ); - int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); - void (*pfnChatInputPosition)( int *x, int *y ); - int (*pfnGetPlayerTeam)( int playerIndex ); - void *(*pfnGetClientFactory)( void ); - // Xash3D extension - int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback ); - void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr ); -} cldll_func_t; - +/* +cdll_exp.h - exports for client +Copyright (C) 2013 Uncle Mike + +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. +*/ +#ifndef CDLL_EXP_H +#define CDLL_EXP_H + +// NOTE: ordering is important! +typedef struct cldll_func_s +{ + int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion ); + void (*pfnInit)( void ); + int (*pfnVidInit)( void ); + int (*pfnRedraw)( float flTime, int intermission ); + int (*pfnUpdateClientData)( client_data_t *cdata, float flTime ); + void (*pfnReset)( void ); + void (*pfnPlayerMove)( struct playermove_s *ppmove, int server ); + void (*pfnPlayerMoveInit)( struct playermove_s *ppmove ); + char (*pfnPlayerMoveTexture)( char *name ); + void (*IN_ActivateMouse)( void ); + void (*IN_DeactivateMouse)( void ); + void (*IN_MouseEvent)( int mstate ); + void (*IN_ClearStates)( void ); + void (*IN_Accumulate)( void ); + void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active ); + int (*CL_IsThirdPerson)( void ); + void (*CL_CameraOffset)( float *ofs ); + void *(*KB_Find)( const char *name ); + void (*CAM_Think)( void ); // camera stuff + void (*pfnCalcRefdef)( ref_params_t *pparams ); + int (*pfnAddEntity)( int type, cl_entity_t *ent, const char *modelname ); + void (*pfnCreateEntities)( void ); + void (*pfnDrawNormalTriangles)( void ); + void (*pfnDrawTransparentTriangles)( void ); + void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity ); + void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed ); + void (*pfnShutdown)( void ); + void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client ); + void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src ); + void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd ); + void (*pfnDemo_ReadBuffer)( int size, byte *buffer ); + int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size ); + int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs ); + void (*pfnFrame)( double time ); + int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding ); + void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp )); + cl_entity_t *(*pfnGetUserEntity)( int index ); + void (*pfnVoiceStatus)( int entindex, qboolean bTalking ); + void (*pfnDirectorMessage)( int iSize, void *pbuf ); + int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); + void (*pfnChatInputPosition)( int *x, int *y ); + int (*pfnGetPlayerTeam)( int playerIndex ); + void *(*pfnGetClientFactory)( void ); + // Xash3D extension + int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback ); + void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr ); +} cldll_func_t; + #endif//CDLL_EXP_H \ No newline at end of file diff --git a/engine/cdll_int.h b/engine/cdll_int.h index dd3b0a02..b77a174a 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -1,308 +1,308 @@ -/*** -* -* 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" - -#define MAX_ALIAS_NAME 32 - -typedef struct cmdalias_s -{ - struct cmdalias_s *next; - char name[MAX_ALIAS_NAME]; - char *value; -} cmdalias_t; - -// this file is included by both the engine and the client-dll, -// so make sure engine declarations aren't done twice - -typedef int HSPRITE; // handle to a graphic -typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); - -#include "wrect.h" - -#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; - 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 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; - -typedef struct hud_player_info_s -{ - char *name; - short ping; - byte thisplayer; // TRUE if this is the calling player - - // stuff that's unused at the moment, but should be done - byte spectator; - byte packetloss; - char *model; - short topcolor; - short bottomcolor; - - unsigned long long m_nSteamID; -} hud_player_info_t; - -typedef struct cl_enginefuncs_s -{ - // sprite handlers - HSPRITE (*pfnSPR_Load)( const char *szPicName ); - int (*pfnSPR_Frames)( HSPRITE hPic ); - int (*pfnSPR_Height)( HSPRITE hPic, int frame ); - int (*pfnSPR_Width)( HSPRITE hPic, int frame ); - void (*pfnSPR_Set)( HSPRITE hPic, int r, int g, int b ); - void (*pfnSPR_Draw)( int frame, int x, int y, const wrect_t *prc ); - void (*pfnSPR_DrawHoles)( int frame, int x, int y, const wrect_t *prc ); - void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc ); - void (*pfnSPR_EnableScissor)( int x, int y, int width, int height ); - void (*pfnSPR_DisableScissor)( void ); - client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount ); - - // screen handlers - void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); - int (*pfnGetScreenInfo)( SCREENINFO *pscrinfo ); - void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b ); - - // cvar handlers - struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags ); - float (*pfnGetCvarFloat)( char *szName ); - char* (*pfnGetCvarString)( char *szName ); - - // command handlers - int (*pfnAddCommand)( char *cmd_name, void (*function)(void) ); - int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn ); - int (*pfnServerCmd)( char *szCmdString ); - int (*pfnClientCmd)( char *szCmdString ); - - void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo ); - - // sound handlers - void (*pfnPlaySoundByName)( char *szSound, float volume ); - void (*pfnPlaySoundByIndex)( int iSound, float volume ); - - // vector helpers - void (*pfnAngleVectors)( const float *vecAngles, float *forward, float *right, float *up ); - - // text message system - client_textmessage_t *(*pfnTextMessageGet)( const char *pName ); - int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b ); - int (*pfnDrawConsoleString)( int x, int y, char *string ); - void (*pfnDrawSetTextColor)( float r, float g, float b ); - void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); - - void (*pfnConsolePrint)( const char *string ); - void (*pfnCenterPrint)( const char *string ); - - // Added for user input processing - int (*GetWindowCenterX)( void ); - int (*GetWindowCenterY)( void ); - void (*GetViewAngles)( float * ); - void (*SetViewAngles)( float * ); - int (*GetMaxClients)( void ); - void (*Cvar_SetValue)( char *cvar, float value ); - - int (*Cmd_Argc)( void ); - char *(*Cmd_Argv)( int arg ); - void (*Con_Printf)( char *fmt, ... ); - void (*Con_DPrintf)( char *fmt, ... ); - void (*Con_NPrintf)( int pos, char *fmt, ... ); - void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); - - const char* (*PhysInfo_ValueForKey)( const char *key ); - const char* (*ServerInfo_ValueForKey)( const char *key ); - float (*GetClientMaxspeed)( void ); - int (*CheckParm)( char *parm, char **ppnext ); - - void (*Key_Event)( int key, int down ); - void (*GetMousePosition)( int *mx, int *my ); - int (*IsNoClipping)( void ); - - struct cl_entity_s *(*GetLocalPlayer)( void ); - struct cl_entity_s *(*GetViewModel)( void ); - struct cl_entity_s *(*GetEntityByIndex)( int idx ); - - float (*GetClientTime)( void ); - void (*V_CalcShake)( void ); - void (*V_ApplyShake)( float *origin, float *angles, float factor ); - - int (*PM_PointContents)( float *point, int *truecontents ); - int (*PM_WaterEntity)( float *p ); - struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehull, int ignore_pe ); - - struct model_s *(*CL_LoadModel)( const char *modelname, int *index ); - int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); - - const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); - void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); - - unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); - void (*pfnPlaybackEvent)( 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 ); - void (*pfnWeaponAnim)( int iAnim, int body ); - float (*pfnRandomFloat)( float flLow, float flHigh ); - long (*pfnRandomLong)( long lLow, long lHigh ); - void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); - int (*Con_IsVisible) (); - const char *(*pfnGetGameDirectory)( void ); - struct cvar_s *(*pfnGetCvarPointer)( const char *szName ); - const char *(*Key_LookupBinding)( const char *pBinding ); - const char *(*pfnGetLevelName)( void ); - void (*pfnGetScreenFade)( struct screenfade_s *fade ); - void (*pfnSetScreenFade)( struct screenfade_s *fade ); - void* (*VGui_GetPanel)( ); - void (*VGui_ViewportPaintBackground)( int extents[4] ); - - byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength ); - char* (*COM_ParseFile)( char *data, char *token ); - void (*COM_FreeFile)( void *buffer ); - - 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; - - // returns 1 if the client is a spectator only (connected to a proxy), 0 otherwise or 2 if in dev_overview mode - int (*IsSpectateOnly)( void ); - struct model_s *(*LoadMapSprite)( const char *filename ); - - // file search functions - void (*COM_AddAppDirectoryToSearchPath)( const char *pszBaseDir, const char *appName ); - int (*COM_ExpandFilename)( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); - - // User info - // playerNum is in the range (1, MaxClients) - // returns NULL if player doesn't exit - // returns "" if no value is set - const char *( *PlayerInfo_ValueForKey )( int playerNum, const char *key ); - void (*PlayerInfo_SetValueForKey )( const char *key, const char *value ); - - // Gets a unique ID for the specified player. This is the same even if you see the player on a different server. - // iPlayer is an entity index, so client 0 would use iPlayer=1. - // Returns false if there is no player on the server in the specified slot. - qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]); - - // TrackerID access - int (*GetTrackerIDForPlayer)(int playerSlot); - int (*GetPlayerForTrackerID)(int trackerID); - - // Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream - // (but it might not get there). - int ( *pfnServerCmdUnreliable )( char *szCmdString ); - - void (*pfnGetMousePos)( struct tagPOINT *ppt ); - void (*pfnSetMousePos)( int x, int y ); - void (*pfnSetMouseEnable)( qboolean fEnable ); - - // undocumented interface starts here - struct cvar_s* (*pfnGetFirstCvarPtr)( void ); - void* (*pfnGetFirstCmdFunctionHandle)( void ); - void* (*pfnGetNextCmdFunctionHandle)( void *cmdhandle ); - const char* (*pfnGetCmdFunctionName)( void *cmdhandle ); - float (*pfnGetClientOldTime)( void ); - float (*pfnGetGravity)( void ); - struct model_s* (*pfnGetModelByIndex)( int index ); - void (*pfnSetFilterMode)( int mode ); // same as gl_texsort in original Quake - void (*pfnSetFilterColor)( float red, float green, float blue ); - void (*pfnSetFilterBrightness)( float brightness ); - void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); - void (*pfnSPR_DrawGeneric)( int frame, int x, int y, const wrect_t *prc, int blendsrc, int blenddst, int width, int height ); - void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *entryPicked ); - int (*pfnDrawString)( int x, int y, const char *str, int r, int g, int b ); - int (*pfnDrawStringReverse)( int x, int y, const char *str, int r, int g, int b ); - const char *(*LocalPlayerInfo_ValueForKey)( const char* key ); - int (*pfnVGUI2DrawCharacter)( int x, int y, int ch, unsigned int font ); - int (*pfnVGUI2DrawCharacterAdditive)( int x, int y, int ch, int r, int g, int b, unsigned int font ); - unsigned int (*pfnGetApproxWavePlayLen)( char *filename ); - void* (*GetCareerGameUI)( void ); // g-cont. !!!! potential crash-point! - void (*Cvar_Set)( char *name, char *value ); - int (*pfnIsPlayingCareerMatch)( void ); - void (*pfnPlaySoundVoiceByName)( char *szSound, float volume, int pitch ); - void (*pfnPrimeMusicStream)( char *filename, int looping ); - double (*pfnSys_FloatTime)( void ); - - // decay funcs - void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int buflen ); - void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen ); - void (*pfnResetTutorMessageDecayData)( void ); - - void (*pfnPlaySoundByNameAtPitch)( char *szSound, float volume, int pitch ); - void (*pfnFillRGBABlend)( int x, int y, int width, int height, int r, int g, int b, int a ); - int (*pfnGetAppID)( void ); - cmdalias_t *(*pfnGetAliases)( void ); - void (*pfnVguiWrap2_GetMouseDelta)( int *x, int *y ); -} cl_enginefunc_t; - -#define CLDLL_INTERFACE_VERSION 7 - -#ifdef __cplusplus -} -#endif - +/*** +* +* 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" + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +// this file is included by both the engine and the client-dll, +// so make sure engine declarations aren't done twice + +typedef int HSPRITE; // handle to a graphic +typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); + +#include "wrect.h" + +#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; + 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 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; + +typedef struct hud_player_info_s +{ + char *name; + short ping; + byte thisplayer; // TRUE if this is the calling player + + // stuff that's unused at the moment, but should be done + byte spectator; + byte packetloss; + char *model; + short topcolor; + short bottomcolor; + + unsigned long long m_nSteamID; +} hud_player_info_t; + +typedef struct cl_enginefuncs_s +{ + // sprite handlers + HSPRITE (*pfnSPR_Load)( const char *szPicName ); + int (*pfnSPR_Frames)( HSPRITE hPic ); + int (*pfnSPR_Height)( HSPRITE hPic, int frame ); + int (*pfnSPR_Width)( HSPRITE hPic, int frame ); + void (*pfnSPR_Set)( HSPRITE hPic, int r, int g, int b ); + void (*pfnSPR_Draw)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawHoles)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc ); + void (*pfnSPR_EnableScissor)( int x, int y, int width, int height ); + void (*pfnSPR_DisableScissor)( void ); + client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount ); + + // screen handlers + void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetScreenInfo)( SCREENINFO *pscrinfo ); + void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b ); + + // cvar handlers + struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags ); + float (*pfnGetCvarFloat)( char *szName ); + char* (*pfnGetCvarString)( char *szName ); + + // command handlers + int (*pfnAddCommand)( char *cmd_name, void (*function)(void) ); + int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn ); + int (*pfnServerCmd)( char *szCmdString ); + int (*pfnClientCmd)( char *szCmdString ); + + void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo ); + + // sound handlers + void (*pfnPlaySoundByName)( char *szSound, float volume ); + void (*pfnPlaySoundByIndex)( int iSound, float volume ); + + // vector helpers + void (*pfnAngleVectors)( const float *vecAngles, float *forward, float *right, float *up ); + + // text message system + client_textmessage_t *(*pfnTextMessageGet)( const char *pName ); + int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b ); + int (*pfnDrawConsoleString)( int x, int y, char *string ); + void (*pfnDrawSetTextColor)( float r, float g, float b ); + void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); + + void (*pfnConsolePrint)( const char *string ); + void (*pfnCenterPrint)( const char *string ); + + // Added for user input processing + int (*GetWindowCenterX)( void ); + int (*GetWindowCenterY)( void ); + void (*GetViewAngles)( float * ); + void (*SetViewAngles)( float * ); + int (*GetMaxClients)( void ); + void (*Cvar_SetValue)( char *cvar, float value ); + + int (*Cmd_Argc)( void ); + char *(*Cmd_Argv)( int arg ); + void (*Con_Printf)( char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_NPrintf)( int pos, char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + + const char* (*PhysInfo_ValueForKey)( const char *key ); + const char* (*ServerInfo_ValueForKey)( const char *key ); + float (*GetClientMaxspeed)( void ); + int (*CheckParm)( char *parm, char **ppnext ); + + void (*Key_Event)( int key, int down ); + void (*GetMousePosition)( int *mx, int *my ); + int (*IsNoClipping)( void ); + + struct cl_entity_s *(*GetLocalPlayer)( void ); + struct cl_entity_s *(*GetViewModel)( void ); + struct cl_entity_s *(*GetEntityByIndex)( int idx ); + + float (*GetClientTime)( void ); + void (*V_CalcShake)( void ); + void (*V_ApplyShake)( float *origin, float *angles, float factor ); + + int (*PM_PointContents)( float *point, int *truecontents ); + int (*PM_WaterEntity)( float *p ); + struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehull, int ignore_pe ); + + struct model_s *(*CL_LoadModel)( const char *modelname, int *index ); + int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); + + const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); + void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); + + unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); + void (*pfnPlaybackEvent)( 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 ); + void (*pfnWeaponAnim)( int iAnim, int body ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + long (*pfnRandomLong)( long lLow, long lHigh ); + void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); + int (*Con_IsVisible) (); + const char *(*pfnGetGameDirectory)( void ); + struct cvar_s *(*pfnGetCvarPointer)( const char *szName ); + const char *(*Key_LookupBinding)( const char *pBinding ); + const char *(*pfnGetLevelName)( void ); + void (*pfnGetScreenFade)( struct screenfade_s *fade ); + void (*pfnSetScreenFade)( struct screenfade_s *fade ); + void* (*VGui_GetPanel)( ); + void (*VGui_ViewportPaintBackground)( int extents[4] ); + + byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength ); + char* (*COM_ParseFile)( char *data, char *token ); + void (*COM_FreeFile)( void *buffer ); + + 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; + + // returns 1 if the client is a spectator only (connected to a proxy), 0 otherwise or 2 if in dev_overview mode + int (*IsSpectateOnly)( void ); + struct model_s *(*LoadMapSprite)( const char *filename ); + + // file search functions + void (*COM_AddAppDirectoryToSearchPath)( const char *pszBaseDir, const char *appName ); + int (*COM_ExpandFilename)( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); + + // User info + // playerNum is in the range (1, MaxClients) + // returns NULL if player doesn't exit + // returns "" if no value is set + const char *( *PlayerInfo_ValueForKey )( int playerNum, const char *key ); + void (*PlayerInfo_SetValueForKey )( const char *key, const char *value ); + + // Gets a unique ID for the specified player. This is the same even if you see the player on a different server. + // iPlayer is an entity index, so client 0 would use iPlayer=1. + // Returns false if there is no player on the server in the specified slot. + qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]); + + // TrackerID access + int (*GetTrackerIDForPlayer)(int playerSlot); + int (*GetPlayerForTrackerID)(int trackerID); + + // Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream + // (but it might not get there). + int ( *pfnServerCmdUnreliable )( char *szCmdString ); + + void (*pfnGetMousePos)( struct tagPOINT *ppt ); + void (*pfnSetMousePos)( int x, int y ); + void (*pfnSetMouseEnable)( qboolean fEnable ); + + // undocumented interface starts here + struct cvar_s* (*pfnGetFirstCvarPtr)( void ); + void* (*pfnGetFirstCmdFunctionHandle)( void ); + void* (*pfnGetNextCmdFunctionHandle)( void *cmdhandle ); + const char* (*pfnGetCmdFunctionName)( void *cmdhandle ); + float (*pfnGetClientOldTime)( void ); + float (*pfnGetGravity)( void ); + struct model_s* (*pfnGetModelByIndex)( int index ); + void (*pfnSetFilterMode)( int mode ); // same as gl_texsort in original Quake + void (*pfnSetFilterColor)( float red, float green, float blue ); + void (*pfnSetFilterBrightness)( float brightness ); + void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); + void (*pfnSPR_DrawGeneric)( int frame, int x, int y, const wrect_t *prc, int blendsrc, int blenddst, int width, int height ); + void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *entryPicked ); + int (*pfnDrawString)( int x, int y, const char *str, int r, int g, int b ); + int (*pfnDrawStringReverse)( int x, int y, const char *str, int r, int g, int b ); + const char *(*LocalPlayerInfo_ValueForKey)( const char* key ); + int (*pfnVGUI2DrawCharacter)( int x, int y, int ch, unsigned int font ); + int (*pfnVGUI2DrawCharacterAdditive)( int x, int y, int ch, int r, int g, int b, unsigned int font ); + unsigned int (*pfnGetApproxWavePlayLen)( char *filename ); + void* (*GetCareerGameUI)( void ); // g-cont. !!!! potential crash-point! + void (*Cvar_Set)( char *name, char *value ); + int (*pfnIsPlayingCareerMatch)( void ); + void (*pfnPlaySoundVoiceByName)( char *szSound, float volume, int pitch ); + void (*pfnPrimeMusicStream)( char *filename, int looping ); + double (*pfnSys_FloatTime)( void ); + + // decay funcs + void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen ); + void (*pfnResetTutorMessageDecayData)( void ); + + void (*pfnPlaySoundByNameAtPitch)( char *szSound, float volume, int pitch ); + void (*pfnFillRGBABlend)( int x, int y, int width, int height, int r, int g, int b, int a ); + int (*pfnGetAppID)( void ); + cmdalias_t *(*pfnGetAliases)( void ); + void (*pfnVguiWrap2_GetMouseDelta)( int *x, int *y ); +} cl_enginefunc_t; + +#define CLDLL_INTERFACE_VERSION 7 + +#ifdef __cplusplus +} +#endif + #endif//CDLL_INT_H \ No newline at end of file diff --git a/engine/custom.h b/engine/custom.h index d7093818..aed6d4a1 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -1,93 +1,93 @@ -/*** -* -* 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 CUSTOM_H -#define CUSTOM_H - -#include "const.h" - -///////////////// -// Customization -// passed to pfnPlayerCustomization -// For automatic downloading. - -typedef enum -{ - t_sound = 0, - t_skin, - t_model, - t_decal, - t_generic, - t_eventscript, - t_world, // Fake type for world, is really t_model -} resourcetype_t; - -typedef struct -{ - int size; -} _resourceinfo_t; - -typedef struct resourceinfo_s -{ - _resourceinfo_t info[8]; -} resourceinfo_t; - -#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. -#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? -#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization - // 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_CHECKFILE (1<<7) // Check file on client - -typedef struct resource_s -{ - char szFileName[64]; // File name to download/precache. - resourcetype_t type; // t_sound, t_skin, t_model, t_decal. - int nIndex; // For t_decals - int nDownloadSize; // Size in Bytes if this must be downloaded. - unsigned char ucFlags; - - // for handling client to client resource propagation - unsigned char rgucMD5_hash[16]; // To determine if we already have it. - unsigned char playernum; // Which player index this resource is associated with, - // if it's a custom resource. - - unsigned char rguc_reserved[32]; // For future expansion - struct resource_s *pNext; // Next in chain. - struct resource_s *pPrev; -} resource_t; - -typedef struct customization_s -{ - qboolean bInUse; // Is this customization in use; - resource_t resource; // The resource_t for this customization - qboolean bTranslated; // Has the raw data been translated into a useable format? - // (e.g., raw decal .wad make into texture_t *) - int nUserData1; // Customization specific data - int nUserData2; // Customization specific data - void *pInfo; // Buffer that holds the data structure that references - // the data (e.g., the cachewad_t) - void *pBuffer; // Buffer that holds the data for the customization - // (the raw .wad data) - struct customization_s *pNext; // Next in chain -} customization_t; - -#define FCUST_FROMHPAK ( 1<<0 ) -#define FCUST_WIPEDATA ( 1<<1 ) -#define FCUST_IGNOREINIT ( 1<<2 ) - +/*** +* +* 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 CUSTOM_H +#define CUSTOM_H + +#include "const.h" + +///////////////// +// Customization +// passed to pfnPlayerCustomization +// For automatic downloading. + +typedef enum +{ + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // Fake type for world, is really t_model +} resourcetype_t; + +typedef struct +{ + int size; +} _resourceinfo_t; + +typedef struct resourceinfo_s +{ + _resourceinfo_t info[8]; +} resourceinfo_t; + +#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. +#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? +#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization + // 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_CHECKFILE (1<<7) // Check file on client + +typedef struct resource_s +{ + char szFileName[64]; // File name to download/precache. + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. + int nIndex; // For t_decals + int nDownloadSize; // Size in Bytes if this must be downloaded. + unsigned char ucFlags; + + // for handling client to client resource propagation + unsigned char rgucMD5_hash[16]; // To determine if we already have it. + unsigned char playernum; // Which player index this resource is associated with, + // if it's a custom resource. + + unsigned char rguc_reserved[32]; // For future expansion + struct resource_s *pNext; // Next in chain. + struct resource_s *pPrev; +} resource_t; + +typedef struct customization_s +{ + qboolean bInUse; // Is this customization in use; + resource_t resource; // The resource_t for this customization + qboolean bTranslated; // Has the raw data been translated into a useable format? + // (e.g., raw decal .wad make into texture_t *) + int nUserData1; // Customization specific data + int nUserData2; // Customization specific data + void *pInfo; // Buffer that holds the data structure that references + // the data (e.g., the cachewad_t) + void *pBuffer; // Buffer that holds the data for the customization + // (the raw .wad data) + struct customization_s *pNext; // Next in chain +} customization_t; + +#define FCUST_FROMHPAK ( 1<<0 ) +#define FCUST_WIPEDATA ( 1<<1 ) +#define FCUST_IGNOREINIT ( 1<<2 ) + #endif // CUSTOM_H \ No newline at end of file diff --git a/engine/customentity.h b/engine/customentity.h index 78475f9b..dc867e5b 100644 --- a/engine/customentity.h +++ b/engine/customentity.h @@ -1,39 +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 CUSTOMENTITY_H -#define CUSTOMENTITY_H - -// Custom Entities - -// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12) -#define BEAMENT_ENTITY( x ) ((x) & 0xFFF) -#define BEAMENT_ATTACHMENT( x ) (((x)>>12) & 0xF) - -// Beam types, encoded as a byte -enum -{ - BEAM_POINTS = 0, - BEAM_ENTPOINT, - BEAM_ENTS, - BEAM_HOSE, -}; - -#define BEAM_FSINE 0x10 -#define BEAM_FSOLID 0x20 -#define BEAM_FSHADEIN 0x40 -#define BEAM_FSHADEOUT 0x80 - +/*** +* +* 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 CUSTOMENTITY_H +#define CUSTOMENTITY_H + +// Custom Entities + +// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12) +#define BEAMENT_ENTITY( x ) ((x) & 0xFFF) +#define BEAMENT_ATTACHMENT( x ) (((x)>>12) & 0xF) + +// Beam types, encoded as a byte +enum +{ + BEAM_POINTS = 0, + BEAM_ENTPOINT, + BEAM_ENTS, + BEAM_HOSE, +}; + +#define BEAM_FSINE 0x10 +#define BEAM_FSOLID 0x20 +#define BEAM_FSHADEIN 0x40 +#define BEAM_FSHADEOUT 0x80 + #endif//CUSTOMENTITY_H \ No newline at end of file diff --git a/engine/edict.h b/engine/edict.h index be63daac..b0469b86 100644 --- a/engine/edict.h +++ b/engine/edict.h @@ -1,42 +1,42 @@ -/*** -* -* 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 EDICT_H -#define EDICT_H - -#define MAX_ENT_LEAFS 48 - -#include "progdefs.h" - -struct edict_s -{ - qboolean free; - int serialnumber; - - link_t area; // linked to a division node or leaf - int headnode; // -1 to use normal leaf check - - int num_leafs; - short leafnums[MAX_ENT_LEAFS]; - - float freetime; // sv.time when the object was freed - - void* pvPrivateData; // Alloced and freed by engine, used by DLLs - entvars_t v; // C exported fields from progs - - // other fields from progs come immediately after -}; - +/*** +* +* 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 EDICT_H +#define EDICT_H + +#define MAX_ENT_LEAFS 48 + +#include "progdefs.h" + +struct edict_s +{ + qboolean free; + int serialnumber; + + link_t area; // linked to a division node or leaf + int headnode; // -1 to use normal leaf check + + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + + float freetime; // sv.time when the object was freed + + void* pvPrivateData; // Alloced and freed by engine, used by DLLs + entvars_t v; // C exported fields from progs + + // other fields from progs come immediately after +}; + #endif//EDICT_H \ No newline at end of file diff --git a/engine/eiface.h b/engine/eiface.h index 5f830ac9..71d87c26 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -1,491 +1,491 @@ -/*** -* -* 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 EIFACE_H -#define EIFACE_H - -#ifdef HLDEMO_BUILD -#define INTERFACE_VERSION 001 -#else // !HLDEMO_BUILD, i.e., regular version of HL -#define INTERFACE_VERSION 140 -#endif // !HLDEMO_BUILD - -#include -#include "custom.h" -#include "cvardef.h" -// -// Defines entity interface between engine and DLLs. -// This header file included by engine files and DLL files. -// -// Before including this header, DLLs must: -// include progdefs.h -// This is conveniently done for them in extdll.h -// - -typedef enum -{ - 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 -{ - print_console, - print_center, - print_chat, -} PRINT_TYPE; - -// For integrity checking of content on clients -typedef enum -{ - 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_TYPE; - -// Returned by TraceLine -typedef struct -{ - int fAllSolid; // if true, plane is not valid - int fStartSolid; // if true, the initial point was in a solid area - int fInOpen; - int fInWater; - float flFraction; // time completed, 1.0 = didn't hit anything - vec3_t vecEndPos; // final position - float flPlaneDist; - 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 -{ - int fPlaying;// is sound playing right now? - int fWasPlaying;// if not, CD is paused if WasPlaying is true. - int fInitialized; - int fEnabled; - int fPlayLooping; - float cdvolume; - int fCDRom; - int fPlayTrack; -} CDStatus; - -typedef unsigned long CRC32_t; - -// Engine hands this to DLLs for functionality callbacks -typedef struct enginefuncs_s -{ - int (*pfnPrecacheModel)( char* s ); - int (*pfnPrecacheSound)( char* s ); - void (*pfnSetModel)( edict_t *e, const char *m ); - int (*pfnModelIndex)( const char *m ); - int (*pfnModelFrames)( int modelIndex ); - void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); - void (*pfnChangeLevel)( char* s1, char* s2 ); - void (*pfnGetSpawnParms)( edict_t *ent ); - void (*pfnSaveSpawnParms)( edict_t *ent ); - float (*pfnVecToYaw)( const float *rgflVector ); - void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut ); - void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); - void (*pfnChangeYaw)( edict_t* ent ); - void (*pfnChangePitch)( edict_t* ent ); - edict_t* (*pfnFindEntityByString)( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); - int (*pfnGetEntityIllum)( edict_t* pEnt ); - edict_t* (*pfnFindEntityInSphere)( edict_t *pEdictStartSearchAfter, const float *org, float rad ); - edict_t* (*pfnFindClientInPVS)( edict_t *pEdict ); - edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer ); - void (*pfnMakeVectors)( const float *rgflVector ); - void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up ); - edict_t* (*pfnCreateEntity)( void ); - void (*pfnRemoveEntity)( edict_t* e ); - edict_t* (*pfnCreateNamedEntity)( int className ); - void (*pfnMakeStatic)( edict_t *ent ); - int (*pfnEntIsOnFloor)( edict_t *e ); - int (*pfnDropToFloor)( edict_t* e ); - int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode ); - void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin ); - void (*pfnEmitSound)( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch ); - void (*pfnEmitAmbientSound)( edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch ); - void (*pfnTraceLine)( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); - void (*pfnTraceToss)( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); - int (*pfnTraceMonsterHull)( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); - void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); - void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); - 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)( char* str ); - void (*pfnServerExecute)( void ); - void (*pfnClientCommand)( edict_t* pEdict, char* szFmt, ... ); - void (*pfnParticleEffect)( const float *org, const float *dir, float color, float count ); - 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 ); - void (*pfnMessageEnd)( void ); - void (*pfnWriteByte)( int iValue ); - void (*pfnWriteChar)( int iValue ); - void (*pfnWriteShort)( int iValue ); - void (*pfnWriteLong)( int iValue ); - void (*pfnWriteAngle)( float flValue ); - void (*pfnWriteCoord)( float flValue ); - void (*pfnWriteString)( const char *sz ); - void (*pfnWriteEntity)( int iValue ); - void (*pfnCVarRegister)( cvar_t *pCvar ); - float (*pfnCVarGetFloat)( const char *szVarName ); - const char* (*pfnCVarGetString)( const char *szVarName ); - void (*pfnCVarSetFloat)( const char *szVarName, float flValue ); - void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); - void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); - void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); - void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); - void* (*pfnPvEntPrivateData)( edict_t *pEdict ); - void (*pfnFreeEntPrivateData)( edict_t *pEdict ); - const char *(*pfnSzFromIndex)( int iString ); - int (*pfnAllocString)( const char *szValue ); - struct entvars_s *(*pfnGetVarsOfEnt)( edict_t *pEdict ); - edict_t* (*pfnPEntityOfEntOffset)( int iEntOffset ); - int (*pfnEntOffsetOfPEntity)( const edict_t *pEdict ); - int (*pfnIndexOfEdict)( const edict_t *pEdict ); - edict_t* (*pfnPEntityOfEntIndex)( int iEntIndex ); - edict_t* (*pfnFindEntityByVars)( struct entvars_s* pvars ); - void* (*pfnGetModelPtr)( edict_t* pEdict ); - int (*pfnRegUserMsg)( const char *pszName, int iSize ); - void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); - void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); - unsigned long (*pfnFunctionFromName)( const char *pName ); - const char *(*pfnNameForFunction)( unsigned long function ); - void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients - void (*pfnServerPrint)( const char *szMsg ); - const char *(*pfnCmd_Args)( void ); // these 3 added - const char *(*pfnCmd_Argv)( int argc ); // so game DLL can easily - int (*pfnCmd_Argc)( void ); // access client 'cmd' strings - void (*pfnGetAttachment)( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); - void (*pfnCRC32_Init)( CRC32_t *pulCRC ); - void (*pfnCRC32_ProcessBuffer)( CRC32_t *pulCRC, void *p, int len ); - void (*pfnCRC32_ProcessByte)( CRC32_t *pulCRC, unsigned char ch ); - CRC32_t (*pfnCRC32_Final)( CRC32_t pulCRC ); - long (*pfnRandomLong)( long lLow, long lHigh ); - float (*pfnRandomFloat)( float flLow, float flHigh ); - 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)( 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 ); - 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 ); - char* (*pfnGetInfoKeyBuffer)( edict_t *e ); // passing in NULL gets the serverinfo - char* (*pfnInfoKeyValue)( char *infobuffer, char *key ); - void (*pfnSetKeyValue)( char *infobuffer, char *key, char *value ); - void (*pfnSetClientKeyValue)( int clientIndex, char *infobuffer, char *key, char *value ); - int (*pfnIsMapValid)( char *filename ); - void (*pfnStaticDecal)( const float *origin, int decalIndex, int entityIndex, int modelIndex ); - 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? - cvar_t *(*pfnCVarGetPointer)( const char *szVarName ); - unsigned int (*pfnGetPlayerWONId)( edict_t *e ); // 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 - - // YWB 8/1/99 TFF Physics additions - void (*pfnInfo_RemoveKey)( char *s, const char *key ); - 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 ); - 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 ); - - void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); - void (*pfnDeltaUnsetField)( struct delta_s *pFields, const char *fieldname ); - 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 ); - void (*pfnDeltaSetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); - void (*pfnDeltaUnsetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); - void (*pfnSetGroupMask)( int mask, int op ); - int (*pfnCreateInstancedBaseline)( int classname, struct entity_state_s *baseline ); - void (*pfnCvar_DirectSet)( struct cvar_s *var, char *value ); - - // Forces the client and server to be running with the same version of the specified file - // ( e.g., a player model ). - // Calling this has no effect in single player - void (*pfnForceUnmodified)( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); - - void (*pfnGetPlayerStats)( const edict_t *pClient, int *ping, int *packet_loss ); - - 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). - qboolean (*pfnVoice_GetClientListening)(int iReceiver, int iSender); - qboolean (*pfnVoice_SetClientListening)(int iReceiver, int iSender, qboolean bListen); - - const char *(*pfnGetPlayerAuthId) ( edict_t *e ); - - void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); - void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked ); - int (*pfnGetFileSize)( char *filename ); - unsigned int (*pfnGetApproxWavePlayLen)( const char *filepath ); - int (*pfnIsCareerMatch)( void ); - int (*pfnGetLocalizedStringLength)( const char *label ); - void (*pfnRegisterTutorMessageShown)( int mid ); - 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 (*CheckParm)( char *parm, char **ppnext ); -} enginefuncs_t; -// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 - -// Passed to pfnKeyValue -typedef struct KeyValueData_s -{ - char *szClassName; // in: entity classname - char *szKeyName; // in: name of key - char *szValue; // in: value of key - long fHandled; // out: DLL sets to true if key-value pair was understood -} KeyValueData; - - -typedef struct -{ - char mapName[32]; - char landmarkName[32]; - edict_t *pentLandmark; - vec3_t vecLandmarkOrigin; -} LEVELLIST; - -typedef struct -{ - int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) - edict_t *pent; // Pointer to the in-game entity - - int location; // Offset from the base data of this entity - int size; // Byte size of this entity's data - int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of - string_t classname; // entity class name - -} ENTITYTABLE; - -#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of ENTITYTABLE->flags - -#define FENTTABLE_PLAYER 0x80000000 -#define FENTTABLE_REMOVED 0x40000000 -#define FENTTABLE_MOVEABLE 0x20000000 -#define FENTTABLE_GLOBAL 0x10000000 - -typedef struct saverestore_s -{ - char *pBaseData; // Start of all entity save data - char *pCurrentData; // Current buffer pointer for sequential access - int size; // Current data size - int bufferSize; // Total space for data - int tokenSize; // Size of the linear list of tokens - int tokenCount; // Number of elements in the pTokens table - char **pTokens; // Hash table of entity strings (sparse) - int currentIndex; // Holds a global entity table ID - int tableCount; // Number of elements in the entity table - int connectionCount; // Number of elements in the levelList[] - ENTITYTABLE *pTable; // Array of ENTITYTABLE elements (1 for each entity) - LEVELLIST levelList[MAX_LEVEL_CONNECTIONS]; // List of connections from this level - - // smooth transition - int fUseLandmark; - char szLandmarkName[20]; // landmark we'll spawn near in next level - vec3_t vecLandmarkOffset; // for landmark transitions - float time; - char szCurrentMapName[32]; // To check global entities -} SAVERESTOREDATA; - -typedef enum _fieldtypes -{ - FIELD_FLOAT = 0, // Any floating point value - FIELD_STRING, // A string ID (return from ALLOC_STRING) - FIELD_ENTITY, // An entity offset (EOFFSET) - FIELD_CLASSPTR, // CBaseEntity * - FIELD_EHANDLE, // Entity handle - FIELD_EVARS, // EVARS * - FIELD_EDICT, // edict_t *, or edict_t * (same thing) - FIELD_VECTOR, // Any vector - FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) - FIELD_POINTER, // Arbitrary data pointer... to be removed, use an array of FIELD_CHARACTER - FIELD_INTEGER, // Any integer or enum - FIELD_FUNCTION, // A class function pointer (Think, Use, etc) - FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression - FIELD_SHORT, // 2 byte integer - FIELD_CHARACTER, // a byte - FIELD_TIME, // a floating point time (these are fixed up automatically too!) - FIELD_MODELNAME, // Engine string that is a model name (needs precache) - FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) - - FIELD_TYPECOUNT, // MUST BE LAST -} FIELDTYPE; - -#ifndef offsetof -#define offsetof(s,m) (size_t)&(((s *)0)->m) -#endif - -#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags } -#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0) -#define DEFINE_ARRAY(type,name,fieldtype,count) _FIELD(type, name, fieldtype, count, 0) -#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, 0 ) -#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, FTYPEDESC_GLOBAL ) -#define DEFINE_GLOBAL_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, FTYPEDESC_GLOBAL ) - -#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore -#define FTYPEDESC_SAVE 0x0002 // This field is saved to disk -#define FTYPEDESC_KEY 0x0004 // This field can be requested and written to by string name at load time -#define FTYPEDESC_FUNCTIONTABLE 0x0008 // This is a table entry for a member function pointer - -typedef struct -{ - FIELDTYPE fieldType; - char *fieldName; - int fieldOffset; - short fieldSize; - short flags; -} TYPEDESCRIPTION; - -#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -typedef struct -{ - // Initialize/shutdown the game (one-time call after loading of game .dll ) - void (*pfnGameInit)( void ); - int (*pfnSpawn)( edict_t *pent ); - void (*pfnThink)( edict_t *pent ); - void (*pfnUse)( edict_t *pentUsed, edict_t *pentOther ); - void (*pfnTouch)( edict_t *pentTouched, edict_t *pentOther ); - void (*pfnBlocked)( edict_t *pentBlocked, edict_t *pentOther ); - void (*pfnKeyValue)( edict_t *pentKeyvalue, KeyValueData *pkvd ); - void (*pfnSave)( edict_t *pent, SAVERESTOREDATA *pSaveData ); - int (*pfnRestore)( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); - void (*pfnSetAbsBox)( edict_t *pent ); - - void (*pfnSaveWriteFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); - void (*pfnSaveReadFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); - void (*pfnSaveGlobalState)( SAVERESTOREDATA * ); - void (*pfnRestoreGlobalState)( SAVERESTOREDATA * ); - void (*pfnResetGlobalState)( void ); - - qboolean (*pfnClientConnect)( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); - - void (*pfnClientDisconnect)( edict_t *pEntity ); - void (*pfnClientKill)( edict_t *pEntity ); - void (*pfnClientPutInServer)( edict_t *pEntity ); - void (*pfnClientCommand)( edict_t *pEntity ); - void (*pfnClientUserInfoChanged)( edict_t *pEntity, char *infobuffer ); - void (*pfnServerActivate)( edict_t *pEdictList, int edictCount, int clientMax ); - void (*pfnServerDeactivate)( void ); - void (*pfnPlayerPreThink)( edict_t *pEntity ); - void (*pfnPlayerPostThink)( edict_t *pEntity ); - - void (*pfnStartFrame)( void ); - void (*pfnParmsNewLevel)( void ); - void (*pfnParmsChangeLevel)( void ); - - // Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life - const char *(*pfnGetGameDescription)( void ); - - // Notify dll about a player customization. - void (*pfnPlayerCustomization)( edict_t *pEntity, customization_t *pCustom ); - - // Spectator funcs - void (*pfnSpectatorConnect)( edict_t *pEntity ); - void (*pfnSpectatorDisconnect)( edict_t *pEntity ); - void (*pfnSpectatorThink)( edict_t *pEntity ); - - // Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. - void (*pfnSys_Error)( const char *error_string ); - - void (*pfnPM_Move)( struct playermove_s *ppmove, qboolean server ); - void (*pfnPM_Init)( struct playermove_s *ppmove ); - 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 ); - void (*pfnCreateBaseline)( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); - void (*pfnRegisterEncoders)( void ); - int (*pfnGetWeaponData)( struct edict_s *player, struct weapon_data_s *info ); - - void (*pfnCmdStart)( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); - void (*pfnCmdEnd)( const edict_t *player ); - - // 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 ); - - // Enumerates player hulls. Returns 0 if the hull number doesn't exist, 1 otherwise - int (*pfnGetHullBounds) ( int hullnumber, float *mins, float *maxs ); - - // Create baselines for certain "unplaced" items. - void (*pfnCreateInstancedBaselines) ( void ); - - // One of the pfnForceUnmodified 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 (*pfnInconsistentFile)( const struct edict_s *player, const char *filename, char *disconnect_message ); - - // 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. - int (*pfnAllowLagCompensation)( void ); -} DLL_FUNCTIONS; - -extern DLL_FUNCTIONS gEntityInterface; - -// Current version. -#define NEW_DLL_FUNCTIONS_VERSION 1 - -typedef struct -{ - // Called right before the object's memory is freed. - // Calls its destructor. - void (*pfnOnFreeEntPrivateData)( edict_t *pEnt ); - void (*pfnGameShutdown)(void); - int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther ); - 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 ); - -// 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 ); - +/*** +* +* 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 EIFACE_H +#define EIFACE_H + +#ifdef HLDEMO_BUILD +#define INTERFACE_VERSION 001 +#else // !HLDEMO_BUILD, i.e., regular version of HL +#define INTERFACE_VERSION 140 +#endif // !HLDEMO_BUILD + +#include +#include "custom.h" +#include "cvardef.h" +// +// Defines entity interface between engine and DLLs. +// This header file included by engine files and DLL files. +// +// Before including this header, DLLs must: +// include progdefs.h +// This is conveniently done for them in extdll.h +// + +typedef enum +{ + 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 +{ + print_console, + print_center, + print_chat, +} PRINT_TYPE; + +// For integrity checking of content on clients +typedef enum +{ + 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_TYPE; + +// Returned by TraceLine +typedef struct +{ + int fAllSolid; // if true, plane is not valid + int fStartSolid; // if true, the initial point was in a solid area + int fInOpen; + int fInWater; + float flFraction; // time completed, 1.0 = didn't hit anything + vec3_t vecEndPos; // final position + float flPlaneDist; + 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 +{ + int fPlaying;// is sound playing right now? + int fWasPlaying;// if not, CD is paused if WasPlaying is true. + int fInitialized; + int fEnabled; + int fPlayLooping; + float cdvolume; + int fCDRom; + int fPlayTrack; +} CDStatus; + +typedef unsigned long CRC32_t; + +// Engine hands this to DLLs for functionality callbacks +typedef struct enginefuncs_s +{ + int (*pfnPrecacheModel)( char* s ); + int (*pfnPrecacheSound)( char* s ); + void (*pfnSetModel)( edict_t *e, const char *m ); + int (*pfnModelIndex)( const char *m ); + int (*pfnModelFrames)( int modelIndex ); + void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); + void (*pfnChangeLevel)( char* s1, char* s2 ); + void (*pfnGetSpawnParms)( edict_t *ent ); + void (*pfnSaveSpawnParms)( edict_t *ent ); + float (*pfnVecToYaw)( const float *rgflVector ); + void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut ); + void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); + void (*pfnChangeYaw)( edict_t* ent ); + void (*pfnChangePitch)( edict_t* ent ); + edict_t* (*pfnFindEntityByString)( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); + int (*pfnGetEntityIllum)( edict_t* pEnt ); + edict_t* (*pfnFindEntityInSphere)( edict_t *pEdictStartSearchAfter, const float *org, float rad ); + edict_t* (*pfnFindClientInPVS)( edict_t *pEdict ); + edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer ); + void (*pfnMakeVectors)( const float *rgflVector ); + void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up ); + edict_t* (*pfnCreateEntity)( void ); + void (*pfnRemoveEntity)( edict_t* e ); + edict_t* (*pfnCreateNamedEntity)( int className ); + void (*pfnMakeStatic)( edict_t *ent ); + int (*pfnEntIsOnFloor)( edict_t *e ); + int (*pfnDropToFloor)( edict_t* e ); + int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode ); + void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin ); + void (*pfnEmitSound)( edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch ); + void (*pfnEmitAmbientSound)( edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch ); + void (*pfnTraceLine)( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceToss)( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); + int (*pfnTraceMonsterHull)( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); + 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)( char* str ); + void (*pfnServerExecute)( void ); + void (*pfnClientCommand)( edict_t* pEdict, char* szFmt, ... ); + void (*pfnParticleEffect)( const float *org, const float *dir, float color, float count ); + 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 ); + void (*pfnMessageEnd)( void ); + void (*pfnWriteByte)( int iValue ); + void (*pfnWriteChar)( int iValue ); + void (*pfnWriteShort)( int iValue ); + void (*pfnWriteLong)( int iValue ); + void (*pfnWriteAngle)( float flValue ); + void (*pfnWriteCoord)( float flValue ); + void (*pfnWriteString)( const char *sz ); + void (*pfnWriteEntity)( int iValue ); + void (*pfnCVarRegister)( cvar_t *pCvar ); + float (*pfnCVarGetFloat)( const char *szVarName ); + const char* (*pfnCVarGetString)( const char *szVarName ); + void (*pfnCVarSetFloat)( const char *szVarName, float flValue ); + void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); + void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); + void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); + void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); + void* (*pfnPvEntPrivateData)( edict_t *pEdict ); + void (*pfnFreeEntPrivateData)( edict_t *pEdict ); + const char *(*pfnSzFromIndex)( int iString ); + int (*pfnAllocString)( const char *szValue ); + struct entvars_s *(*pfnGetVarsOfEnt)( edict_t *pEdict ); + edict_t* (*pfnPEntityOfEntOffset)( int iEntOffset ); + int (*pfnEntOffsetOfPEntity)( const edict_t *pEdict ); + int (*pfnIndexOfEdict)( const edict_t *pEdict ); + edict_t* (*pfnPEntityOfEntIndex)( int iEntIndex ); + edict_t* (*pfnFindEntityByVars)( struct entvars_s* pvars ); + void* (*pfnGetModelPtr)( edict_t* pEdict ); + int (*pfnRegUserMsg)( const char *pszName, int iSize ); + void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); + void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); + unsigned long (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( unsigned long function ); + void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients + void (*pfnServerPrint)( const char *szMsg ); + const char *(*pfnCmd_Args)( void ); // these 3 added + const char *(*pfnCmd_Argv)( int argc ); // so game DLL can easily + int (*pfnCmd_Argc)( void ); // access client 'cmd' strings + void (*pfnGetAttachment)( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); + void (*pfnCRC32_Init)( CRC32_t *pulCRC ); + void (*pfnCRC32_ProcessBuffer)( CRC32_t *pulCRC, void *p, int len ); + void (*pfnCRC32_ProcessByte)( CRC32_t *pulCRC, unsigned char ch ); + CRC32_t (*pfnCRC32_Final)( CRC32_t pulCRC ); + long (*pfnRandomLong)( long lLow, long lHigh ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + 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)( 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 ); + 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 ); + char* (*pfnGetInfoKeyBuffer)( edict_t *e ); // passing in NULL gets the serverinfo + char* (*pfnInfoKeyValue)( char *infobuffer, char *key ); + void (*pfnSetKeyValue)( char *infobuffer, char *key, char *value ); + void (*pfnSetClientKeyValue)( int clientIndex, char *infobuffer, char *key, char *value ); + int (*pfnIsMapValid)( char *filename ); + void (*pfnStaticDecal)( const float *origin, int decalIndex, int entityIndex, int modelIndex ); + 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? + cvar_t *(*pfnCVarGetPointer)( const char *szVarName ); + unsigned int (*pfnGetPlayerWONId)( edict_t *e ); // 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 + + // YWB 8/1/99 TFF Physics additions + void (*pfnInfo_RemoveKey)( char *s, const char *key ); + 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 ); + 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 ); + + void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); + void (*pfnDeltaUnsetField)( struct delta_s *pFields, const char *fieldname ); + 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 ); + void (*pfnDeltaSetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); + void (*pfnDeltaUnsetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); + void (*pfnSetGroupMask)( int mask, int op ); + int (*pfnCreateInstancedBaseline)( int classname, struct entity_state_s *baseline ); + void (*pfnCvar_DirectSet)( struct cvar_s *var, char *value ); + + // Forces the client and server to be running with the same version of the specified file + // ( e.g., a player model ). + // Calling this has no effect in single player + void (*pfnForceUnmodified)( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); + + void (*pfnGetPlayerStats)( const edict_t *pClient, int *ping, int *packet_loss ); + + 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). + qboolean (*pfnVoice_GetClientListening)(int iReceiver, int iSender); + qboolean (*pfnVoice_SetClientListening)(int iReceiver, int iSender, qboolean bListen); + + const char *(*pfnGetPlayerAuthId) ( edict_t *e ); + + void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); + void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked ); + int (*pfnGetFileSize)( char *filename ); + unsigned int (*pfnGetApproxWavePlayLen)( const char *filepath ); + int (*pfnIsCareerMatch)( void ); + int (*pfnGetLocalizedStringLength)( const char *label ); + void (*pfnRegisterTutorMessageShown)( int mid ); + 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 (*CheckParm)( char *parm, char **ppnext ); +} enginefuncs_t; +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 + +// Passed to pfnKeyValue +typedef struct KeyValueData_s +{ + char *szClassName; // in: entity classname + char *szKeyName; // in: name of key + char *szValue; // in: value of key + long fHandled; // out: DLL sets to true if key-value pair was understood +} KeyValueData; + + +typedef struct +{ + char mapName[32]; + char landmarkName[32]; + edict_t *pentLandmark; + vec3_t vecLandmarkOrigin; +} LEVELLIST; + +typedef struct +{ + int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) + edict_t *pent; // Pointer to the in-game entity + + int location; // Offset from the base data of this entity + int size; // Byte size of this entity's data + int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name + +} ENTITYTABLE; + +#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of ENTITYTABLE->flags + +#define FENTTABLE_PLAYER 0x80000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_GLOBAL 0x10000000 + +typedef struct saverestore_s +{ + char *pBaseData; // Start of all entity save data + char *pCurrentData; // Current buffer pointer for sequential access + int size; // Current data size + int bufferSize; // Total space for data + int tokenSize; // Size of the linear list of tokens + int tokenCount; // Number of elements in the pTokens table + char **pTokens; // Hash table of entity strings (sparse) + int currentIndex; // Holds a global entity table ID + int tableCount; // Number of elements in the entity table + int connectionCount; // Number of elements in the levelList[] + ENTITYTABLE *pTable; // Array of ENTITYTABLE elements (1 for each entity) + LEVELLIST levelList[MAX_LEVEL_CONNECTIONS]; // List of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[20]; // landmark we'll spawn near in next level + vec3_t vecLandmarkOffset; // for landmark transitions + float time; + char szCurrentMapName[32]; // To check global entities +} SAVERESTOREDATA; + +typedef enum _fieldtypes +{ + FIELD_FLOAT = 0, // Any floating point value + FIELD_STRING, // A string ID (return from ALLOC_STRING) + FIELD_ENTITY, // An entity offset (EOFFSET) + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // Entity handle + FIELD_EVARS, // EVARS * + FIELD_EDICT, // edict_t *, or edict_t * (same thing) + FIELD_VECTOR, // Any vector + FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) + FIELD_POINTER, // Arbitrary data pointer... to be removed, use an array of FIELD_CHARACTER + FIELD_INTEGER, // Any integer or enum + FIELD_FUNCTION, // A class function pointer (Think, Use, etc) + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_MODELNAME, // Engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) + + FIELD_TYPECOUNT, // MUST BE LAST +} FIELDTYPE; + +#ifndef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags } +#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0) +#define DEFINE_ARRAY(type,name,fieldtype,count) _FIELD(type, name, fieldtype, count, 0) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, FTYPEDESC_GLOBAL ) +#define DEFINE_GLOBAL_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, FTYPEDESC_GLOBAL ) + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore +#define FTYPEDESC_SAVE 0x0002 // This field is saved to disk +#define FTYPEDESC_KEY 0x0004 // This field can be requested and written to by string name at load time +#define FTYPEDESC_FUNCTIONTABLE 0x0008 // This is a table entry for a member function pointer + +typedef struct +{ + FIELDTYPE fieldType; + char *fieldName; + int fieldOffset; + short fieldSize; + short flags; +} TYPEDESCRIPTION; + +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +typedef struct +{ + // Initialize/shutdown the game (one-time call after loading of game .dll ) + void (*pfnGameInit)( void ); + int (*pfnSpawn)( edict_t *pent ); + void (*pfnThink)( edict_t *pent ); + void (*pfnUse)( edict_t *pentUsed, edict_t *pentOther ); + void (*pfnTouch)( edict_t *pentTouched, edict_t *pentOther ); + void (*pfnBlocked)( edict_t *pentBlocked, edict_t *pentOther ); + void (*pfnKeyValue)( edict_t *pentKeyvalue, KeyValueData *pkvd ); + void (*pfnSave)( edict_t *pent, SAVERESTOREDATA *pSaveData ); + int (*pfnRestore)( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); + void (*pfnSetAbsBox)( edict_t *pent ); + + void (*pfnSaveWriteFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveReadFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveGlobalState)( SAVERESTOREDATA * ); + void (*pfnRestoreGlobalState)( SAVERESTOREDATA * ); + void (*pfnResetGlobalState)( void ); + + qboolean (*pfnClientConnect)( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ); + + void (*pfnClientDisconnect)( edict_t *pEntity ); + void (*pfnClientKill)( edict_t *pEntity ); + void (*pfnClientPutInServer)( edict_t *pEntity ); + void (*pfnClientCommand)( edict_t *pEntity ); + void (*pfnClientUserInfoChanged)( edict_t *pEntity, char *infobuffer ); + void (*pfnServerActivate)( edict_t *pEdictList, int edictCount, int clientMax ); + void (*pfnServerDeactivate)( void ); + void (*pfnPlayerPreThink)( edict_t *pEntity ); + void (*pfnPlayerPostThink)( edict_t *pEntity ); + + void (*pfnStartFrame)( void ); + void (*pfnParmsNewLevel)( void ); + void (*pfnParmsChangeLevel)( void ); + + // Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life + const char *(*pfnGetGameDescription)( void ); + + // Notify dll about a player customization. + void (*pfnPlayerCustomization)( edict_t *pEntity, customization_t *pCustom ); + + // Spectator funcs + void (*pfnSpectatorConnect)( edict_t *pEntity ); + void (*pfnSpectatorDisconnect)( edict_t *pEntity ); + void (*pfnSpectatorThink)( edict_t *pEntity ); + + // Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. + void (*pfnSys_Error)( const char *error_string ); + + void (*pfnPM_Move)( struct playermove_s *ppmove, qboolean server ); + void (*pfnPM_Init)( struct playermove_s *ppmove ); + 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 ); + void (*pfnCreateBaseline)( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); + void (*pfnRegisterEncoders)( void ); + int (*pfnGetWeaponData)( struct edict_s *player, struct weapon_data_s *info ); + + void (*pfnCmdStart)( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); + void (*pfnCmdEnd)( const edict_t *player ); + + // 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 ); + + // Enumerates player hulls. Returns 0 if the hull number doesn't exist, 1 otherwise + int (*pfnGetHullBounds) ( int hullnumber, float *mins, float *maxs ); + + // Create baselines for certain "unplaced" items. + void (*pfnCreateInstancedBaselines) ( void ); + + // One of the pfnForceUnmodified 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 (*pfnInconsistentFile)( const struct edict_s *player, const char *filename, char *disconnect_message ); + + // 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. + int (*pfnAllowLagCompensation)( void ); +} DLL_FUNCTIONS; + +extern DLL_FUNCTIONS gEntityInterface; + +// Current version. +#define NEW_DLL_FUNCTIONS_VERSION 1 + +typedef struct +{ + // Called right before the object's memory is freed. + // Calls its destructor. + void (*pfnOnFreeEntPrivateData)( edict_t *pEnt ); + void (*pfnGameShutdown)(void); + int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther ); + 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 ); + +// 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 diff --git a/engine/keydefs.h b/engine/keydefs.h index 2a1312f0..ea22139f 100644 --- a/engine/keydefs.h +++ b/engine/keydefs.h @@ -1,133 +1,133 @@ -/*** -* -* 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 KEYDEFS_H -#define KEYDEFS_H - -// -// 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 -#define K_KP_NUMLOCK 176 - -// -// 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 - +/*** +* +* 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 KEYDEFS_H +#define KEYDEFS_H + +// +// 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 +#define K_KP_NUMLOCK 176 + +// +// 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 \ No newline at end of file diff --git a/engine/menu_int.h b/engine/menu_int.h index f380d6ff..53b0725a 100644 --- a/engine/menu_int.h +++ b/engine/menu_int.h @@ -1,188 +1,188 @@ -/* -menu_int.h - interface between engine and menu -Copyright (C) 2010 Uncle Mike - -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. -*/ - -#ifndef MENU_INT_H -#define MENU_INT_H - -#include "cvardef.h" -#include "gameinfo.h" -#include "wrect.h" - -typedef int HIMAGE; // handle to a graphic - -// flags for PIC_Load -#define PIC_NEAREST (1<<0) // disable texfilter -#define PIC_KEEP_RGBDATA (1<<1) // some images keep source -#define PIC_NOFLIP_TGA (1<<2) // Steam background completely ignore tga attribute 0x20 -#define PIC_KEEP_8BIT (1<<3) // keep original 8-bit image (if present) - -typedef struct ui_globalvars_s -{ - float time; // unclamped host.realtime - float frametime; - - int scrWidth; // actual values - int scrHeight; - - int maxClients; - int developer; - int demoplayback; - int demorecording; - char demoname[64]; // name of currently playing demo - char maptitle[64]; // title of active map -} ui_globalvars_t; - -typedef struct ui_enginefuncs_s -{ - // image handlers - HIMAGE (*pfnPIC_Load)( const char *szPicName, const byte *ucRawImage, long ulRawImageSize, long flags ); - void (*pfnPIC_Free)( const char *szPicName ); - int (*pfnPIC_Width)( HIMAGE hPic ); - int (*pfnPIC_Height)( HIMAGE hPic ); - void (*pfnPIC_Set)( HIMAGE hPic, int r, int g, int b, int a ); - void (*pfnPIC_Draw)( int x, int y, int width, int height, const wrect_t *prc ); - void (*pfnPIC_DrawHoles)( int x, int y, int width, int height, const wrect_t *prc ); - void (*pfnPIC_DrawTrans)( int x, int y, int width, int height, const wrect_t *prc ); - void (*pfnPIC_DrawAdditive)( int x, int y, int width, int height, const wrect_t *prc ); - void (*pfnPIC_EnableScissor)( int x, int y, int width, int height ); - void (*pfnPIC_DisableScissor)( void ); - - // screen handlers - void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); - - // cvar handlers - cvar_t* (*pfnRegisterVariable)( const char *szName, const char *szValue, int flags ); - float (*pfnGetCvarFloat)( const char *szName ); - char* (*pfnGetCvarString)( const char *szName ); - void (*pfnCvarSetString)( const char *szName, const char *szValue ); - void (*pfnCvarSetValue)( const char *szName, float flValue ); - - // command handlers - int (*pfnAddCommand)( const char *cmd_name, void (*function)(void) ); - void (*pfnClientCmd)( int execute_now, const char *szCmdString ); - void (*pfnDelCommand)( const char *cmd_name ); - int (*pfnCmdArgc)( void ); - char* (*pfnCmdArgv)( int argc ); - char* (*pfnCmd_Args)( void ); - - // debug messages (in-menu shows only notify) - void (*Con_Printf)( char *fmt, ... ); - void (*Con_DPrintf)( char *fmt, ... ); - void (*Con_NPrintf)( int pos, char *fmt, ... ); - void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); - - // sound handlers - void (*pfnPlayLocalSound)( const char *szSound ); - - // cinematic handlers - void (*pfnDrawLogo)( const char *filename, float x, float y, float width, float height ); - int (*pfnGetLogoWidth)( void ); - int (*pfnGetLogoHeight)( void ); - float (*pfnGetLogoLength)( void ); // cinematic duration in seconds - - // text message system - void (*pfnDrawCharacter)( int x, int y, int width, int height, int ch, int ulRGBA, HIMAGE hFont ); - int (*pfnDrawConsoleString)( int x, int y, const char *string ); - void (*pfnDrawSetTextColor)( int r, int g, int b, int alpha ); - void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); - void (*pfnSetConsoleDefaultColor)( int r, int g, int b ); // color must came from colors.lst - - // custom rendering (for playermodel preview) - struct cl_entity_s* (*pfnGetPlayerModel)( void ); // for drawing playermodel previews - void (*pfnSetModel)( struct cl_entity_s *ed, const char *path ); - void (*pfnClearScene)( void ); - void (*pfnRenderScene)( const struct ref_params_s *fd ); - int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); - - // misc handlers - void (*pfnHostError)( const char *szFmt, ... ); - int (*pfnFileExists)( const char *filename, int gamedironly ); - void (*pfnGetGameDir)( char *szGetGameDir ); - - // gameinfo handlers - int (*pfnCreateMapsList)( int fRefresh ); - int (*pfnClientInGame)( void ); - void (*pfnClientJoin)( const struct netadr_s adr ); - - // parse txt files - byte* (*COM_LoadFile)( const char *filename, int *pLength ); - char* (*COM_ParseFile)( char *data, char *token ); - void (*COM_FreeFile)( void *buffer ); - - // keyfuncs - void (*pfnKeyClearStates)( void ); // call when menu open or close - void (*pfnSetKeyDest)( int dest ); - const char *(*pfnKeynumToString)( int keynum ); - const char *(*pfnKeyGetBinding)( int keynum ); - void (*pfnKeySetBinding)( int keynum, const char *binding ); - int (*pfnKeyIsDown)( int keynum ); - int (*pfnKeyGetOverstrikeMode)( void ); - void (*pfnKeySetOverstrikeMode)( int fActive ); - void *(*pfnKeyGetState)( const char *name ); // for mlook, klook etc - - // engine memory manager - void* (*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); - void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); - - // collect info from engine - int (*pfnGetGameInfo)( GAMEINFO *pgameinfo ); - GAMEINFO **(*pfnGetGamesList)( int *numGames ); // collect info about all mods - char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); // find in files - int (*pfnGetSaveComment)( const char *savename, char *comment ); - int (*pfnGetDemoComment)( const char *demoname, char *comment ); - int (*pfnCheckGameDll)( void ); // returns false if hl.dll is missed or invalid - char *(*pfnGetClipboardData)( void ); - - // engine launcher - void (*pfnShellExecute)( const char *name, const char *args, int closeEngine ); - void (*pfnWriteServerConfig)( const char *name ); - void (*pfnChangeInstance)( const char *newInstance, const char *szFinalMessage ); - void (*pfnPlayBackgroundTrack)( const char *introName, const char *loopName ); - void (*pfnHostEndGame)( const char *szFinalMessage ); - - // menu interface is freezed at version 0.75 - // new functions starts here - float (*pfnRandomFloat)( float flLow, float flHigh ); - long (*pfnRandomLong)( long lLow, long lHigh ); - - void (*pfnSetCursor)( void *hCursor ); // change cursor - int (*pfnIsMapValid)( char *filename ); - void (*pfnProcessImage)( int texnum, float gamma, int topColor, int bottomColor ); - int (*pfnCompareFileTime)( char *filename1, char *filename2, int *iCompare ); -} ui_enginefuncs_t; - -typedef struct -{ - int (*pfnVidInit)( void ); - void (*pfnInit)( void ); - void (*pfnShutdown)( void ); - void (*pfnRedraw)( float flTime ); - void (*pfnKeyEvent)( int key, int down ); - void (*pfnMouseMove)( int x, int y ); - void (*pfnSetActiveMenu)( int active ); - void (*pfnAddServerToList)( struct netadr_s adr, const char *info ); - void (*pfnGetCursorPos)( int *pos_x, int *pos_y ); - void (*pfnSetCursorPos)( int pos_x, int pos_y ); - void (*pfnShowCursor)( int show ); - void (*pfnCharEvent)( int key ); - int (*pfnMouseInRect)( void ); // mouse entering\leave game window - int (*pfnIsVisible)( void ); - int (*pfnCreditsActive)( void ); // unused - void (*pfnFinalCredits)( void ); // show credits + game end -} UI_FUNCTIONS; - -typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); - +/* +menu_int.h - interface between engine and menu +Copyright (C) 2010 Uncle Mike + +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. +*/ + +#ifndef MENU_INT_H +#define MENU_INT_H + +#include "cvardef.h" +#include "gameinfo.h" +#include "wrect.h" + +typedef int HIMAGE; // handle to a graphic + +// flags for PIC_Load +#define PIC_NEAREST (1<<0) // disable texfilter +#define PIC_KEEP_RGBDATA (1<<1) // some images keep source +#define PIC_NOFLIP_TGA (1<<2) // Steam background completely ignore tga attribute 0x20 +#define PIC_KEEP_8BIT (1<<3) // keep original 8-bit image (if present) + +typedef struct ui_globalvars_s +{ + float time; // unclamped host.realtime + float frametime; + + int scrWidth; // actual values + int scrHeight; + + int maxClients; + int developer; + int demoplayback; + int demorecording; + char demoname[64]; // name of currently playing demo + char maptitle[64]; // title of active map +} ui_globalvars_t; + +typedef struct ui_enginefuncs_s +{ + // image handlers + HIMAGE (*pfnPIC_Load)( const char *szPicName, const byte *ucRawImage, long ulRawImageSize, long flags ); + void (*pfnPIC_Free)( const char *szPicName ); + int (*pfnPIC_Width)( HIMAGE hPic ); + int (*pfnPIC_Height)( HIMAGE hPic ); + void (*pfnPIC_Set)( HIMAGE hPic, int r, int g, int b, int a ); + void (*pfnPIC_Draw)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawHoles)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawTrans)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_DrawAdditive)( int x, int y, int width, int height, const wrect_t *prc ); + void (*pfnPIC_EnableScissor)( int x, int y, int width, int height ); + void (*pfnPIC_DisableScissor)( void ); + + // screen handlers + void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); + + // cvar handlers + cvar_t* (*pfnRegisterVariable)( const char *szName, const char *szValue, int flags ); + float (*pfnGetCvarFloat)( const char *szName ); + char* (*pfnGetCvarString)( const char *szName ); + void (*pfnCvarSetString)( const char *szName, const char *szValue ); + void (*pfnCvarSetValue)( const char *szName, float flValue ); + + // command handlers + int (*pfnAddCommand)( const char *cmd_name, void (*function)(void) ); + void (*pfnClientCmd)( int execute_now, const char *szCmdString ); + void (*pfnDelCommand)( const char *cmd_name ); + int (*pfnCmdArgc)( void ); + char* (*pfnCmdArgv)( int argc ); + char* (*pfnCmd_Args)( void ); + + // debug messages (in-menu shows only notify) + void (*Con_Printf)( char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_NPrintf)( int pos, char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + + // sound handlers + void (*pfnPlayLocalSound)( const char *szSound ); + + // cinematic handlers + void (*pfnDrawLogo)( const char *filename, float x, float y, float width, float height ); + int (*pfnGetLogoWidth)( void ); + int (*pfnGetLogoHeight)( void ); + float (*pfnGetLogoLength)( void ); // cinematic duration in seconds + + // text message system + void (*pfnDrawCharacter)( int x, int y, int width, int height, int ch, int ulRGBA, HIMAGE hFont ); + int (*pfnDrawConsoleString)( int x, int y, const char *string ); + void (*pfnDrawSetTextColor)( int r, int g, int b, int alpha ); + void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); + void (*pfnSetConsoleDefaultColor)( int r, int g, int b ); // color must came from colors.lst + + // custom rendering (for playermodel preview) + struct cl_entity_s* (*pfnGetPlayerModel)( void ); // for drawing playermodel previews + void (*pfnSetModel)( struct cl_entity_s *ed, const char *path ); + void (*pfnClearScene)( void ); + void (*pfnRenderScene)( const struct ref_params_s *fd ); + int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); + + // misc handlers + void (*pfnHostError)( const char *szFmt, ... ); + int (*pfnFileExists)( const char *filename, int gamedironly ); + void (*pfnGetGameDir)( char *szGetGameDir ); + + // gameinfo handlers + int (*pfnCreateMapsList)( int fRefresh ); + int (*pfnClientInGame)( void ); + void (*pfnClientJoin)( const struct netadr_s adr ); + + // parse txt files + byte* (*COM_LoadFile)( const char *filename, int *pLength ); + char* (*COM_ParseFile)( char *data, char *token ); + void (*COM_FreeFile)( void *buffer ); + + // keyfuncs + void (*pfnKeyClearStates)( void ); // call when menu open or close + void (*pfnSetKeyDest)( int dest ); + const char *(*pfnKeynumToString)( int keynum ); + const char *(*pfnKeyGetBinding)( int keynum ); + void (*pfnKeySetBinding)( int keynum, const char *binding ); + int (*pfnKeyIsDown)( int keynum ); + int (*pfnKeyGetOverstrikeMode)( void ); + void (*pfnKeySetOverstrikeMode)( int fActive ); + void *(*pfnKeyGetState)( const char *name ); // for mlook, klook etc + + // engine memory manager + void* (*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); + + // collect info from engine + int (*pfnGetGameInfo)( GAMEINFO *pgameinfo ); + GAMEINFO **(*pfnGetGamesList)( int *numGames ); // collect info about all mods + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); // find in files + int (*pfnGetSaveComment)( const char *savename, char *comment ); + int (*pfnGetDemoComment)( const char *demoname, char *comment ); + int (*pfnCheckGameDll)( void ); // returns false if hl.dll is missed or invalid + char *(*pfnGetClipboardData)( void ); + + // engine launcher + void (*pfnShellExecute)( const char *name, const char *args, int closeEngine ); + void (*pfnWriteServerConfig)( const char *name ); + void (*pfnChangeInstance)( const char *newInstance, const char *szFinalMessage ); + void (*pfnPlayBackgroundTrack)( const char *introName, const char *loopName ); + void (*pfnHostEndGame)( const char *szFinalMessage ); + + // menu interface is freezed at version 0.75 + // new functions starts here + float (*pfnRandomFloat)( float flLow, float flHigh ); + long (*pfnRandomLong)( long lLow, long lHigh ); + + void (*pfnSetCursor)( void *hCursor ); // change cursor + int (*pfnIsMapValid)( char *filename ); + void (*pfnProcessImage)( int texnum, float gamma, int topColor, int bottomColor ); + int (*pfnCompareFileTime)( char *filename1, char *filename2, int *iCompare ); +} ui_enginefuncs_t; + +typedef struct +{ + int (*pfnVidInit)( void ); + void (*pfnInit)( void ); + void (*pfnShutdown)( void ); + void (*pfnRedraw)( float flTime ); + void (*pfnKeyEvent)( int key, int down ); + void (*pfnMouseMove)( int x, int y ); + void (*pfnSetActiveMenu)( int active ); + void (*pfnAddServerToList)( struct netadr_s adr, const char *info ); + void (*pfnGetCursorPos)( int *pos_x, int *pos_y ); + void (*pfnSetCursorPos)( int pos_x, int pos_y ); + void (*pfnShowCursor)( int show ); + void (*pfnCharEvent)( int key ); + int (*pfnMouseInRect)( void ); // mouse entering\leave game window + int (*pfnIsVisible)( void ); + int (*pfnCreditsActive)( void ); // unused + void (*pfnFinalCredits)( void ); // show credits + game end +} UI_FUNCTIONS; + +typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); + #endif//MENU_INT_H \ No newline at end of file diff --git a/engine/physint.h b/engine/physint.h index 14f068ce..af923a00 100644 --- a/engine/physint.h +++ b/engine/physint.h @@ -1,114 +1,114 @@ -/* -physint.h - Server Physics Interface -Copyright (C) 2011 Uncle Mike - -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. -*/ - -#ifndef PHYSINT_H -#define PHYSINT_H - -#define SV_PHYSICS_INTERFACE_VERSION 6 - -#define STRUCT_FROM_LINK( l, t, m ) ((t *)((byte *)l - (int)&(((t *)0)->m))) -#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area ) - -// values that can be returned with pfnServerState -#define SERVER_DEAD 0 -#define SERVER_LOADING 1 -#define SERVER_ACTIVE 2 - -typedef struct areanode_s -{ - int axis; // -1 = leaf node - float dist; - struct areanode_s *children[2]; - link_t trigger_edicts; - link_t solid_edicts; - link_t water_edicts; // func water -} areanode_t; - -typedef struct server_physics_api_s -{ - // unlink edict from old position and link onto new - void ( *pfnLinkEdict) ( edict_t *ent, qboolean touch_triggers ); - double ( *pfnGetServerTime )( void ); // unclamped - double ( *pfnGetFrameTime )( void ); // unclamped - void* ( *pfnGetModel )( int modelindex ); - areanode_t* ( *pfnGetHeadnode )( void ); // BSP tree for all physic entities - int ( *pfnServerState )( void ); - void ( *pfnHost_Error )( const char *error, ... ); // cause Host Error -// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 - struct triangleapi_s *pTriAPI; // draw coliisions etc. Only for local system - - // draw debug messages (must be called from DrawOrthoTriangles). Only for local system - int ( *pfnDrawConsoleString )( int x, int y, char *string ); - void ( *pfnDrawSetTextColor )( float r, float g, float b ); - void ( *pfnDrawConsoleStringLen )( const char *string, int *length, int *height ); - void ( *Con_NPrintf )( int pos, char *fmt, ... ); - void ( *Con_NXPrintf )( struct con_nprint_s *info, char *fmt, ... ); - const char *( *pfnGetLightStyle )( int style ); // read custom appreance for selected lightstyle - void ( *pfnUpdateFogSettings )( unsigned int packed_fog ); - char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); - struct msurface_s *(*pfnTraceSurface)( edict_t *pTextureEntity, const float *v1, const float *v2 ); - const byte *(*pfnGetTextureData)( unsigned int texnum ); - - // static allocations - void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); - void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); -} server_physics_api_t; - -// physic callbacks -typedef struct physics_interface_s -{ - int version; - // passed through pfnCreate (0 is attempt to create, -1 is reject) - int ( *SV_CreateEntity )( edict_t *pent, const char *szName ); - // run custom physics for each entity (return 0 to use built-in engine physic) - int ( *SV_PhysicsEntity )( edict_t *pEntity ); - // spawn entities with internal mod function e.g. for re-arrange spawn order (0 - use engine parser, 1 - use mod parser) - int ( *SV_LoadEntities )( const char *mapname, char *entities ); - // update conveyor belt for clients - void ( *SV_UpdatePlayerBaseVelocity )( edict_t *ent ); - // The game .dll should return 1 if save game should be allowed - int ( *SV_AllowSaveGame )( void ); -// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 - // override trigger area checking and touching - int ( *SV_TriggerTouch )( edict_t *pent, edict_t *trigger ); - // some engine features can be enabled only through this function - unsigned int ( *SV_CheckFeatures )( void ); - // used for draw debug collisions for custom physic engine etc - void ( *DrawDebugTriangles )( void ); - // used for draw debug overlay (textured) - void ( *DrawNormalTriangles )( void ); - // used for draw debug messages (2d mode) - void ( *DrawOrthoTriangles )( void ); - // tracing entities with SOLID_CUSTOM mode on a server (not used by pmove code) - void ( *ClipMoveToEntity)( edict_t *ent, const float *start, float *mins, float *maxs, const float *end, trace_t *trace ); - // tracing entities with SOLID_CUSTOM mode on a server (only used by pmove code) - void ( *ClipPMoveToEntity)( struct physent_s *pe, const float *start, float *mins, float *maxs, const float *end, struct pmtrace_s *tr ); - // called at end the frame of SV_Physics call - void ( *SV_EndFrame )( void ); - // called through save\restore process - void (*pfnCreateEntitiesInTransitionList)( SAVERESTOREDATA*, int levelMask ); - // called through save\restore process - void (*pfnCreateEntitiesInRestoreList)( SAVERESTOREDATA*, int createPlayers ); - // allocate custom string (e.g. using user implementation of stringtable, not engine strings) - string_t (*pfnAllocString)( const char *szValue ); - // make custom string (e.g. using user implementation of stringtable, not engine strings) - string_t (*pfnMakeString)( const char *szValue ); - // read custom string (e.g. using user implementation of stringtable, not engine strings) - const char* (*pfnGetString)( string_t iString ); - // helper for restore custom decals that have custom message (e.g. Paranoia) - int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); -} physics_interface_t; - +/* +physint.h - Server Physics Interface +Copyright (C) 2011 Uncle Mike + +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. +*/ + +#ifndef PHYSINT_H +#define PHYSINT_H + +#define SV_PHYSICS_INTERFACE_VERSION 6 + +#define STRUCT_FROM_LINK( l, t, m ) ((t *)((byte *)l - (int)&(((t *)0)->m))) +#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area ) + +// values that can be returned with pfnServerState +#define SERVER_DEAD 0 +#define SERVER_LOADING 1 +#define SERVER_ACTIVE 2 + +typedef struct areanode_s +{ + int axis; // -1 = leaf node + float dist; + struct areanode_s *children[2]; + link_t trigger_edicts; + link_t solid_edicts; + link_t water_edicts; // func water +} areanode_t; + +typedef struct server_physics_api_s +{ + // unlink edict from old position and link onto new + void ( *pfnLinkEdict) ( edict_t *ent, qboolean touch_triggers ); + double ( *pfnGetServerTime )( void ); // unclamped + double ( *pfnGetFrameTime )( void ); // unclamped + void* ( *pfnGetModel )( int modelindex ); + areanode_t* ( *pfnGetHeadnode )( void ); // BSP tree for all physic entities + int ( *pfnServerState )( void ); + void ( *pfnHost_Error )( const char *error, ... ); // cause Host Error +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 + struct triangleapi_s *pTriAPI; // draw coliisions etc. Only for local system + + // draw debug messages (must be called from DrawOrthoTriangles). Only for local system + int ( *pfnDrawConsoleString )( int x, int y, char *string ); + void ( *pfnDrawSetTextColor )( float r, float g, float b ); + void ( *pfnDrawConsoleStringLen )( const char *string, int *length, int *height ); + void ( *Con_NPrintf )( int pos, char *fmt, ... ); + void ( *Con_NXPrintf )( struct con_nprint_s *info, char *fmt, ... ); + const char *( *pfnGetLightStyle )( int style ); // read custom appreance for selected lightstyle + void ( *pfnUpdateFogSettings )( unsigned int packed_fog ); + char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly ); + struct msurface_s *(*pfnTraceSurface)( edict_t *pTextureEntity, const float *v1, const float *v2 ); + const byte *(*pfnGetTextureData)( unsigned int texnum ); + + // static allocations + void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline ); + void (*pfnMemFree)( void *mem, const char *filename, const int fileline ); +} server_physics_api_t; + +// physic callbacks +typedef struct physics_interface_s +{ + int version; + // passed through pfnCreate (0 is attempt to create, -1 is reject) + int ( *SV_CreateEntity )( edict_t *pent, const char *szName ); + // run custom physics for each entity (return 0 to use built-in engine physic) + int ( *SV_PhysicsEntity )( edict_t *pEntity ); + // spawn entities with internal mod function e.g. for re-arrange spawn order (0 - use engine parser, 1 - use mod parser) + int ( *SV_LoadEntities )( const char *mapname, char *entities ); + // update conveyor belt for clients + void ( *SV_UpdatePlayerBaseVelocity )( edict_t *ent ); + // The game .dll should return 1 if save game should be allowed + int ( *SV_AllowSaveGame )( void ); +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6 + // override trigger area checking and touching + int ( *SV_TriggerTouch )( edict_t *pent, edict_t *trigger ); + // some engine features can be enabled only through this function + unsigned int ( *SV_CheckFeatures )( void ); + // used for draw debug collisions for custom physic engine etc + void ( *DrawDebugTriangles )( void ); + // used for draw debug overlay (textured) + void ( *DrawNormalTriangles )( void ); + // used for draw debug messages (2d mode) + void ( *DrawOrthoTriangles )( void ); + // tracing entities with SOLID_CUSTOM mode on a server (not used by pmove code) + void ( *ClipMoveToEntity)( edict_t *ent, const float *start, float *mins, float *maxs, const float *end, trace_t *trace ); + // tracing entities with SOLID_CUSTOM mode on a server (only used by pmove code) + void ( *ClipPMoveToEntity)( struct physent_s *pe, const float *start, float *mins, float *maxs, const float *end, struct pmtrace_s *tr ); + // called at end the frame of SV_Physics call + void ( *SV_EndFrame )( void ); + // called through save\restore process + void (*pfnCreateEntitiesInTransitionList)( SAVERESTOREDATA*, int levelMask ); + // called through save\restore process + void (*pfnCreateEntitiesInRestoreList)( SAVERESTOREDATA*, int createPlayers ); + // allocate custom string (e.g. using user implementation of stringtable, not engine strings) + string_t (*pfnAllocString)( const char *szValue ); + // make custom string (e.g. using user implementation of stringtable, not engine strings) + string_t (*pfnMakeString)( const char *szValue ); + // read custom string (e.g. using user implementation of stringtable, not engine strings) + const char* (*pfnGetString)( string_t iString ); + // helper for restore custom decals that have custom message (e.g. Paranoia) + int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); +} physics_interface_t; + #endif//PHYSINT_H \ No newline at end of file diff --git a/engine/progdefs.h b/engine/progdefs.h index 2a35559c..74004a27 100644 --- a/engine/progdefs.h +++ b/engine/progdefs.h @@ -1,218 +1,218 @@ -/*** -* -* 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 PROGDEFS_H -#define PROGDEFS_H - -typedef struct -{ - float time; - float frametime; - float force_retouch; - string_t mapname; - string_t startspot; - float deathmatch; - float coop; - float teamplay; - float serverflags; - float found_secrets; - vec3_t v_forward; - vec3_t v_up; - vec3_t v_right; - float trace_allsolid; - float trace_startsolid; - float trace_fraction; - vec3_t trace_endpos; - vec3_t trace_plane_normal; - float trace_plane_dist; - edict_t *trace_ent; - float trace_inopen; - float trace_inwater; - int trace_hitgroup; - int trace_flags; - int changelevel; // transition in progress when true (was msg_entity) - int cdAudioTrack; - int maxClients; - int maxEntities; - const char *pStringBase; - - void *pSaveData; // (SAVERESTOREDATA *) pointer - vec3_t vecLandmarkOffset; -} globalvars_t; - -typedef struct entvars_s -{ - string_t classname; - string_t globalname; - - vec3_t origin; - vec3_t oldorigin; - vec3_t velocity; - vec3_t basevelocity; - vec3_t clbasevelocity; // Base velocity that was passed in to server physics so - // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. - vec3_t movedir; - - vec3_t angles; // Model angles - vec3_t avelocity; // angle velocity (degrees per second) - vec3_t punchangle; // auto-decaying view angle adjustment - vec3_t v_angle; // Viewing angle (player only) - - // For parametric entities - vec3_t endpos; - vec3_t startpos; - float impacttime; - float starttime; - - int fixangle; // 0:nothing, 1:force view angles, 2:add avelocity - float idealpitch; - float pitch_speed; - float ideal_yaw; - float yaw_speed; - - int modelindex; - - string_t model; - int viewmodel; // player's viewmodel - int weaponmodel; // what other players see - - vec3_t absmin; // BB max translated to world coord - vec3_t absmax; // BB max translated to world coord - vec3_t mins; // local BB min - vec3_t maxs; // local BB max - vec3_t size; // maxs - mins - - float ltime; - float nextthink; - - int movetype; - int solid; - - int skin; - int body; // sub-model selection for studiomodels - int effects; - float gravity; // % of "normal" gravity - float friction; // inverse elasticity of MOVETYPE_BOUNCE - - int light_level; - - int sequence; // animation sequence - int gaitsequence; // movement animation sequence for player (0 for none) - float frame; // % playback position in animation sequences (0..255) - float animtime; // world time when frame was set - float framerate; // animation playback rate (-8x to 8x) - byte controller[4]; // bone controller setting (0..255) - byte blending[2]; // blending amount between sub-sequences (0..255) - - float scale; // sprites and models rendering scale (0..255) - int rendermode; - float renderamt; - vec3_t rendercolor; - int renderfx; - - float health; - float frags; - int weapons; // bit mask for available weapons - float takedamage; - - int deadflag; - vec3_t view_ofs; // eye position - - int button; - int impulse; - - edict_t *chain; // Entity pointer when linked into a linked list - edict_t *dmg_inflictor; - edict_t *enemy; - edict_t *aiment; // entity pointer when MOVETYPE_FOLLOW - edict_t *owner; - edict_t *groundentity; - - int spawnflags; - int flags; - - int colormap; // lowbyte topcolor, highbyte bottomcolor - int team; - - float max_health; - float teleport_time; - float armortype; - float armorvalue; - int waterlevel; - int watertype; - - string_t target; - string_t targetname; - string_t netname; - string_t message; - - float dmg_take; - float dmg_save; - float dmg; - float dmgtime; - - string_t noise; - string_t noise1; - string_t noise2; - string_t noise3; - - float speed; - float air_finished; - float pain_finished; - float radsuit_finished; - - edict_t *pContainingEntity; - - int playerclass; - float maxspeed; - - float fov; - int weaponanim; - - int pushmsec; - - int bInDuck; - int flTimeStepSound; - int flSwimTime; - int flDuckTime; - int iStepLeft; - float flFallVelocity; - - int gamestate; - - int oldbuttons; - - int groupinfo; - - // 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; - edict_t *euser1; - edict_t *euser2; - edict_t *euser3; - edict_t *euser4; -} entvars_t; - +/*** +* +* 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 PROGDEFS_H +#define PROGDEFS_H + +typedef struct +{ + float time; + float frametime; + float force_retouch; + string_t mapname; + string_t startspot; + float deathmatch; + float coop; + float teamplay; + float serverflags; + float found_secrets; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + edict_t *trace_ent; + float trace_inopen; + float trace_inwater; + int trace_hitgroup; + int trace_flags; + int changelevel; // transition in progress when true (was msg_entity) + int cdAudioTrack; + int maxClients; + int maxEntities; + const char *pStringBase; + + void *pSaveData; // (SAVERESTOREDATA *) pointer + vec3_t vecLandmarkOffset; +} globalvars_t; + +typedef struct entvars_s +{ + string_t classname; + string_t globalname; + + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t basevelocity; + vec3_t clbasevelocity; // Base velocity that was passed in to server physics so + // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. + vec3_t movedir; + + vec3_t angles; // Model angles + vec3_t avelocity; // angle velocity (degrees per second) + vec3_t punchangle; // auto-decaying view angle adjustment + vec3_t v_angle; // Viewing angle (player only) + + // For parametric entities + vec3_t endpos; + vec3_t startpos; + float impacttime; + float starttime; + + int fixangle; // 0:nothing, 1:force view angles, 2:add avelocity + float idealpitch; + float pitch_speed; + float ideal_yaw; + float yaw_speed; + + int modelindex; + + string_t model; + int viewmodel; // player's viewmodel + int weaponmodel; // what other players see + + vec3_t absmin; // BB max translated to world coord + vec3_t absmax; // BB max translated to world coord + vec3_t mins; // local BB min + vec3_t maxs; // local BB max + vec3_t size; // maxs - mins + + float ltime; + float nextthink; + + int movetype; + int solid; + + int skin; + int body; // sub-model selection for studiomodels + int effects; + float gravity; // % of "normal" gravity + float friction; // inverse elasticity of MOVETYPE_BOUNCE + + int light_level; + + int sequence; // animation sequence + int gaitsequence; // movement animation sequence for player (0 for none) + float frame; // % playback position in animation sequences (0..255) + float animtime; // world time when frame was set + float framerate; // animation playback rate (-8x to 8x) + byte controller[4]; // bone controller setting (0..255) + byte blending[2]; // blending amount between sub-sequences (0..255) + + float scale; // sprites and models rendering scale (0..255) + int rendermode; + float renderamt; + vec3_t rendercolor; + int renderfx; + + float health; + float frags; + int weapons; // bit mask for available weapons + float takedamage; + + int deadflag; + vec3_t view_ofs; // eye position + + int button; + int impulse; + + edict_t *chain; // Entity pointer when linked into a linked list + edict_t *dmg_inflictor; + edict_t *enemy; + edict_t *aiment; // entity pointer when MOVETYPE_FOLLOW + edict_t *owner; + edict_t *groundentity; + + int spawnflags; + int flags; + + int colormap; // lowbyte topcolor, highbyte bottomcolor + int team; + + float max_health; + float teleport_time; + float armortype; + float armorvalue; + int waterlevel; + int watertype; + + string_t target; + string_t targetname; + string_t netname; + string_t message; + + float dmg_take; + float dmg_save; + float dmg; + float dmgtime; + + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; + + float speed; + float air_finished; + float pain_finished; + float radsuit_finished; + + edict_t *pContainingEntity; + + int playerclass; + float maxspeed; + + float fov; + int weaponanim; + + int pushmsec; + + int bInDuck; + int flTimeStepSound; + int flSwimTime; + int flDuckTime; + int iStepLeft; + float flFallVelocity; + + int gamestate; + + int oldbuttons; + + int groupinfo; + + // 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; + edict_t *euser1; + edict_t *euser2; + edict_t *euser3; + edict_t *euser4; +} entvars_t; + #endif//PROGDEFS_H \ No newline at end of file diff --git a/engine/shake.h b/engine/shake.h index 7eeb6790..c644a476 100644 --- a/engine/shake.h +++ b/engine/shake.h @@ -1,50 +1,50 @@ -/*** -* -* 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 SHAKE_H -#define SHAKE_H - -// Screen / View effects - -// screen shake -extern int gmsgShake; - -// This structure is sent over the net to describe a screen shake event -typedef struct -{ - unsigned short amplitude; // FIXED 4.12 amount of shake - unsigned short duration; // FIXED 4.12 seconds duration - unsigned short frequency; // FIXED 8.8 noise frequency (low frequency is a jerk,high frequency is a rumble) -} ScreenShake; - -// Fade in/out -extern int gmsgFade; - -#define FFADE_IN 0x0000 // Just here so we don't pass 0 into the function -#define FFADE_OUT 0x0001 // Fade out (not in) -#define FFADE_MODULATE 0x0002 // Modulate (don't blend) -#define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received - - -// This structure is sent over the net to describe a screen fade event -typedef struct -{ - unsigned short duration; // FIXED 4.12 seconds duration - unsigned short holdTime; // FIXED 4.12 seconds duration until reset (fade & hold) - short fadeFlags; // flags - byte r, g, b, a; // fade to color ( max alpha ) -} ScreenFade; - +/*** +* +* 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 SHAKE_H +#define SHAKE_H + +// Screen / View effects + +// screen shake +extern int gmsgShake; + +// This structure is sent over the net to describe a screen shake event +typedef struct +{ + unsigned short amplitude; // FIXED 4.12 amount of shake + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short frequency; // FIXED 8.8 noise frequency (low frequency is a jerk,high frequency is a rumble) +} ScreenShake; + +// Fade in/out +extern int gmsgFade; + +#define FFADE_IN 0x0000 // Just here so we don't pass 0 into the function +#define FFADE_OUT 0x0001 // Fade out (not in) +#define FFADE_MODULATE 0x0002 // Modulate (don't blend) +#define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received + + +// This structure is sent over the net to describe a screen fade event +typedef struct +{ + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short holdTime; // FIXED 4.12 seconds duration until reset (fade & hold) + short fadeFlags; // flags + byte r, g, b, a; // fade to color ( max alpha ) +} ScreenFade; + #endif // SHAKE_H \ No newline at end of file diff --git a/engine/sprite.h b/engine/sprite.h index 99c39935..afc81a4e 100644 --- a/engine/sprite.h +++ b/engine/sprite.h @@ -1,102 +1,102 @@ -/*** -* -* 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 SPRITE_H -#define SPRITE_H - -/* -============================================================================== - -SPRITE MODELS - -.spr extended version (Half-Life compatible sprites with some Xash3D extensions) -============================================================================== -*/ - -#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP" -#define SPRITE_VERSION 2 // Half-Life sprites - -typedef enum -{ - ST_SYNC = 0, - ST_RAND -} synctype_t; - -typedef enum -{ - FRAME_SINGLE = 0, - FRAME_GROUP, - FRAME_ANGLED // Xash3D ext -} frametype_t; - -typedef enum -{ - SPR_NORMAL = 0, - SPR_ADDITIVE, - SPR_INDEXALPHA, - SPR_ALPHTEST, -} drawtype_t; - -typedef enum -{ - SPR_FWD_PARALLEL_UPRIGHT = 0, - SPR_FACING_UPRIGHT, - SPR_FWD_PARALLEL, - SPR_ORIENTED, - SPR_FWD_PARALLEL_ORIENTED, -} angletype_t; - -typedef enum -{ - SPR_CULL_FRONT = 0, // oriented sprite will be draw with one face - SPR_CULL_NONE, // oriented sprite will be draw back face too -} facetype_t; - -typedef struct -{ - int ident; // LittleLong 'ISPR' - int version; // current version 2 - angletype_t type; // camera align - drawtype_t texFormat; // rendering mode - int boundingradius; // quick face culling - int bounds[2]; // mins\maxs - int numframes; // including groups - facetype_t facetype; // cullface (Xash3D ext) - synctype_t synctype; // animation synctype -} dsprite_t; - -typedef struct -{ - int origin[2]; - int width; - int height; -} dspriteframe_t; - -typedef struct -{ - int numframes; -} dspritegroup_t; - -typedef struct -{ - float interval; -} dspriteinterval_t; - -typedef struct -{ - frametype_t type; -} dframetype_t; - +/*** +* +* 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 SPRITE_H +#define SPRITE_H + +/* +============================================================================== + +SPRITE MODELS + +.spr extended version (Half-Life compatible sprites with some Xash3D extensions) +============================================================================== +*/ + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP" +#define SPRITE_VERSION 2 // Half-Life sprites + +typedef enum +{ + ST_SYNC = 0, + ST_RAND +} synctype_t; + +typedef enum +{ + FRAME_SINGLE = 0, + FRAME_GROUP, + FRAME_ANGLED // Xash3D ext +} frametype_t; + +typedef enum +{ + SPR_NORMAL = 0, + SPR_ADDITIVE, + SPR_INDEXALPHA, + SPR_ALPHTEST, +} drawtype_t; + +typedef enum +{ + SPR_FWD_PARALLEL_UPRIGHT = 0, + SPR_FACING_UPRIGHT, + SPR_FWD_PARALLEL, + SPR_ORIENTED, + SPR_FWD_PARALLEL_ORIENTED, +} angletype_t; + +typedef enum +{ + SPR_CULL_FRONT = 0, // oriented sprite will be draw with one face + SPR_CULL_NONE, // oriented sprite will be draw back face too +} facetype_t; + +typedef struct +{ + int ident; // LittleLong 'ISPR' + int version; // current version 2 + angletype_t type; // camera align + drawtype_t texFormat; // rendering mode + int boundingradius; // quick face culling + int bounds[2]; // mins\maxs + int numframes; // including groups + facetype_t facetype; // cullface (Xash3D ext) + synctype_t synctype; // animation synctype +} dsprite_t; + +typedef struct +{ + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct +{ + int numframes; +} dspritegroup_t; + +typedef struct +{ + float interval; +} dspriteinterval_t; + +typedef struct +{ + frametype_t type; +} dframetype_t; + #endif//SPRITE_H \ No newline at end of file diff --git a/engine/studio.h b/engine/studio.h index 3d4f3d87..b5b709bb 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -1,371 +1,371 @@ -/*** -* -* 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 STUDIO_H -#define STUDIO_H - -/* -============================================================================== - -STUDIO MODELS - -Studio models are position independent, so the cache manager can move them. -============================================================================== -*/ - -// header -#define STUDIO_VERSION 10 -#define IDSTUDIOHEADER (('T'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDST" -#define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ" - -// studio limits -#define MAXSTUDIOTRIANGLES 32768 // max triangles per model -#define MAXSTUDIOVERTS 4096 // max vertices per submodel -#define MAXSTUDIOSEQUENCES 256 // total animation sequences -#define MAXSTUDIOSKINS 256 // 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 // body parts per submodel -#define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) -#define MAXSTUDIOANIMATIONS 512 // max frames per sequence -#define MAXSTUDIOMESHES 256 // max textures per model -#define MAXSTUDIOEVENTS 1024 // events per model -#define MAXSTUDIOPIVOTS 256 // pivot points -#define MAXSTUDIOBLENDS 16 // max anim blends -#define MAXSTUDIOCONTROLLERS 8 // max controllers per model -#define MAXSTUDIOATTACHMENTS 4 // max attachments per model - -// client-side model flags -#define STUDIO_ROCKET 0x0001 // leave a trail -#define STUDIO_GRENADE 0x0002 // leave a trail -#define STUDIO_GIB 0x0004 // leave a trail -#define STUDIO_ROTATE 0x0008 // rotate (bonus items) -#define STUDIO_TRACER 0x0010 // green split trail -#define STUDIO_ZOMGIB 0x0020 // small blood trail -#define STUDIO_TRACER2 0x0040 // orange split trail + rotate -#define STUDIO_TRACER3 0x0080 // purple trail -#define STUDIO_DYNAMIC_LIGHT 0x0100 // dynamically get lighting from floor or ceil (flying monsters) -#define STUDIO_TRACE_HITBOX 0x0200 // always use hitbox trace instead of bbox - -// lighting & rendermode options -#define STUDIO_NF_FLATSHADE 0x0001 -#define STUDIO_NF_CHROME 0x0002 -#define STUDIO_NF_FULLBRIGHT 0x0004 -#define STUDIO_NF_COLORMAP 0x0008 // can changed by colormap command -#define STUDIO_NF_ALPHA 0x0010 // rendering as transparent texture -#define STUDIO_NF_ADDITIVE 0x0020 // rendering with additive mode -#define STUDIO_NF_TRANSPARENT 0x0040 // use texture with alpha channel -#define STUDIO_NF_NORMALMAP 0x0080 // indexed normalmap -#define STUDIO_NF_GLOSSMAP 0x0100 // heightmap that can be used for parallax or normalmap -#define STUDIO_NF_GLOSSPOWER 0x0200 // glossmap -#define STUDIO_NF_UV_COORDS (1<<31) // using fixed coords instead of ST - -// motion flags -#define STUDIO_X 0x0001 -#define STUDIO_Y 0x0002 -#define STUDIO_Z 0x0004 -#define STUDIO_XR 0x0008 -#define STUDIO_YR 0x0010 -#define STUDIO_ZR 0x0020 -#define STUDIO_LX 0x0040 -#define STUDIO_LY 0x0080 -#define STUDIO_LZ 0x0100 -#define STUDIO_AX 0x0200 -#define STUDIO_AY 0x0400 -#define STUDIO_AZ 0x0800 -#define STUDIO_AXR 0x1000 -#define STUDIO_AYR 0x2000 -#define STUDIO_AZR 0x4000 -#define STUDIO_TYPES 0x7FFF -#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance - -// bonecontroller types -#define STUDIO_MOUTH 4 // hardcoded - -// sequence flags -#define STUDIO_LOOPING 0x0001 -#define STUDIO_STATIC 0x8000 // studiomodel is static - -// bone flags -#define STUDIO_HAS_NORMALS 0x0001 -#define STUDIO_HAS_VERTICES 0x0002 -#define STUDIO_HAS_BBOX 0x0004 -#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them - -typedef struct -{ - int ident; - int version; - - char name[64]; - int length; - - vec3_t eyeposition; // ideal eye position - vec3_t min; // ideal movement hull size - vec3_t max; - - vec3_t bbmin; // clipping bounding box - vec3_t bbmax; - - int flags; - - int numbones; // bones - int boneindex; - - int numbonecontrollers; // bone controllers - int bonecontrollerindex; - - int numhitboxes; // complex bounding boxes - int hitboxindex; - - int numseq; // animation sequences - int seqindex; - - int numseqgroups; // demand loaded sequences - int seqgroupindex; - - int numtextures; // raw textures - int textureindex; - int texturedataindex; - - int numskinref; // replaceable textures - int numskinfamilies; - int skinindex; - - int numbodyparts; - int bodypartindex; - - int numattachments; // queryable attachable points - int attachmentindex; - - int soundtable; - int soundindex; - int soundgroups; - int soundgroupindex; - - int numtransitions; // animation node to animation node transition graph - int transitionindex; -} studiohdr_t; - -// header for demand loaded sequence group data -typedef struct -{ - int id; - int version; - - char name[64]; - int length; -} studioseqhdr_t; - -// bones -typedef struct -{ - char name[32]; // bone name for symbolic links - int parent; // parent bone - int flags; // ?? - int bonecontroller[6]; // bone controller index, -1 == none - float value[6]; // default DoF values - float scale[6]; // scale for delta DoF values -} mstudiobone_t; - -// bone controllers -typedef struct -{ - int bone; // -1 == 0 - int type; // X, Y, Z, XR, YR, ZR, M - float start; - float end; - int rest; // byte index value at rest - int index; // 0-3 user set controller, 4 mouth -} mstudiobonecontroller_t; - -// intersection boxes -typedef struct -{ - int bone; - int group; // intersection group - vec3_t bbmin; // bounding box - vec3_t bbmax; -} mstudiobbox_t; - -#ifndef CACHE_USER -#define CACHE_USER -typedef struct cache_user_s -{ - void *data; // extradata -} cache_user_t; -#endif - -// demand loaded sequence groups -typedef struct -{ - char label[32]; // textual name - char name[64]; // file name - cache_user_t cache; // cache index pointer -#ifndef __amd64 - int data; // hack for group 0 -#endif -} mstudioseqgroup_t; - -// sequence descriptions -typedef struct -{ - char label[32]; // sequence label - - float fps; // frames per second - int flags; // looping/non-looping flags - - int activity; - int actweight; - - int numevents; - int eventindex; - - int numframes; // number of frames per sequence - - int numpivots; // number of foot pivots - int pivotindex; - - int motiontype; - int motionbone; - vec3_t linearmovement; - int automoveposindex; - int automoveangleindex; - - vec3_t bbmin; // per sequence bounding box - vec3_t bbmax; - - int numblends; - int animindex; // mstudioanim_t pointer relative to start of sequence group data - // [blend][bone][X, Y, Z, XR, YR, ZR] - - int blendtype[2]; // X, Y, Z, XR, YR, ZR - float blendstart[2]; // starting value - float blendend[2]; // ending value - int blendparent; - - int seqgroup; // sequence group for demand loading - - int entrynode; // transition node at entry - int exitnode; // transition node at exit - int nodeflags; // transition rules - - int nextseq; // auto advancing sequences -} mstudioseqdesc_t; - -// events -#include "studio_event.h" - -// pivots -typedef struct -{ - vec3_t org; // pivot point - int start; - int end; -} mstudiopivot_t; - -// attachment -typedef struct -{ - char name[32]; - int type; - int bone; - vec3_t org; // attachment point - vec3_t vectors[3]; -} mstudioattachment_t; - -typedef struct -{ - unsigned short offset[6]; -} mstudioanim_t; - -// animation frames -typedef union -{ - struct - { - byte valid; - byte total; - } num; - short value; -} mstudioanimvalue_t; - -// body part index -typedef struct -{ - char name[64]; - int nummodels; - int base; - int modelindex; // index into models array -} mstudiobodyparts_t; - -// skin info -typedef struct mstudiotex_s -{ - char name[64]; - unsigned short flags; - unsigned short unused; // lower 16 bit is a user area - int width; - int height; - int index; -} mstudiotexture_t; - -// skin families -// short index[skinfamilies][skinref] - -// studio models -typedef struct -{ - char name[64]; - - int type; - float boundingradius; - - int nummesh; - int meshindex; - - int numverts; // number of unique vertices - int vertinfoindex; // vertex bone info - int vertindex; // vertex vec3_t - int numnorms; // number of unique surface normals - int norminfoindex; // normal bone info - int normindex; // normal vec3_t - - int numgroups; // deformation groups - int groupindex; -} mstudiomodel_t; - -// vec3_t boundingbox[model][bone][2]; // complex intersection info - -// meshes -typedef struct -{ - int numtris; - int triindex; - int skinref; - int numnorms; // per mesh normals - int normindex; // normal vec3_t -} mstudiomesh_t; - -// triangles -typedef struct -{ - short vertindex; // index into vertex array - short normindex; // index into normal array - short s,t; // s,t position on skin -} mstudiotrivert_t; - -#endif//STUDIO_H +/*** +* +* 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 STUDIO_H +#define STUDIO_H + +/* +============================================================================== + +STUDIO MODELS + +Studio models are position independent, so the cache manager can move them. +============================================================================== +*/ + +// header +#define STUDIO_VERSION 10 +#define IDSTUDIOHEADER (('T'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDST" +#define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ" + +// studio limits +#define MAXSTUDIOTRIANGLES 32768 // max triangles per model +#define MAXSTUDIOVERTS 4096 // max vertices per submodel +#define MAXSTUDIOSEQUENCES 256 // total animation sequences +#define MAXSTUDIOSKINS 256 // 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 // body parts per submodel +#define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) +#define MAXSTUDIOANIMATIONS 512 // max frames per sequence +#define MAXSTUDIOMESHES 256 // max textures per model +#define MAXSTUDIOEVENTS 1024 // events per model +#define MAXSTUDIOPIVOTS 256 // pivot points +#define MAXSTUDIOBLENDS 16 // max anim blends +#define MAXSTUDIOCONTROLLERS 8 // max controllers per model +#define MAXSTUDIOATTACHMENTS 4 // max attachments per model + +// client-side model flags +#define STUDIO_ROCKET 0x0001 // leave a trail +#define STUDIO_GRENADE 0x0002 // leave a trail +#define STUDIO_GIB 0x0004 // leave a trail +#define STUDIO_ROTATE 0x0008 // rotate (bonus items) +#define STUDIO_TRACER 0x0010 // green split trail +#define STUDIO_ZOMGIB 0x0020 // small blood trail +#define STUDIO_TRACER2 0x0040 // orange split trail + rotate +#define STUDIO_TRACER3 0x0080 // purple trail +#define STUDIO_DYNAMIC_LIGHT 0x0100 // dynamically get lighting from floor or ceil (flying monsters) +#define STUDIO_TRACE_HITBOX 0x0200 // always use hitbox trace instead of bbox + +// lighting & rendermode options +#define STUDIO_NF_FLATSHADE 0x0001 +#define STUDIO_NF_CHROME 0x0002 +#define STUDIO_NF_FULLBRIGHT 0x0004 +#define STUDIO_NF_COLORMAP 0x0008 // can changed by colormap command +#define STUDIO_NF_ALPHA 0x0010 // rendering as transparent texture +#define STUDIO_NF_ADDITIVE 0x0020 // rendering with additive mode +#define STUDIO_NF_TRANSPARENT 0x0040 // use texture with alpha channel +#define STUDIO_NF_NORMALMAP 0x0080 // indexed normalmap +#define STUDIO_NF_GLOSSMAP 0x0100 // heightmap that can be used for parallax or normalmap +#define STUDIO_NF_GLOSSPOWER 0x0200 // glossmap +#define STUDIO_NF_UV_COORDS (1<<31) // using fixed coords instead of ST + +// motion flags +#define STUDIO_X 0x0001 +#define STUDIO_Y 0x0002 +#define STUDIO_Z 0x0004 +#define STUDIO_XR 0x0008 +#define STUDIO_YR 0x0010 +#define STUDIO_ZR 0x0020 +#define STUDIO_LX 0x0040 +#define STUDIO_LY 0x0080 +#define STUDIO_LZ 0x0100 +#define STUDIO_AX 0x0200 +#define STUDIO_AY 0x0400 +#define STUDIO_AZ 0x0800 +#define STUDIO_AXR 0x1000 +#define STUDIO_AYR 0x2000 +#define STUDIO_AZR 0x4000 +#define STUDIO_TYPES 0x7FFF +#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + +// bonecontroller types +#define STUDIO_MOUTH 4 // hardcoded + +// sequence flags +#define STUDIO_LOOPING 0x0001 +#define STUDIO_STATIC 0x8000 // studiomodel is static + +// bone flags +#define STUDIO_HAS_NORMALS 0x0001 +#define STUDIO_HAS_VERTICES 0x0002 +#define STUDIO_HAS_BBOX 0x0004 +#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + +typedef struct +{ + int ident; + int version; + + char name[64]; + int length; + + vec3_t eyeposition; // ideal eye position + vec3_t min; // ideal movement hull size + vec3_t max; + + vec3_t bbmin; // clipping bounding box + vec3_t bbmax; + + int flags; + + int numbones; // bones + int boneindex; + + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + + int numhitboxes; // complex bounding boxes + int hitboxindex; + + int numseq; // animation sequences + int seqindex; + + int numseqgroups; // demand loaded sequences + int seqgroupindex; + + int numtextures; // raw textures + int textureindex; + int texturedataindex; + + int numskinref; // replaceable textures + int numskinfamilies; + int skinindex; + + int numbodyparts; + int bodypartindex; + + int numattachments; // queryable attachable points + int attachmentindex; + + int soundtable; + int soundindex; + int soundgroups; + int soundgroupindex; + + int numtransitions; // animation node to animation node transition graph + int transitionindex; +} studiohdr_t; + +// header for demand loaded sequence group data +typedef struct +{ + int id; + int version; + + char name[64]; + int length; +} studioseqhdr_t; + +// bones +typedef struct +{ + char name[32]; // bone name for symbolic links + int parent; // parent bone + int flags; // ?? + int bonecontroller[6]; // bone controller index, -1 == none + float value[6]; // default DoF values + float scale[6]; // scale for delta DoF values +} mstudiobone_t; + +// bone controllers +typedef struct +{ + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int index; // 0-3 user set controller, 4 mouth +} mstudiobonecontroller_t; + +// intersection boxes +typedef struct +{ + int bone; + int group; // intersection group + vec3_t bbmin; // bounding box + vec3_t bbmax; +} mstudiobbox_t; + +#ifndef CACHE_USER +#define CACHE_USER +typedef struct cache_user_s +{ + void *data; // extradata +} cache_user_t; +#endif + +// demand loaded sequence groups +typedef struct +{ + char label[32]; // textual name + char name[64]; // file name + cache_user_t cache; // cache index pointer +#ifndef __amd64 + int data; // hack for group 0 +#endif +} mstudioseqgroup_t; + +// sequence descriptions +typedef struct +{ + char label[32]; // sequence label + + float fps; // frames per second + int flags; // looping/non-looping flags + + int activity; + int actweight; + + int numevents; + int eventindex; + + int numframes; // number of frames per sequence + + int numpivots; // number of foot pivots + int pivotindex; + + int motiontype; + int motionbone; + vec3_t linearmovement; + int automoveposindex; + int automoveangleindex; + + vec3_t bbmin; // per sequence bounding box + vec3_t bbmax; + + int numblends; + int animindex; // mstudioanim_t pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + int blendtype[2]; // X, Y, Z, XR, YR, ZR + float blendstart[2]; // starting value + float blendend[2]; // ending value + int blendparent; + + int seqgroup; // sequence group for demand loading + + int entrynode; // transition node at entry + int exitnode; // transition node at exit + int nodeflags; // transition rules + + int nextseq; // auto advancing sequences +} mstudioseqdesc_t; + +// events +#include "studio_event.h" + +// pivots +typedef struct +{ + vec3_t org; // pivot point + int start; + int end; +} mstudiopivot_t; + +// attachment +typedef struct +{ + char name[32]; + int type; + int bone; + vec3_t org; // attachment point + vec3_t vectors[3]; +} mstudioattachment_t; + +typedef struct +{ + unsigned short offset[6]; +} mstudioanim_t; + +// animation frames +typedef union +{ + struct + { + byte valid; + byte total; + } num; + short value; +} mstudioanimvalue_t; + +// body part index +typedef struct +{ + char name[64]; + int nummodels; + int base; + int modelindex; // index into models array +} mstudiobodyparts_t; + +// skin info +typedef struct mstudiotex_s +{ + char name[64]; + unsigned short flags; + unsigned short unused; // lower 16 bit is a user area + int width; + int height; + int index; +} mstudiotexture_t; + +// skin families +// short index[skinfamilies][skinref] + +// studio models +typedef struct +{ + char name[64]; + + int type; + float boundingradius; + + int nummesh; + int meshindex; + + int numverts; // number of unique vertices + int vertinfoindex; // vertex bone info + int vertindex; // vertex vec3_t + int numnorms; // number of unique surface normals + int norminfoindex; // normal bone info + int normindex; // normal vec3_t + + int numgroups; // deformation groups + int groupindex; +} mstudiomodel_t; + +// vec3_t boundingbox[model][bone][2]; // complex intersection info + +// meshes +typedef struct +{ + int numtris; + int triindex; + int skinref; + int numnorms; // per mesh normals + int normindex; // normal vec3_t +} mstudiomesh_t; + +// triangles +typedef struct +{ + short vertindex; // index into vertex array + short normindex; // index into normal array + short s,t; // s,t position on skin +} mstudiotrivert_t; + +#endif//STUDIO_H diff --git a/engine/warpsin.h b/engine/warpsin.h index e140acf9..e46b44d7 100644 --- a/engine/warpsin.h +++ b/engine/warpsin.h @@ -1,53 +1,53 @@ -/* -Copyright (C) 1997-2001 Id Software, Inc. - -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. - -*/ - - -0.000000, 0.098165, 0.196270, 0.294259, 0.392069, 0.489643, 0.586920, 0.683850, -0.780360, 0.876405, 0.971920, 1.066850, 1.161140, 1.254725, 1.347560, 1.439580, -1.530735, 1.620965, 1.710220, 1.798445, 1.885585, 1.971595, 2.056410, 2.139990, -2.222280, 2.303235, 2.382795, 2.460925, 2.537575, 2.612690, 2.686235, 2.758160, -2.828425, 2.896990, 2.963805, 3.028835, 3.092040, 3.153385, 3.212830, 3.270340, -3.325880, 3.379415, 3.430915, 3.480350, 3.527685, 3.572895, 3.615955, 3.656840, -3.695520, 3.731970, 3.766175, 3.798115, 3.827760, 3.855105, 3.880125, 3.902810, -3.923140, 3.941110, 3.956705, 3.969920, 3.980740, 3.989160, 3.995180, 3.998795, -4.000000, 3.998795, 3.995180, 3.989160, 3.980740, 3.969920, 3.956705, 3.941110, -3.923140, 3.902810, 3.880125, 3.855105, 3.827760, 3.798115, 3.766175, 3.731970, -3.695520, 3.656840, 3.615955, 3.572895, 3.527685, 3.480350, 3.430915, 3.379415, -3.325880, 3.270340, 3.212830, 3.153385, 3.092040, 3.028835, 2.963805, 2.896990, -2.828425, 2.758160, 2.686235, 2.612690, 2.537575, 2.460925, 2.382795, 2.303235, -2.222280, 2.139990, 2.056410, 1.971595, 1.885585, 1.798445, 1.710220, 1.620965, -1.530735, 1.439580, 1.347560, 1.254725, 1.161140, 1.066850, 0.971920, 0.876405, -0.780360, 0.683850, 0.586920, 0.489643, 0.392069, 0.294259, 0.196270, 0.098165, -0.000000, -0.098165, -0.196270, -0.294259, -0.392069, -0.489643, -0.586920, -0.683850, --0.780360, -0.876405, -0.971920, -1.066850, -1.161140, -1.254725, -1.347560, -1.439580, --1.530735, -1.620965, -1.710220, -1.798445, -1.885585, -1.971595, -2.056410, -2.139990, --2.222280, -2.303235, -2.382795, -2.460925, -2.537575, -2.612690, -2.686235, -2.758160, --2.828425, -2.896990, -2.963805, -3.028835, -3.092040, -3.153385, -3.212830, -3.270340, --3.325880, -3.379415, -3.430915, -3.480350, -3.527685, -3.572895, -3.615955, -3.656840, --3.695520, -3.731970, -3.766175, -3.798115, -3.827760, -3.855105, -3.880125, -3.902810, --3.923140, -3.941110, -3.956705, -3.969920, -3.980740, -3.989160, -3.995180, -3.998795, --4.000000, -3.998795, -3.995180, -3.989160, -3.980740, -3.969920, -3.956705, -3.941110, --3.923140, -3.902810, -3.880125, -3.855105, -3.827760, -3.798115, -3.766175, -3.731970, --3.695520, -3.656840, -3.615955, -3.572895, -3.527685, -3.480350, -3.430915, -3.379415, --3.325880, -3.270340, -3.212830, -3.153385, -3.092040, -3.028835, -2.963805, -2.896990, --2.828425, -2.758160, -2.686235, -2.612690, -2.537575, -2.460925, -2.382795, -2.303235, --2.222280, -2.139990, -2.056410, -1.971595, -1.885585, -1.798445, -1.710220, -1.620965, --1.530735, -1.439580, -1.347560, -1.254725, -1.161140, -1.066850, -0.971920, -0.876405, --0.780360, -0.683850, -0.586920, -0.489643, -0.392069, -0.294259, -0.196270, -0.098165, +/* +Copyright (C) 1997-2001 Id Software, Inc. + +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. + +*/ + + +0.000000, 0.098165, 0.196270, 0.294259, 0.392069, 0.489643, 0.586920, 0.683850, +0.780360, 0.876405, 0.971920, 1.066850, 1.161140, 1.254725, 1.347560, 1.439580, +1.530735, 1.620965, 1.710220, 1.798445, 1.885585, 1.971595, 2.056410, 2.139990, +2.222280, 2.303235, 2.382795, 2.460925, 2.537575, 2.612690, 2.686235, 2.758160, +2.828425, 2.896990, 2.963805, 3.028835, 3.092040, 3.153385, 3.212830, 3.270340, +3.325880, 3.379415, 3.430915, 3.480350, 3.527685, 3.572895, 3.615955, 3.656840, +3.695520, 3.731970, 3.766175, 3.798115, 3.827760, 3.855105, 3.880125, 3.902810, +3.923140, 3.941110, 3.956705, 3.969920, 3.980740, 3.989160, 3.995180, 3.998795, +4.000000, 3.998795, 3.995180, 3.989160, 3.980740, 3.969920, 3.956705, 3.941110, +3.923140, 3.902810, 3.880125, 3.855105, 3.827760, 3.798115, 3.766175, 3.731970, +3.695520, 3.656840, 3.615955, 3.572895, 3.527685, 3.480350, 3.430915, 3.379415, +3.325880, 3.270340, 3.212830, 3.153385, 3.092040, 3.028835, 2.963805, 2.896990, +2.828425, 2.758160, 2.686235, 2.612690, 2.537575, 2.460925, 2.382795, 2.303235, +2.222280, 2.139990, 2.056410, 1.971595, 1.885585, 1.798445, 1.710220, 1.620965, +1.530735, 1.439580, 1.347560, 1.254725, 1.161140, 1.066850, 0.971920, 0.876405, +0.780360, 0.683850, 0.586920, 0.489643, 0.392069, 0.294259, 0.196270, 0.098165, +0.000000, -0.098165, -0.196270, -0.294259, -0.392069, -0.489643, -0.586920, -0.683850, +-0.780360, -0.876405, -0.971920, -1.066850, -1.161140, -1.254725, -1.347560, -1.439580, +-1.530735, -1.620965, -1.710220, -1.798445, -1.885585, -1.971595, -2.056410, -2.139990, +-2.222280, -2.303235, -2.382795, -2.460925, -2.537575, -2.612690, -2.686235, -2.758160, +-2.828425, -2.896990, -2.963805, -3.028835, -3.092040, -3.153385, -3.212830, -3.270340, +-3.325880, -3.379415, -3.430915, -3.480350, -3.527685, -3.572895, -3.615955, -3.656840, +-3.695520, -3.731970, -3.766175, -3.798115, -3.827760, -3.855105, -3.880125, -3.902810, +-3.923140, -3.941110, -3.956705, -3.969920, -3.980740, -3.989160, -3.995180, -3.998795, +-4.000000, -3.998795, -3.995180, -3.989160, -3.980740, -3.969920, -3.956705, -3.941110, +-3.923140, -3.902810, -3.880125, -3.855105, -3.827760, -3.798115, -3.766175, -3.731970, +-3.695520, -3.656840, -3.615955, -3.572895, -3.527685, -3.480350, -3.430915, -3.379415, +-3.325880, -3.270340, -3.212830, -3.153385, -3.092040, -3.028835, -2.963805, -2.896990, +-2.828425, -2.758160, -2.686235, -2.612690, -2.537575, -2.460925, -2.382795, -2.303235, +-2.222280, -2.139990, -2.056410, -1.971595, -1.885585, -1.798445, -1.710220, -1.620965, +-1.530735, -1.439580, -1.347560, -1.254725, -1.161140, -1.066850, -0.971920, -0.876405, +-0.780360, -0.683850, -0.586920, -0.489643, -0.392069, -0.294259, -0.196270, -0.098165, diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h index 58871a4a..4c6b2c97 100644 --- a/game_shared/bitvec.h +++ b/game_shared/bitvec.h @@ -1,179 +1,179 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef BITVEC_H -#define BITVEC_H -#ifdef _WIN32 -#pragma once -#endif - - -#include -#include - -class CBitVecAccessor -{ -public: - CBitVecAccessor(unsigned long *pDWords, int iBit); - - void operator=(int val); - operator unsigned long(); - -private: - unsigned long *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(); - unsigned long GetDWord(int i); - void SetDWord(int i, unsigned long val); - - int GetNumBits(); - -private: - - enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; - unsigned long m_DWords[NUM_DWORDS]; -}; - - - -// ------------------------------------------------------------------------ // -// CBitVecAccessor inlines. -// ------------------------------------------------------------------------ // - -inline CBitVecAccessor::CBitVecAccessor(unsigned long *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] &= ~(unsigned long)(1 << (m_iBit & 31)); -} - -inline CBitVecAccessor::operator unsigned long() -{ - return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); -} - - - -// ------------------------------------------------------------------------ // -// CBitVec inlines. -// ------------------------------------------------------------------------ // - -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) -{ - 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 int CBitVec::GetNumDWords() -{ - return NUM_DWORDS; -} - -template -inline unsigned long CBitVec::GetDWord(int i) -{ - assert(i >= 0 && i < NUM_DWORDS); - return m_DWords[i]; -} - - -template -inline void CBitVec::SetDWord(int i, unsigned long val) -{ - assert(i >= 0 && i < NUM_DWORDS); - m_DWords[i] = val; -} - - -#endif // BITVEC_H - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include + +class CBitVecAccessor +{ +public: + CBitVecAccessor(unsigned long *pDWords, int iBit); + + void operator=(int val); + operator unsigned long(); + +private: + unsigned long *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(); + unsigned long GetDWord(int i); + void SetDWord(int i, unsigned long val); + + int GetNumBits(); + +private: + + enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; + unsigned long m_DWords[NUM_DWORDS]; +}; + + + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(unsigned long *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] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator unsigned long() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + + +// ------------------------------------------------------------------------ // +// CBitVec inlines. +// ------------------------------------------------------------------------ // + +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) +{ + 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 int CBitVec::GetNumDWords() +{ + return NUM_DWORDS; +} + +template +inline unsigned long CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + + +template +inline void CBitVec::SetDWord(int i, unsigned long val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} + + +#endif // BITVEC_H + diff --git a/game_shared/vgui_checkbutton2.cpp b/game_shared/vgui_checkbutton2.cpp index 511853f8..b998a41d 100644 --- a/game_shared/vgui_checkbutton2.cpp +++ b/game_shared/vgui_checkbutton2.cpp @@ -1,197 +1,197 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include -#include "vgui_checkbutton2.h" -#include "vgui_loadtga.h" - - -#define EXTRA_X 5 - - -using namespace vgui; - - - -CCheckButton2::CCheckButton2() : - m_Label(""), - m_pChecked(NULL), - m_pUnchecked(NULL), - m_pHandler(NULL), - m_CheckboxPanel(NULL) -{ - m_bOwnImages = false; - m_bChecked = false; - m_pChecked = m_pUnchecked = NULL; - m_bCheckboxLeft = true; - - m_Label.setParent(this); - m_Label.setFgColor(255,255,255,0); - m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white - m_Label.addInputSignal(this); - - m_CheckboxPanel.setParent(this); - m_CheckboxPanel.addInputSignal(this); - - setPaintBackgroundEnabled(false); -} - - -CCheckButton2::~CCheckButton2() -{ - DeleteImages(); -} - - -void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) -{ - DeleteImages(); - - m_pChecked = vgui_LoadTGA(pChecked); - m_pUnchecked = vgui_LoadTGA(pUnchecked); - m_bOwnImages = true; - - SetupControls(); -} - - -void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) -{ - DeleteImages(); - - m_pChecked = pChecked; - m_pUnchecked = pUnchecked; - m_bOwnImages = false; - - SetupControls(); -} - - -void CCheckButton2::DeleteImages() -{ - if(m_bOwnImages) - { - delete m_pChecked; - delete m_pUnchecked; - } - - m_pChecked = NULL; - m_pUnchecked = NULL; - m_bOwnImages = false; - - SetupControls(); -} - - -void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) -{ - m_bCheckboxLeft = bLeftAlign; - SetupControls(); -} - - -bool CCheckButton2::GetCheckboxLeft() -{ - return m_bCheckboxLeft; -} - - -void CCheckButton2::SetText(char const *pText, ...) -{ - char str[512]; - - va_list marker; - va_start(marker, pText); - _vsnprintf(str, sizeof(str), pText, marker); - va_end(marker); - - m_Label.setText(str); - SetupControls(); -} - - -void CCheckButton2::SetTextColor(int r, int g, int b, int a) -{ - m_Label.setFgColor(r, g, b, a); - repaint(); -} - - -void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) -{ - m_pHandler = pHandler; -} - - -bool CCheckButton2::IsChecked() -{ - return m_bChecked; -} - - -void CCheckButton2::SetChecked(bool bChecked) -{ - m_bChecked = bChecked; - SetupControls(); -} - - -void CCheckButton2::internalMousePressed(MouseCode code) -{ - m_bChecked = !m_bChecked; - - if(m_pHandler) - m_pHandler->StateChanged(this); - - SetupControls(); -} - - -void CCheckButton2::SetupControls() -{ - // Initialize the checkbutton bitmap. - Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; - - Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; - int controlSizes[2][2]; - - controlSizes[0][0] = controlSizes[0][1] = 0; - if(pBitmap) - pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); - - m_CheckboxPanel.setImage(pBitmap); - m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); - - - // Get the label's size. - m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); - m_Label.setContentAlignment(Label::a_west); - - - // Position the controls. - int iLeftControl = !m_bCheckboxLeft; - int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; - controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); - controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); - - - // Fit this control to the sizes of the subcontrols. - setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); - repaint(); -} - - -void CCheckButton2::mousePressed(MouseCode code, Panel *panel) -{ - internalMousePressed(code); -} - - - - - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "vgui_checkbutton2.h" +#include "vgui_loadtga.h" + + +#define EXTRA_X 5 + + +using namespace vgui; + + + +CCheckButton2::CCheckButton2() : + m_Label(""), + m_pChecked(NULL), + m_pUnchecked(NULL), + m_pHandler(NULL), + m_CheckboxPanel(NULL) +{ + m_bOwnImages = false; + m_bChecked = false; + m_pChecked = m_pUnchecked = NULL; + m_bCheckboxLeft = true; + + m_Label.setParent(this); + m_Label.setFgColor(255,255,255,0); + m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white + m_Label.addInputSignal(this); + + m_CheckboxPanel.setParent(this); + m_CheckboxPanel.addInputSignal(this); + + setPaintBackgroundEnabled(false); +} + + +CCheckButton2::~CCheckButton2() +{ + DeleteImages(); +} + + +void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) +{ + DeleteImages(); + + m_pChecked = vgui_LoadTGA(pChecked); + m_pUnchecked = vgui_LoadTGA(pUnchecked); + m_bOwnImages = true; + + SetupControls(); +} + + +void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) +{ + DeleteImages(); + + m_pChecked = pChecked; + m_pUnchecked = pUnchecked; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::DeleteImages() +{ + if(m_bOwnImages) + { + delete m_pChecked; + delete m_pUnchecked; + } + + m_pChecked = NULL; + m_pUnchecked = NULL; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) +{ + m_bCheckboxLeft = bLeftAlign; + SetupControls(); +} + + +bool CCheckButton2::GetCheckboxLeft() +{ + return m_bCheckboxLeft; +} + + +void CCheckButton2::SetText(char const *pText, ...) +{ + char str[512]; + + va_list marker; + va_start(marker, pText); + _vsnprintf(str, sizeof(str), pText, marker); + va_end(marker); + + m_Label.setText(str); + SetupControls(); +} + + +void CCheckButton2::SetTextColor(int r, int g, int b, int a) +{ + m_Label.setFgColor(r, g, b, a); + repaint(); +} + + +void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) +{ + m_pHandler = pHandler; +} + + +bool CCheckButton2::IsChecked() +{ + return m_bChecked; +} + + +void CCheckButton2::SetChecked(bool bChecked) +{ + m_bChecked = bChecked; + SetupControls(); +} + + +void CCheckButton2::internalMousePressed(MouseCode code) +{ + m_bChecked = !m_bChecked; + + if(m_pHandler) + m_pHandler->StateChanged(this); + + SetupControls(); +} + + +void CCheckButton2::SetupControls() +{ + // Initialize the checkbutton bitmap. + Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; + + Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; + int controlSizes[2][2]; + + controlSizes[0][0] = controlSizes[0][1] = 0; + if(pBitmap) + pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); + + m_CheckboxPanel.setImage(pBitmap); + m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); + + + // Get the label's size. + m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); + m_Label.setContentAlignment(Label::a_west); + + + // Position the controls. + int iLeftControl = !m_bCheckboxLeft; + int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; + controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); + controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); + + + // Fit this control to the sizes of the subcontrols. + setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); + repaint(); +} + + +void CCheckButton2::mousePressed(MouseCode code, Panel *panel) +{ + internalMousePressed(code); +} + + + + + diff --git a/game_shared/vgui_checkbutton2.h b/game_shared/vgui_checkbutton2.h index 8f985d9f..ef8f82ae 100644 --- a/game_shared/vgui_checkbutton2.h +++ b/game_shared/vgui_checkbutton2.h @@ -1,101 +1,101 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_CHECKBUTTON2_H -#define VGUI_CHECKBUTTON2_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "vgui_label.h" -#include "vgui_imagepanel.h" -#include "vgui_defaultinputsignal.h" - - -namespace vgui -{ - - -class CCheckButton2; - - -class ICheckButton2Handler -{ -public: - virtual void StateChanged(CCheckButton2 *pButton) = 0; -}; - - -// VGUI checkbox class. -// - Provides access to the checkbox images. -// - Provides an easy callback mechanism for state changes. -// - Default background is invisible, and default text color is white. -class CCheckButton2 : public Panel, public CDefaultInputSignal -{ -public: - - CCheckButton2(); - ~CCheckButton2(); - - // Initialize the button with these. - void SetImages(char const *pChecked, char const *pUnchecked); - void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. - void DeleteImages(); - - // The checkbox can be to the left or the right of the text (default is left). - void SetCheckboxLeft(bool bLeftAlign); - bool GetCheckboxLeft(); - - // Set the label text. - void SetText(char const *pText, ...); - void SetTextColor(int r, int g, int b, int a); - - // You can register for change notification here. - void SetHandler(ICheckButton2Handler *pHandler); - - // Get/set the check state. - bool IsChecked(); - void SetChecked(bool bChecked); - - - -// Panel overrides. -public: - - virtual void internalMousePressed(MouseCode code); - - -protected: - - void SetupControls(); - - -// InputSignal overrides. -protected: - virtual void mousePressed(MouseCode code,Panel* panel); - - -public: - ICheckButton2Handler *m_pHandler; - - bool m_bCheckboxLeft; - Label m_Label; - ImagePanel m_CheckboxPanel; - - Image *m_pChecked; - Image *m_pUnchecked; - bool m_bOwnImages; - - bool m_bChecked; -}; - - -} - - -#endif // VGUI_CHECKBUTTON2_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_CHECKBUTTON2_H +#define VGUI_CHECKBUTTON2_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_label.h" +#include "vgui_imagepanel.h" +#include "vgui_defaultinputsignal.h" + + +namespace vgui +{ + + +class CCheckButton2; + + +class ICheckButton2Handler +{ +public: + virtual void StateChanged(CCheckButton2 *pButton) = 0; +}; + + +// VGUI checkbox class. +// - Provides access to the checkbox images. +// - Provides an easy callback mechanism for state changes. +// - Default background is invisible, and default text color is white. +class CCheckButton2 : public Panel, public CDefaultInputSignal +{ +public: + + CCheckButton2(); + ~CCheckButton2(); + + // Initialize the button with these. + void SetImages(char const *pChecked, char const *pUnchecked); + void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. + void DeleteImages(); + + // The checkbox can be to the left or the right of the text (default is left). + void SetCheckboxLeft(bool bLeftAlign); + bool GetCheckboxLeft(); + + // Set the label text. + void SetText(char const *pText, ...); + void SetTextColor(int r, int g, int b, int a); + + // You can register for change notification here. + void SetHandler(ICheckButton2Handler *pHandler); + + // Get/set the check state. + bool IsChecked(); + void SetChecked(bool bChecked); + + + +// Panel overrides. +public: + + virtual void internalMousePressed(MouseCode code); + + +protected: + + void SetupControls(); + + +// InputSignal overrides. +protected: + virtual void mousePressed(MouseCode code,Panel* panel); + + +public: + ICheckButton2Handler *m_pHandler; + + bool m_bCheckboxLeft; + Label m_Label; + ImagePanel m_CheckboxPanel; + + Image *m_pChecked; + Image *m_pUnchecked; + bool m_bOwnImages; + + bool m_bChecked; +}; + + +} + + +#endif // VGUI_CHECKBUTTON2_H diff --git a/game_shared/vgui_defaultinputsignal.h b/game_shared/vgui_defaultinputsignal.h index 94dae8df..835d92b0 100644 --- a/game_shared/vgui_defaultinputsignal.h +++ b/game_shared/vgui_defaultinputsignal.h @@ -1,39 +1,39 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_DEFAULTINPUTSIGNAL_H -#define VGUI_DEFAULTINPUTSIGNAL_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "vgui_inputsignal.h" - - -namespace vgui -{ - // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. - class CDefaultInputSignal : public vgui::InputSignal - { - public: - virtual void cursorMoved(int x,int y,Panel* panel) {} - virtual void cursorEntered(Panel* panel) {} - virtual void cursorExited(Panel* panel) {} - virtual void mousePressed(MouseCode code,Panel* panel) {} - virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} - virtual void mouseReleased(MouseCode code,Panel* panel) {} - virtual void mouseWheeled(int delta,Panel* panel) {} - virtual void keyPressed(KeyCode code,Panel* panel) {} - virtual void keyTyped(KeyCode code,Panel* panel) {} - virtual void keyReleased(KeyCode code,Panel* panel) {} - virtual void keyFocusTicked(Panel* panel) {} - }; -} - - -#endif // VGUI_DEFAULTINPUTSIGNAL_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_DEFAULTINPUTSIGNAL_H +#define VGUI_DEFAULTINPUTSIGNAL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_inputsignal.h" + + +namespace vgui +{ + // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. + class CDefaultInputSignal : public vgui::InputSignal + { + public: + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) {} + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseReleased(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} + }; +} + + +#endif // VGUI_DEFAULTINPUTSIGNAL_H diff --git a/game_shared/vgui_grid.cpp b/game_shared/vgui_grid.cpp index 00e9d699..5a1af15e 100644 --- a/game_shared/vgui_grid.cpp +++ b/game_shared/vgui_grid.cpp @@ -1,398 +1,398 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include "vgui_grid.h" - - -using namespace vgui; - - -#define AssertCheck(expr, msg) \ - if(!(expr))\ - {\ - assert(!msg);\ - return 0;\ - } - - - -// ------------------------------------------------------------------------------ // -// CGrid::CGridEntry. -// ------------------------------------------------------------------------------ // - -CGrid::CGridEntry::CGridEntry() -{ - m_pPanel = NULL; - m_bUnderline = false; -} - -CGrid::CGridEntry::~CGridEntry() -{ -} - - -// ------------------------------------------------------------------------------ // -// CGrid. -// ------------------------------------------------------------------------------ // - -CGrid::CGrid() -{ - Clear(); -} - - -CGrid::~CGrid() -{ - Term(); -} - - -bool CGrid::SetDimensions(int xCols, int yRows) -{ - Term(); - - m_GridEntries = new CGridEntry[xCols * yRows]; - m_Widths = new int[xCols*2 + yRows*2]; - m_Heights = m_Widths + xCols; - m_ColOffsets = m_Heights + yRows; - m_RowOffsets = m_ColOffsets + xCols; - - if(!m_GridEntries || !m_Widths) - { - Term(); - return false; - } - - memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); - - m_xCols = xCols; - m_yRows = yRows; - return true; -} - - -void CGrid::Term() -{ - delete [] m_GridEntries; - delete [] m_Widths; - Clear(); -} - - -Panel* CGrid::GetEntry(int x, int y) -{ - return GridEntry(x, y)->m_pPanel; -} - - -bool CGrid::SetEntry(int x, int y, Panel *pPanel) -{ - CGridEntry *pEntry = GridEntry(x, y); - if(!pEntry) - return false; - - if(pEntry->m_pPanel) - pEntry->m_pPanel->setParent(NULL); - - pEntry->m_pPanel = pPanel; - if(pPanel) - pPanel->setParent(this); - - m_bDirty = true; - return true; -} - - -int CGrid::GetXSpacing() -{ - return m_xSpacing; -} - - -int CGrid::GetYSpacing() -{ - return m_ySpacing; -} - - -void CGrid::SetSpacing(int xSpacing, int ySpacing) -{ - if(xSpacing != m_xSpacing) - { - m_xSpacing = xSpacing; - CalcColOffsets(0); - m_bDirty = true; - } - - if(ySpacing != m_ySpacing) - { - m_ySpacing = ySpacing; - CalcRowOffsets(0); - m_bDirty = true; - } -} - - -bool CGrid::SetColumnWidth(int iColumn, int width) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); - m_Widths[iColumn] = width; - CalcColOffsets(iColumn+1); - m_bDirty = true; - return true; -} - - -bool CGrid::SetRowHeight(int iRow, int height) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); - m_Heights[iRow] = height; - CalcRowOffsets(iRow+1); - m_bDirty = true; - return true; -} - - -int CGrid::GetColumnWidth(int iColumn) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); - return m_Widths[iColumn]; -} - - -int CGrid::GetRowHeight(int iRow) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); - return m_Heights[iRow]; -} - - -int CGrid::CalcFitColumnWidth(int iColumn) -{ - AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); - - int maxSize = 0; - for(int i=0; i < m_yRows; i++) - { - Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; - if(!pPanel) - continue; - - int w, h; - pPanel->getSize(w,h); - if(w > maxSize) - maxSize = w; - } - - return maxSize; -} - - -int CGrid::CalcFitRowHeight(int iRow) -{ - AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); - - int maxSize = 0; - for(int i=0; i < m_xCols; i++) - { - Panel *pPanel = GridEntry(i, iRow)->m_pPanel; - if(!pPanel) - continue; - - int w, h; - pPanel->getSize(w,h); - if(h > maxSize) - maxSize = h; - } - - return maxSize; -} - - -void CGrid::AutoSetRowHeights() -{ - for(int i=0; i < m_yRows; i++) - SetRowHeight(i, CalcFitRowHeight(i)); -} - - -bool CGrid::GetEntryBox( - int col, int row, int &x, int &y, int &w, int &h) -{ - AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); - - x = m_ColOffsets[col]; - w = m_Widths[col]; - - y = m_RowOffsets[row]; - h = m_Heights[row]; - return true; -} - - -bool CGrid::CopyColumnWidths(CGrid *pOther) -{ - if(!pOther || pOther->m_xCols != m_xCols) - return false; - - for(int i=0; i < m_xCols; i++) - m_Widths[i] = pOther->m_Widths[i]; - - CalcColOffsets(0); - m_bDirty = true; - return true; -} - - -void CGrid::RepositionContents() -{ - for(int x=0; x < m_xCols; x++) - { - for(int y=0; y < m_yRows; y++) - { - Panel *pPanel = GridEntry(x,y)->m_pPanel; - if(!pPanel) - continue; - - pPanel->setBounds( - m_ColOffsets[x], - m_RowOffsets[y], - m_Widths[x], - m_Heights[y]); - } - } - - m_bDirty = false; -} - - -int CGrid::CalcDrawHeight() -{ - if(m_yRows > 0) - { - return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; - } - else - { - return 0; - } -} - - -void CGrid::paint() -{ - if(m_bDirty) - RepositionContents(); - - Panel::paint(); - - // walk the grid looking for underlined rows - int x = 0, y = 0; - for (int row = 0; row < m_yRows; row++) - { - CGridEntry *cell = GridEntry(0, row); - - y += cell->m_pPanel->getTall() + m_ySpacing; - if (cell->m_bUnderline) - { - drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); - drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); - } - } -} - -void CGrid::paintBackground() -{ - Panel::paintBackground(); -} - -//----------------------------------------------------------------------------- -// Purpose: sets underline color for a particular row -//----------------------------------------------------------------------------- -void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) -{ - CGridEntry *cell = GridEntry(0, row); - cell->m_bUnderline = enabled; - if (enabled) - { - cell->m_iUnderlineOffset = offset; - cell->m_UnderlineColor[0] = r; - cell->m_UnderlineColor[1] = g; - cell->m_UnderlineColor[2] = b; - cell->m_UnderlineColor[3] = a; - } -} - -void CGrid::Clear() -{ - m_xCols = m_yRows = 0; - m_Widths = NULL; - m_GridEntries = NULL; - m_xSpacing = m_ySpacing = 0; - m_bDirty = false; -} - - -CGrid::CGridEntry* CGrid::GridEntry(int x, int y) -{ - AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); - return &m_GridEntries[y*m_xCols + x]; -} - - -void CGrid::CalcColOffsets(int iStart) -{ - int cur = m_xSpacing; - if(iStart != 0) - cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; - - for(int i=iStart; i < m_xCols; i++) - { - m_ColOffsets[i] = cur; - cur += m_Widths[i] + m_xSpacing; - } -} - - -void CGrid::CalcRowOffsets(int iStart) -{ - int cur = m_ySpacing; - if(iStart != 0) - cur += m_RowOffsets[iStart-1]; - - for(int i=iStart; i < m_yRows; i++) - { - m_RowOffsets[i] = cur; - cur += m_Heights[i] + m_ySpacing; - } -} - -bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) -{ - row = -1; col = -1; - for(int x=0; x < m_xCols; x++) - { - for(int y=0; y < m_yRows; y++) - { - Panel *pPanel = GridEntry(x,y)->m_pPanel; - if (!pPanel) - continue; - - if (pPanel->isWithin(worldX, worldY)) - { - col = x; - row = y; - return true; - } - } - } - - return false; -} - - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "vgui_grid.h" + + +using namespace vgui; + + +#define AssertCheck(expr, msg) \ + if(!(expr))\ + {\ + assert(!msg);\ + return 0;\ + } + + + +// ------------------------------------------------------------------------------ // +// CGrid::CGridEntry. +// ------------------------------------------------------------------------------ // + +CGrid::CGridEntry::CGridEntry() +{ + m_pPanel = NULL; + m_bUnderline = false; +} + +CGrid::CGridEntry::~CGridEntry() +{ +} + + +// ------------------------------------------------------------------------------ // +// CGrid. +// ------------------------------------------------------------------------------ // + +CGrid::CGrid() +{ + Clear(); +} + + +CGrid::~CGrid() +{ + Term(); +} + + +bool CGrid::SetDimensions(int xCols, int yRows) +{ + Term(); + + m_GridEntries = new CGridEntry[xCols * yRows]; + m_Widths = new int[xCols*2 + yRows*2]; + m_Heights = m_Widths + xCols; + m_ColOffsets = m_Heights + yRows; + m_RowOffsets = m_ColOffsets + xCols; + + if(!m_GridEntries || !m_Widths) + { + Term(); + return false; + } + + memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); + + m_xCols = xCols; + m_yRows = yRows; + return true; +} + + +void CGrid::Term() +{ + delete [] m_GridEntries; + delete [] m_Widths; + Clear(); +} + + +Panel* CGrid::GetEntry(int x, int y) +{ + return GridEntry(x, y)->m_pPanel; +} + + +bool CGrid::SetEntry(int x, int y, Panel *pPanel) +{ + CGridEntry *pEntry = GridEntry(x, y); + if(!pEntry) + return false; + + if(pEntry->m_pPanel) + pEntry->m_pPanel->setParent(NULL); + + pEntry->m_pPanel = pPanel; + if(pPanel) + pPanel->setParent(this); + + m_bDirty = true; + return true; +} + + +int CGrid::GetXSpacing() +{ + return m_xSpacing; +} + + +int CGrid::GetYSpacing() +{ + return m_ySpacing; +} + + +void CGrid::SetSpacing(int xSpacing, int ySpacing) +{ + if(xSpacing != m_xSpacing) + { + m_xSpacing = xSpacing; + CalcColOffsets(0); + m_bDirty = true; + } + + if(ySpacing != m_ySpacing) + { + m_ySpacing = ySpacing; + CalcRowOffsets(0); + m_bDirty = true; + } +} + + +bool CGrid::SetColumnWidth(int iColumn, int width) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); + m_Widths[iColumn] = width; + CalcColOffsets(iColumn+1); + m_bDirty = true; + return true; +} + + +bool CGrid::SetRowHeight(int iRow, int height) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); + m_Heights[iRow] = height; + CalcRowOffsets(iRow+1); + m_bDirty = true; + return true; +} + + +int CGrid::GetColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); + return m_Widths[iColumn]; +} + + +int CGrid::GetRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); + return m_Heights[iRow]; +} + + +int CGrid::CalcFitColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_yRows; i++) + { + Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(w > maxSize) + maxSize = w; + } + + return maxSize; +} + + +int CGrid::CalcFitRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_xCols; i++) + { + Panel *pPanel = GridEntry(i, iRow)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(h > maxSize) + maxSize = h; + } + + return maxSize; +} + + +void CGrid::AutoSetRowHeights() +{ + for(int i=0; i < m_yRows; i++) + SetRowHeight(i, CalcFitRowHeight(i)); +} + + +bool CGrid::GetEntryBox( + int col, int row, int &x, int &y, int &w, int &h) +{ + AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); + + x = m_ColOffsets[col]; + w = m_Widths[col]; + + y = m_RowOffsets[row]; + h = m_Heights[row]; + return true; +} + + +bool CGrid::CopyColumnWidths(CGrid *pOther) +{ + if(!pOther || pOther->m_xCols != m_xCols) + return false; + + for(int i=0; i < m_xCols; i++) + m_Widths[i] = pOther->m_Widths[i]; + + CalcColOffsets(0); + m_bDirty = true; + return true; +} + + +void CGrid::RepositionContents() +{ + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if(!pPanel) + continue; + + pPanel->setBounds( + m_ColOffsets[x], + m_RowOffsets[y], + m_Widths[x], + m_Heights[y]); + } + } + + m_bDirty = false; +} + + +int CGrid::CalcDrawHeight() +{ + if(m_yRows > 0) + { + return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; + } + else + { + return 0; + } +} + + +void CGrid::paint() +{ + if(m_bDirty) + RepositionContents(); + + Panel::paint(); + + // walk the grid looking for underlined rows + int x = 0, y = 0; + for (int row = 0; row < m_yRows; row++) + { + CGridEntry *cell = GridEntry(0, row); + + y += cell->m_pPanel->getTall() + m_ySpacing; + if (cell->m_bUnderline) + { + drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); + drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); + } + } +} + +void CGrid::paintBackground() +{ + Panel::paintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets underline color for a particular row +//----------------------------------------------------------------------------- +void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) +{ + CGridEntry *cell = GridEntry(0, row); + cell->m_bUnderline = enabled; + if (enabled) + { + cell->m_iUnderlineOffset = offset; + cell->m_UnderlineColor[0] = r; + cell->m_UnderlineColor[1] = g; + cell->m_UnderlineColor[2] = b; + cell->m_UnderlineColor[3] = a; + } +} + +void CGrid::Clear() +{ + m_xCols = m_yRows = 0; + m_Widths = NULL; + m_GridEntries = NULL; + m_xSpacing = m_ySpacing = 0; + m_bDirty = false; +} + + +CGrid::CGridEntry* CGrid::GridEntry(int x, int y) +{ + AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); + return &m_GridEntries[y*m_xCols + x]; +} + + +void CGrid::CalcColOffsets(int iStart) +{ + int cur = m_xSpacing; + if(iStart != 0) + cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; + + for(int i=iStart; i < m_xCols; i++) + { + m_ColOffsets[i] = cur; + cur += m_Widths[i] + m_xSpacing; + } +} + + +void CGrid::CalcRowOffsets(int iStart) +{ + int cur = m_ySpacing; + if(iStart != 0) + cur += m_RowOffsets[iStart-1]; + + for(int i=iStart; i < m_yRows; i++) + { + m_RowOffsets[i] = cur; + cur += m_Heights[i] + m_ySpacing; + } +} + +bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) +{ + row = -1; col = -1; + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if (!pPanel) + continue; + + if (pPanel->isWithin(worldX, worldY)) + { + col = x; + row = y; + return true; + } + } + } + + return false; +} + + diff --git a/game_shared/vgui_grid.h b/game_shared/vgui_grid.h index 472f5094..eaf8e1d7 100644 --- a/game_shared/vgui_grid.h +++ b/game_shared/vgui_grid.h @@ -1,122 +1,122 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_GRID_H -#define VGUI_GRID_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "vgui_panel.h" - - -namespace vgui -{ - -// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and -// configure and fill the panels however you want. -// To use this control, call SetDimensions, SetSpacing and fill the controls. -class CGrid : public Panel -{ -public: - CGrid(); - virtual ~CGrid(); - - bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. - void Term(); - - Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. - bool SetEntry(int x, int y, Panel *pPanel); - - int GetXSpacing(); - int GetYSpacing(); - void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. - - bool SetColumnWidth(int iColumn, int width); // Set a column's width. - bool SetRowHeight(int iRow, int height); // Set a row's height. - - int GetColumnWidth(int iColumn); - int GetRowHeight(int iRow); - - int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. - int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. - - int CalcDrawHeight(); // Returns how many pixels high the grid control should be - // for all of its contents to be visible (based on its row heights - // and y spacing). - - void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. - - bool GetEntryBox( // Returns the bounding box for the specified entry. - int col, int row, int &x, int &y, int &w, int &h); - - bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the - // column count is different. - - void RepositionContents(); // Sets the size and position of all the grid entries based - // on current spacings and row/column widths. - // You usually only want to call this while setting up the control - // if you want to get the position or dimensions of the child - // controls. This will set them. - - void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row - - // returns the true if found, false otherwise - bool getCellAtPoint(int worldX, int worldY, int &row, int &col); - -// Panel overrides. -public: - - virtual void paint(); - virtual void paintBackground(); - -protected: - - class CGridEntry - { - public: - CGridEntry(); - ~CGridEntry(); - - Panel *m_pPanel; - - bool m_bUnderline; - short m_UnderlineColor[4]; - int m_iUnderlineOffset; - }; - - void Clear(); - CGridEntry* GridEntry(int x, int y); - - void CalcColOffsets(int iStart); - void CalcRowOffsets(int iStart); - - -protected: - - bool m_bDirty; // Set when controls will need to be repositioned. - - int m_xCols; - int m_yRows; - - int m_xSpacing; - int m_ySpacing; - - int *m_Widths; - int *m_Heights; - int *m_ColOffsets; - int *m_RowOffsets; - - CGridEntry *m_GridEntries; - -}; - -}; - - -#endif // VGUI_GRID_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_GRID_H +#define VGUI_GRID_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" + + +namespace vgui +{ + +// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and +// configure and fill the panels however you want. +// To use this control, call SetDimensions, SetSpacing and fill the controls. +class CGrid : public Panel +{ +public: + CGrid(); + virtual ~CGrid(); + + bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. + void Term(); + + Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. + bool SetEntry(int x, int y, Panel *pPanel); + + int GetXSpacing(); + int GetYSpacing(); + void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. + + bool SetColumnWidth(int iColumn, int width); // Set a column's width. + bool SetRowHeight(int iRow, int height); // Set a row's height. + + int GetColumnWidth(int iColumn); + int GetRowHeight(int iRow); + + int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. + int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. + + int CalcDrawHeight(); // Returns how many pixels high the grid control should be + // for all of its contents to be visible (based on its row heights + // and y spacing). + + void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. + + bool GetEntryBox( // Returns the bounding box for the specified entry. + int col, int row, int &x, int &y, int &w, int &h); + + bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the + // column count is different. + + void RepositionContents(); // Sets the size and position of all the grid entries based + // on current spacings and row/column widths. + // You usually only want to call this while setting up the control + // if you want to get the position or dimensions of the child + // controls. This will set them. + + void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row + + // returns the true if found, false otherwise + bool getCellAtPoint(int worldX, int worldY, int &row, int &col); + +// Panel overrides. +public: + + virtual void paint(); + virtual void paintBackground(); + +protected: + + class CGridEntry + { + public: + CGridEntry(); + ~CGridEntry(); + + Panel *m_pPanel; + + bool m_bUnderline; + short m_UnderlineColor[4]; + int m_iUnderlineOffset; + }; + + void Clear(); + CGridEntry* GridEntry(int x, int y); + + void CalcColOffsets(int iStart); + void CalcRowOffsets(int iStart); + + +protected: + + bool m_bDirty; // Set when controls will need to be repositioned. + + int m_xCols; + int m_yRows; + + int m_xSpacing; + int m_ySpacing; + + int *m_Widths; + int *m_Heights; + int *m_ColOffsets; + int *m_RowOffsets; + + CGridEntry *m_GridEntries; + +}; + +}; + + +#endif // VGUI_GRID_H diff --git a/game_shared/vgui_helpers.cpp b/game_shared/vgui_helpers.cpp index fbcfeb5e..c2694759 100644 --- a/game_shared/vgui_helpers.cpp +++ b/game_shared/vgui_helpers.cpp @@ -1,45 +1,45 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "vgui_helpers.h" - - -using namespace vgui; - - -void AlignPanel(Panel *pChild, Panel *pParent, int alignment) -{ - int w, h, cw, ch; - pParent->getSize(w, h); - pChild->getSize(cw, ch); - - int xCenter = (w - cw) / 2; - int yCenter = (h - ch) / 2; - - if(alignment == Label::a_west) - pChild->setPos(0, yCenter); - else if(alignment == Label::a_northwest) - pChild->setPos(0,0); - else if(alignment == Label::a_north) - pChild->setPos(xCenter, 0); - else if(alignment == Label::a_northeast) - pChild->setPos(w - cw, 0); - else if(alignment == Label::a_east) - pChild->setPos(w - cw, yCenter); - else if(alignment == Label::a_southeast) - pChild->setPos(w - cw, h - ch); - else if(alignment == Label::a_south) - pChild->setPos(xCenter, h - ch); - else if(alignment == Label::a_southwest) - pChild->setPos(0, h - ch); - else if(alignment == Label::a_center) - pChild->setPos(xCenter, yCenter); -} - - - - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_helpers.h" + + +using namespace vgui; + + +void AlignPanel(Panel *pChild, Panel *pParent, int alignment) +{ + int w, h, cw, ch; + pParent->getSize(w, h); + pChild->getSize(cw, ch); + + int xCenter = (w - cw) / 2; + int yCenter = (h - ch) / 2; + + if(alignment == Label::a_west) + pChild->setPos(0, yCenter); + else if(alignment == Label::a_northwest) + pChild->setPos(0,0); + else if(alignment == Label::a_north) + pChild->setPos(xCenter, 0); + else if(alignment == Label::a_northeast) + pChild->setPos(w - cw, 0); + else if(alignment == Label::a_east) + pChild->setPos(w - cw, yCenter); + else if(alignment == Label::a_southeast) + pChild->setPos(w - cw, h - ch); + else if(alignment == Label::a_south) + pChild->setPos(xCenter, h - ch); + else if(alignment == Label::a_southwest) + pChild->setPos(0, h - ch); + else if(alignment == Label::a_center) + pChild->setPos(xCenter, yCenter); +} + + + + diff --git a/game_shared/vgui_helpers.h b/game_shared/vgui_helpers.h index f9ee45e8..09e82667 100644 --- a/game_shared/vgui_helpers.h +++ b/game_shared/vgui_helpers.h @@ -1,31 +1,31 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_HELPERS_H -#define VGUI_HELPERS_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "vgui_panel.h" -#include "vgui_label.h" - - -inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} -inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} -inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} -inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} -inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} -inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} - -// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. -void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); - - -#endif // VGUI_HELPERS_H - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_HELPERS_H +#define VGUI_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" +#include "vgui_label.h" + + +inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} +inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} +inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} +inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} +inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} +inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} + +// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. +void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); + + +#endif // VGUI_HELPERS_H + diff --git a/game_shared/vgui_listbox.cpp b/game_shared/vgui_listbox.cpp index 972091e0..6986d909 100644 --- a/game_shared/vgui_listbox.cpp +++ b/game_shared/vgui_listbox.cpp @@ -1,207 +1,207 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "vgui_listbox.h" - - - -using namespace vgui; - - -CListBox::CListBox() : Panel(0, 0, 0, 0), - m_ItemsPanel(0,0,0,0), - m_ScrollBar(0, 0, 0, 0, true), - m_Slider(0, 0, 10, 40, true) -{ - m_Signal.m_pListBox = this; - - m_ItemsPanel.setParent(this); - m_ItemsPanel.setBgColor(0,0,0,255); - - m_Slider.setRangeWindow(50); - m_Slider.setRangeWindowEnabled(true); - - m_ScrollBar.setParent(this); - m_ScrollBar.addIntChangeSignal(&m_Signal); - m_ScrollBar.setSlider(&m_Slider); - m_ScrollBar.setButtonPressedScrollValue(1); - - m_Items.m_pNext = m_Items.m_pPrev = &m_Items; - m_ItemOffset = 0; - m_iScrollMax = -1; -} - -CListBox::~CListBox() -{ - Term(); -} - -void CListBox::Init() -{ - Term(); -} - -void CListBox::Term() -{ - m_ItemOffset = 0; - - // Free the LBItems. - LBItem *pNext; - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) - { - pItem->m_pPanel->setParent(NULL); // detach the panel from us - pNext = pItem->m_pNext; - delete pItem; - } - m_Items.m_pPrev = m_Items.m_pNext = &m_Items; -} - -void CListBox::AddItem(Panel* panel) -{ - // Add the item. - LBItem *pItem = new LBItem; - if(!pItem) - return; - - pItem->m_pPanel = panel; - pItem->m_pPanel->setParent(&m_ItemsPanel); - - pItem->m_pPrev = m_Items.m_pPrev; - pItem->m_pNext = &m_Items; - pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; - - m_ScrollBar.setRange(0, GetScrollMax()); - m_Slider.setRangeWindow(50); - m_Slider.setRangeWindowEnabled(true); - - InternalLayout(); -} - -int CListBox::GetNumItems() -{ - int count=0; - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) - ++count; - - return count; -} - -int CListBox::GetItemWidth() -{ - int wide, tall; - m_ItemsPanel.getSize(wide, tall); - return wide; -} - -int CListBox::GetScrollPos() -{ - return m_ItemOffset; -} - -void CListBox::SetScrollPos(int pos) -{ - int maxItems = GetScrollMax(); - if(maxItems < 0) - return; - - m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); - InternalLayout(); -} - -void CListBox::setPos(int x, int y) -{ - Panel::setPos(x, y); - InternalLayout(); -} - -void CListBox::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - InternalLayout(); -} - -void CListBox::setPixelScroll(int value) -{ - m_ItemOffset = m_ScrollBar.getValue(); - InternalLayout(); -} - -void CListBox::InternalLayout() -{ - int x, y, wide, tall; - getBounds(x, y, wide, tall); - - // Reposition the main panel and the scrollbar. - m_ItemsPanel.setBounds(0, 0, wide-15, tall); - m_ScrollBar.setBounds(wide-15, 0, 15, tall); - - bool bNeedScrollbar = false; - - // Reposition the items. - int curItem = 0; - int curY = 0; - int maxItem = GetScrollMax(); - for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) - { - if(curItem < m_ItemOffset) - { - pItem->m_pPanel->setVisible(false); - bNeedScrollbar = true; - } - else if (curItem >= maxItem) - { - // item is past the end of the items we care about - pItem->m_pPanel->setVisible(false); - } - else - { - pItem->m_pPanel->setVisible(true); - - int itemWidth, itemHeight; - pItem->m_pPanel->getSize(itemWidth, itemHeight); - - // Don't change the item's height but change its width to fit the listbox. - pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); - - curY += itemHeight; - - if (curY > tall) - { - bNeedScrollbar = true; - } - } - - ++curItem; - } - - m_ScrollBar.setVisible(bNeedScrollbar); - - repaint(); -} - -void CListBox::paintBackground() -{ -} - -void CListBox::SetScrollRange(int maxScroll) -{ - m_iScrollMax = maxScroll; - m_ScrollBar.setRange(0, maxScroll); - InternalLayout(); -} - -int CListBox::GetScrollMax() -{ - if (m_iScrollMax < 0) - { - return GetNumItems() - 1; - } - - return m_iScrollMax; -} - - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_listbox.h" + + + +using namespace vgui; + + +CListBox::CListBox() : Panel(0, 0, 0, 0), + m_ItemsPanel(0,0,0,0), + m_ScrollBar(0, 0, 0, 0, true), + m_Slider(0, 0, 10, 40, true) +{ + m_Signal.m_pListBox = this; + + m_ItemsPanel.setParent(this); + m_ItemsPanel.setBgColor(0,0,0,255); + + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + m_ScrollBar.setParent(this); + m_ScrollBar.addIntChangeSignal(&m_Signal); + m_ScrollBar.setSlider(&m_Slider); + m_ScrollBar.setButtonPressedScrollValue(1); + + m_Items.m_pNext = m_Items.m_pPrev = &m_Items; + m_ItemOffset = 0; + m_iScrollMax = -1; +} + +CListBox::~CListBox() +{ + Term(); +} + +void CListBox::Init() +{ + Term(); +} + +void CListBox::Term() +{ + m_ItemOffset = 0; + + // Free the LBItems. + LBItem *pNext; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) + { + pItem->m_pPanel->setParent(NULL); // detach the panel from us + pNext = pItem->m_pNext; + delete pItem; + } + m_Items.m_pPrev = m_Items.m_pNext = &m_Items; +} + +void CListBox::AddItem(Panel* panel) +{ + // Add the item. + LBItem *pItem = new LBItem; + if(!pItem) + return; + + pItem->m_pPanel = panel; + pItem->m_pPanel->setParent(&m_ItemsPanel); + + pItem->m_pPrev = m_Items.m_pPrev; + pItem->m_pNext = &m_Items; + pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; + + m_ScrollBar.setRange(0, GetScrollMax()); + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + InternalLayout(); +} + +int CListBox::GetNumItems() +{ + int count=0; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + ++count; + + return count; +} + +int CListBox::GetItemWidth() +{ + int wide, tall; + m_ItemsPanel.getSize(wide, tall); + return wide; +} + +int CListBox::GetScrollPos() +{ + return m_ItemOffset; +} + +void CListBox::SetScrollPos(int pos) +{ + int maxItems = GetScrollMax(); + if(maxItems < 0) + return; + + m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); + InternalLayout(); +} + +void CListBox::setPos(int x, int y) +{ + Panel::setPos(x, y); + InternalLayout(); +} + +void CListBox::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + InternalLayout(); +} + +void CListBox::setPixelScroll(int value) +{ + m_ItemOffset = m_ScrollBar.getValue(); + InternalLayout(); +} + +void CListBox::InternalLayout() +{ + int x, y, wide, tall; + getBounds(x, y, wide, tall); + + // Reposition the main panel and the scrollbar. + m_ItemsPanel.setBounds(0, 0, wide-15, tall); + m_ScrollBar.setBounds(wide-15, 0, 15, tall); + + bool bNeedScrollbar = false; + + // Reposition the items. + int curItem = 0; + int curY = 0; + int maxItem = GetScrollMax(); + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + { + if(curItem < m_ItemOffset) + { + pItem->m_pPanel->setVisible(false); + bNeedScrollbar = true; + } + else if (curItem >= maxItem) + { + // item is past the end of the items we care about + pItem->m_pPanel->setVisible(false); + } + else + { + pItem->m_pPanel->setVisible(true); + + int itemWidth, itemHeight; + pItem->m_pPanel->getSize(itemWidth, itemHeight); + + // Don't change the item's height but change its width to fit the listbox. + pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); + + curY += itemHeight; + + if (curY > tall) + { + bNeedScrollbar = true; + } + } + + ++curItem; + } + + m_ScrollBar.setVisible(bNeedScrollbar); + + repaint(); +} + +void CListBox::paintBackground() +{ +} + +void CListBox::SetScrollRange(int maxScroll) +{ + m_iScrollMax = maxScroll; + m_ScrollBar.setRange(0, maxScroll); + InternalLayout(); +} + +int CListBox::GetScrollMax() +{ + if (m_iScrollMax < 0) + { + return GetNumItems() - 1; + } + + return m_iScrollMax; +} + + diff --git a/game_shared/vgui_listbox.h b/game_shared/vgui_listbox.h index a48acef4..7191f827 100644 --- a/game_shared/vgui_listbox.h +++ b/game_shared/vgui_listbox.h @@ -1,115 +1,115 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_LISTBOX_H -#define VOICE_LISTBOX_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "VGUI_Panel.h" -#include "VGUI_IntChangeSignal.h" - -#include "VGUI_Slider2.h" -#include "VGUI_ScrollBar2.h" - - -namespace vgui -{ - -// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: -// - This listbox clips its child items to its rectangle. -// - You can access things like the scrollbar and find out the item width. -// - The scrollbar scrolls one element at a time and the range is correct. - -// Note: this listbox does not provide notification when items are -class CListBox : public Panel -{ -public: - - CListBox(); - ~CListBox(); - - void Init(); - void Term(); - - // Add an item to the listbox. This automatically sets the item's parent to the listbox - // and resizes the item's width to fit within the listbox. - void AddItem(Panel *pPanel); - - // Get the number of items currently in the listbox. - int GetNumItems(); - - // Get the width that listbox items will be set to (this changes if you resize the listbox). - int GetItemWidth(); - - // Get/set the scrollbar position (position says which element is at the top of the listbox). - int GetScrollPos(); - void SetScrollPos(int pos); - - // sets the last item the listbox should scroll to - // scroll to GetNumItems() if not set - void SetScrollRange(int maxScroll); - - // returns the maximum value the scrollbar can scroll to - int GetScrollMax(); - -// vgui overrides. -public: - - virtual void setPos(int x, int y); - virtual void setSize(int wide,int tall); - virtual void setPixelScroll(int value); - virtual void paintBackground(); - - -protected: - - class LBItem - { - public: - Panel *m_pPanel; - LBItem *m_pPrev, *m_pNext; - }; - - class ListBoxSignal : public IntChangeSignal - { - public: - void intChanged(int value,Panel* panel) - { - m_pListBox->setPixelScroll(-value); - } - - vgui::CListBox *m_pListBox; - }; - - -protected: - - void InternalLayout(); - - -protected: - - // All the items.. - LBItem m_Items; - - Panel m_ItemsPanel; - - int m_ItemOffset; // where we're scrolled to - Slider2 m_Slider; - ScrollBar2 m_ScrollBar; - ListBoxSignal m_Signal; - - int m_iScrollMax; -}; - -} - - -#endif // VOICE_LISTBOX_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_LISTBOX_H +#define VOICE_LISTBOX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" +#include "VGUI_IntChangeSignal.h" + +#include "VGUI_Slider2.h" +#include "VGUI_ScrollBar2.h" + + +namespace vgui +{ + +// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: +// - This listbox clips its child items to its rectangle. +// - You can access things like the scrollbar and find out the item width. +// - The scrollbar scrolls one element at a time and the range is correct. + +// Note: this listbox does not provide notification when items are +class CListBox : public Panel +{ +public: + + CListBox(); + ~CListBox(); + + void Init(); + void Term(); + + // Add an item to the listbox. This automatically sets the item's parent to the listbox + // and resizes the item's width to fit within the listbox. + void AddItem(Panel *pPanel); + + // Get the number of items currently in the listbox. + int GetNumItems(); + + // Get the width that listbox items will be set to (this changes if you resize the listbox). + int GetItemWidth(); + + // Get/set the scrollbar position (position says which element is at the top of the listbox). + int GetScrollPos(); + void SetScrollPos(int pos); + + // sets the last item the listbox should scroll to + // scroll to GetNumItems() if not set + void SetScrollRange(int maxScroll); + + // returns the maximum value the scrollbar can scroll to + int GetScrollMax(); + +// vgui overrides. +public: + + virtual void setPos(int x, int y); + virtual void setSize(int wide,int tall); + virtual void setPixelScroll(int value); + virtual void paintBackground(); + + +protected: + + class LBItem + { + public: + Panel *m_pPanel; + LBItem *m_pPrev, *m_pNext; + }; + + class ListBoxSignal : public IntChangeSignal + { + public: + void intChanged(int value,Panel* panel) + { + m_pListBox->setPixelScroll(-value); + } + + vgui::CListBox *m_pListBox; + }; + + +protected: + + void InternalLayout(); + + +protected: + + // All the items.. + LBItem m_Items; + + Panel m_ItemsPanel; + + int m_ItemOffset; // where we're scrolled to + Slider2 m_Slider; + ScrollBar2 m_ScrollBar; + ListBoxSignal m_Signal; + + int m_iScrollMax; +}; + +} + + +#endif // VOICE_LISTBOX_H diff --git a/game_shared/vgui_loadtga.cpp b/game_shared/vgui_loadtga.cpp index d7e1f5e9..5c0d9189 100644 --- a/game_shared/vgui_loadtga.cpp +++ b/game_shared/vgui_loadtga.cpp @@ -1,93 +1,93 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "../cl_dll/wrect.h" -#include "../cl_dll/cl_dll.h" -#include "vgui.h" -#include "vgui_loadtga.h" -#include "vgui_inputstream.h" - - -// ---------------------------------------------------------------------- // -// Helper class for loading tga files. -// ---------------------------------------------------------------------- // -class MemoryInputStream : public vgui::InputStream -{ -public: - MemoryInputStream() - { - m_pData = NULL; - m_DataLen = m_ReadPos = 0; - } - - virtual void seekStart(bool& success) {m_ReadPos=0; success=true;} - virtual void seekRelative(int count,bool& success) {m_ReadPos+=count; success=true;} - virtual void seekEnd(bool& success) {m_ReadPos=m_DataLen; success=true;} - virtual int getAvailable(bool& success) {success=false; return 0;} // This is what vgui does for files... - - virtual uchar readUChar(bool& success) - { - if(m_ReadPos>=0 && m_ReadPos=0 && m_ReadPos -#include -#include -#include - -using namespace vgui; - - -namespace -{ -class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal -{ -public: - FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) - { - _scrollBar=scrollBar; - } - virtual void intChanged(int value,Panel* panel) - { - _scrollBar->fireIntChangeSignal(); - } -protected: - ScrollBar2* _scrollBar; -}; - -class FooDefaultButtonSignal : public ActionSignal -{ -public: - ScrollBar2* _scrollBar; - int _buttonIndex; -public: - FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) - { - _scrollBar=scrollBar; - _buttonIndex=buttonIndex; - } -public: - virtual void actionPerformed(Panel* panel) - { - _scrollBar->doButtonPressed(_buttonIndex); - } -}; - -} - -//----------------------------------------------------------------------------- -// Purpose: Default scrollbar button -// Draws in new scoreboard style -//----------------------------------------------------------------------------- -class ScrollBarButton : public Button -{ -private: - LineBorder m_Border; - -public: - ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) - { - Image *image = vgui_LoadTGA(filename); - if (image) - { - image->setColor(Color(140, 140, 140, 0)); - setImage(image); - } - - setBorder(&m_Border); - } - - virtual void paintBackground() - { - int wide,tall; - getPaintSize(wide,tall); - - // fill the background - drawSetColor(0, 0, 0, 0); - drawFilledRect(0, 0, wide, tall); - } -}; - - - - -//----------------------------------------------------------------------------- -// Purpose: Constructor -// Input : x - -// y - -// wide - -// tall - -// vertical - -//----------------------------------------------------------------------------- -ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) -{ - _slider=null; - _button[0]=null; - _button[1]=null; - - if(vertical) - { - setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); - setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); - setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); - } - else - { - // untested code - setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); - setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); - setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); - } - - setPaintBorderEnabled(true); - setPaintBackgroundEnabled(true); - setPaintEnabled(true); - setButtonPressedScrollValue(15); - - validate(); - } - -void ScrollBar2::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - - if(_slider==null) - { - return; - } - - if(_button[0]==null) - { - return; - } - - if(_button[1]==null) - { - return; - } - - getPaintSize(wide,tall); - - if(_slider->isVertical()) - { - _slider->setBounds(0,wide,wide,tall-(wide*2)); - //_slider->setBounds(0,0,wide,tall); - _button[0]->setBounds(0,0,wide,wide); - _button[1]->setBounds(0,tall-wide,wide,wide); - } - else - { - _slider->setBounds(tall,0,wide-(tall*2),tall); - //_slider->setBounds(0,0,wide,tall); - _button[0]->setBounds(0,0,tall,tall); - _button[1]->setBounds((wide-tall),0,tall,tall); - } -} - -void ScrollBar2::performLayout() -{ -} - -void ScrollBar2::setValue(int value) -{ - _slider->setValue(value); -} - -int ScrollBar2::getValue() -{ - return _slider->getValue(); -} - -void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) -{ - _intChangeSignalDar.putElement(s); - _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); -} - -void ScrollBar2::setRange(int min,int max) -{ - _slider->setRange(min,max); -} - -void ScrollBar2::fireIntChangeSignal() -{ - for(int i=0;i<_intChangeSignalDar.getCount();i++) - { - _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); - } -} - -bool ScrollBar2::isVertical() -{ - return _slider->isVertical(); -} - -bool ScrollBar2::hasFullRange() -{ - return _slider->hasFullRange(); -} - -//LEAK: new and old slider will leak -void ScrollBar2::setButton(Button* button,int index) -{ - if(_button[index]!=null) - { - removeChild(_button[index]); - } - _button[index]=button; - addChild(_button[index]); - - _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); - - validate(); - - //_button[index]->setVisible(false); -} - -Button* ScrollBar2::getButton(int index) -{ - return _button[index]; -} - -//LEAK: new and old slider will leak -void ScrollBar2::setSlider(Slider2 *slider) -{ - if(_slider!=null) - { - removeChild(_slider); - } - _slider=slider; - addChild(_slider); - - _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); - - validate(); -} - -Slider2 *ScrollBar2::getSlider() -{ - return _slider; -} - -void ScrollBar2::doButtonPressed(int buttonIndex) -{ - if(buttonIndex==0) - { - _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); - } - else - { - _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); - } - -} - -void ScrollBar2::setButtonPressedScrollValue(int value) -{ - _buttonPressedScrollValue=value; -} - -void ScrollBar2::setRangeWindow(int rangeWindow) -{ - _slider->setRangeWindow(rangeWindow); -} - -void ScrollBar2::setRangeWindowEnabled(bool state) -{ - _slider->setRangeWindowEnabled(state); -} - -void ScrollBar2::validate() -{ - if(_slider!=null) - { - int buttonOffset=0; - - for(int i=0;i<2;i++) - { - if(_button[i]!=null) - { - if(_button[i]->isVisible()) - { - if(_slider->isVertical()) - { - buttonOffset+=_button[i]->getTall(); - } - else - { - buttonOffset+=_button[i]->getWide(); - } - } - } - } - - _slider->setButtonOffset(buttonOffset); - } - - int wide,tall; - getSize(wide,tall); - setSize(wide,tall); -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + + +#include "VGUI_ScrollBar2.h" +#include "VGUI_Slider2.h" +#include "vgui_loadtga.h" + +#include +#include +#include +#include + +using namespace vgui; + + +namespace +{ +class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal +{ +public: + FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) + { + _scrollBar=scrollBar; + } + virtual void intChanged(int value,Panel* panel) + { + _scrollBar->fireIntChangeSignal(); + } +protected: + ScrollBar2* _scrollBar; +}; + +class FooDefaultButtonSignal : public ActionSignal +{ +public: + ScrollBar2* _scrollBar; + int _buttonIndex; +public: + FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) + { + _scrollBar=scrollBar; + _buttonIndex=buttonIndex; + } +public: + virtual void actionPerformed(Panel* panel) + { + _scrollBar->doButtonPressed(_buttonIndex); + } +}; + +} + +//----------------------------------------------------------------------------- +// Purpose: Default scrollbar button +// Draws in new scoreboard style +//----------------------------------------------------------------------------- +class ScrollBarButton : public Button +{ +private: + LineBorder m_Border; + +public: + ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) + { + Image *image = vgui_LoadTGA(filename); + if (image) + { + image->setColor(Color(140, 140, 140, 0)); + setImage(image); + } + + setBorder(&m_Border); + } + + virtual void paintBackground() + { + int wide,tall; + getPaintSize(wide,tall); + + // fill the background + drawSetColor(0, 0, 0, 0); + drawFilledRect(0, 0, wide, tall); + } +}; + + + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : x - +// y - +// wide - +// tall - +// vertical - +//----------------------------------------------------------------------------- +ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _slider=null; + _button[0]=null; + _button[1]=null; + + if(vertical) + { + setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); + setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); + setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); + } + else + { + // untested code + setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); + setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); + setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); + } + + setPaintBorderEnabled(true); + setPaintBackgroundEnabled(true); + setPaintEnabled(true); + setButtonPressedScrollValue(15); + + validate(); + } + +void ScrollBar2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + if(_slider==null) + { + return; + } + + if(_button[0]==null) + { + return; + } + + if(_button[1]==null) + { + return; + } + + getPaintSize(wide,tall); + + if(_slider->isVertical()) + { + _slider->setBounds(0,wide,wide,tall-(wide*2)); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,wide,wide); + _button[1]->setBounds(0,tall-wide,wide,wide); + } + else + { + _slider->setBounds(tall,0,wide-(tall*2),tall); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,tall,tall); + _button[1]->setBounds((wide-tall),0,tall,tall); + } +} + +void ScrollBar2::performLayout() +{ +} + +void ScrollBar2::setValue(int value) +{ + _slider->setValue(value); +} + +int ScrollBar2::getValue() +{ + return _slider->getValue(); +} + +void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); +} + +void ScrollBar2::setRange(int min,int max) +{ + _slider->setRange(min,max); +} + +void ScrollBar2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); + } +} + +bool ScrollBar2::isVertical() +{ + return _slider->isVertical(); +} + +bool ScrollBar2::hasFullRange() +{ + return _slider->hasFullRange(); +} + +//LEAK: new and old slider will leak +void ScrollBar2::setButton(Button* button,int index) +{ + if(_button[index]!=null) + { + removeChild(_button[index]); + } + _button[index]=button; + addChild(_button[index]); + + _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); + + validate(); + + //_button[index]->setVisible(false); +} + +Button* ScrollBar2::getButton(int index) +{ + return _button[index]; +} + +//LEAK: new and old slider will leak +void ScrollBar2::setSlider(Slider2 *slider) +{ + if(_slider!=null) + { + removeChild(_slider); + } + _slider=slider; + addChild(_slider); + + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); + + validate(); +} + +Slider2 *ScrollBar2::getSlider() +{ + return _slider; +} + +void ScrollBar2::doButtonPressed(int buttonIndex) +{ + if(buttonIndex==0) + { + _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); + } + else + { + _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); + } + +} + +void ScrollBar2::setButtonPressedScrollValue(int value) +{ + _buttonPressedScrollValue=value; +} + +void ScrollBar2::setRangeWindow(int rangeWindow) +{ + _slider->setRangeWindow(rangeWindow); +} + +void ScrollBar2::setRangeWindowEnabled(bool state) +{ + _slider->setRangeWindowEnabled(state); +} + +void ScrollBar2::validate() +{ + if(_slider!=null) + { + int buttonOffset=0; + + for(int i=0;i<2;i++) + { + if(_button[i]!=null) + { + if(_button[i]->isVisible()) + { + if(_slider->isVertical()) + { + buttonOffset+=_button[i]->getTall(); + } + else + { + buttonOffset+=_button[i]->getWide(); + } + } + } + } + + _slider->setButtonOffset(buttonOffset); + } + + int wide,tall; + getSize(wide,tall); + setSize(wide,tall); +} diff --git a/game_shared/vgui_scrollbar2.h b/game_shared/vgui_scrollbar2.h index b9dfea6d..ad2d2d05 100644 --- a/game_shared/vgui_scrollbar2.h +++ b/game_shared/vgui_scrollbar2.h @@ -1,62 +1,62 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_SCROLLBAR2_H -#define VGUI_SCROLLBAR2_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include -#include - -namespace vgui -{ - -class IntChangeSignal; -class Button; -class Slider2; - -//----------------------------------------------------------------------------- -// Purpose: Hacked up version of the vgui scrollbar -//----------------------------------------------------------------------------- -class VGUIAPI ScrollBar2 : public Panel -{ -public: - ScrollBar2(int x,int y,int wide,int tall,bool vertical); -public: - virtual void setValue(int value); - virtual int getValue(); - virtual void addIntChangeSignal(IntChangeSignal* s); - virtual void setRange(int min,int max); - virtual void setRangeWindow(int rangeWindow); - virtual void setRangeWindowEnabled(bool state); - virtual void setSize(int wide,int tall); - virtual bool isVertical(); - virtual bool hasFullRange(); - virtual void setButton(Button *button,int index); - virtual Button* getButton(int index); - virtual void setSlider(Slider2 *slider); - virtual Slider2 *getSlider(); - virtual void doButtonPressed(int buttonIndex); - virtual void setButtonPressedScrollValue(int value); - virtual void validate(); -public: //bullshit public - virtual void fireIntChangeSignal(); -protected: - virtual void performLayout(); -protected: - Button* _button[2]; - Slider2 *_slider; - Dar _intChangeSignalDar; - int _buttonPressedScrollValue; -}; - -} - -#endif // VGUI_SCROLLBAR2_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SCROLLBAR2_H +#define VGUI_SCROLLBAR2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class IntChangeSignal; +class Button; +class Slider2; + +//----------------------------------------------------------------------------- +// Purpose: Hacked up version of the vgui scrollbar +//----------------------------------------------------------------------------- +class VGUIAPI ScrollBar2 : public Panel +{ +public: + ScrollBar2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual bool isVertical(); + virtual bool hasFullRange(); + virtual void setButton(Button *button,int index); + virtual Button* getButton(int index); + virtual void setSlider(Slider2 *slider); + virtual Slider2 *getSlider(); + virtual void doButtonPressed(int buttonIndex); + virtual void setButtonPressedScrollValue(int value); + virtual void validate(); +public: //bullshit public + virtual void fireIntChangeSignal(); +protected: + virtual void performLayout(); +protected: + Button* _button[2]; + Slider2 *_slider; + Dar _intChangeSignalDar; + int _buttonPressedScrollValue; +}; + +} + +#endif // VGUI_SCROLLBAR2_H diff --git a/game_shared/vgui_slider2.cpp b/game_shared/vgui_slider2.cpp index 7a220b5b..801f5c00 100644 --- a/game_shared/vgui_slider2.cpp +++ b/game_shared/vgui_slider2.cpp @@ -1,436 +1,436 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -#include "VGUI_Slider2.h" - -#include -#include -#include -#include - -using namespace vgui; - -namespace -{ -class FooDefaultSliderSignal : public InputSignal -{ -private: - Slider2* _slider; -public: - FooDefaultSliderSignal(Slider2* slider) - { - _slider=slider; - } -public: - void cursorMoved(int x,int y,Panel* panel) - { - _slider->privateCursorMoved(x,y,panel); - } - void cursorEntered(Panel* panel){} - void cursorExited(Panel* panel){} - void mouseDoublePressed(MouseCode code,Panel* panel){} - void mousePressed(MouseCode code,Panel* panel) - { - _slider->privateMousePressed(code,panel); - } - void mouseReleased(MouseCode code,Panel* panel) - { - _slider->privateMouseReleased(code,panel); - } - void mouseWheeled(int delta,Panel* panel){} - void keyPressed(KeyCode code,Panel* panel){} - void keyTyped(KeyCode code,Panel* panel){} - void keyReleased(KeyCode code,Panel* panel){} - void keyFocusTicked(Panel* panel){} -}; -} - -Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) -{ - _vertical=vertical; - _dragging=false; - _value=0; - _range[0]=0; - _range[1]=299; - _rangeWindow=0; - _rangeWindowEnabled=false; - _buttonOffset=0; - recomputeNobPosFromValue(); - addInputSignal(new FooDefaultSliderSignal(this)); -} - -void Slider2::setSize(int wide,int tall) -{ - Panel::setSize(wide,tall); - recomputeNobPosFromValue(); -} - -bool Slider2::isVertical() -{ - return _vertical; -} - -void Slider2::setValue(int value) -{ - int oldValue=_value; - - if(value<_range[0]) - { - value=_range[0]; - } - - if(value>_range[1]) - { - value=_range[1]; - } - - _value=value; - recomputeNobPosFromValue(); - - if(_value!=oldValue) - { - fireIntChangeSignal(); - } -} - -int Slider2::getValue() -{ - return _value; -} - -void Slider2::recomputeNobPosFromValue() -{ - int wide,tall; - - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float fvalue=(float)(_value-_range[0]); - float fper=fvalue/frange; - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - float fnobsize=frangewindow; - float freepixels = ftall - fnobsize; - - float firstpixel = freepixels * fper; - - _nobPos[0]=(int)( firstpixel ); - _nobPos[1]=(int)( firstpixel + fnobsize ); - - if(_nobPos[1]>tall) - { - _nobPos[0]=tall-((int)fnobsize); - _nobPos[1]=tall; - } - } - else - { - float fnobsize=frangewindow; - float freepixels = fwide - fnobsize; - - float firstpixel = freepixels * fper; - - _nobPos[0]=(int)( firstpixel ); - _nobPos[1]=(int)( firstpixel + fnobsize ); - - if(_nobPos[1]>wide) - { - _nobPos[0]=wide-((int)fnobsize); - _nobPos[1]=wide; - } - } - } - - repaint(); -} - -void Slider2::recomputeValueFromNobPos() -{ - int wide,tall; - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float fvalue=(float)(_value-_range[0]); - float fnob=(float)_nobPos[0]; - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - float fnobsize=frangewindow; - fvalue=frange*(fnob/(ftall-fnobsize)); - } - else - { - float fnobsize=frangewindow; - fvalue=frange*(fnob/(fwide-fnobsize)); - } - } - // Take care of rounding issues. - _value=(int)(fvalue+_range[0]+0.5); - - // Clamp final result - _value = ( _value < _range[1] ) ? _value : _range[1]; -} - -bool Slider2::hasFullRange() -{ - int wide,tall; - getPaintSize(wide,tall); - - float fwide=(float)wide; - float ftall=(float)tall; - float frange=(float)(_range[1]-_range[0]); - float frangewindow=(float)(_rangeWindow); - - if(frangewindow<0) - { - frangewindow=0; - } - - if(!_rangeWindowEnabled) - { - frangewindow=frange; - } - - if ( frangewindow > 0 ) - { - if(_vertical) - { - if( frangewindow <= ( ftall + _buttonOffset ) ) - { - return true; - } - } - else - { - if( frangewindow <= ( fwide + _buttonOffset ) ) - { - return true; - } - } - } - - return false; -} - -void Slider2::addIntChangeSignal(IntChangeSignal* s) -{ - _intChangeSignalDar.putElement(s); -} - -void Slider2::fireIntChangeSignal() -{ - for(int i=0;i<_intChangeSignalDar.getCount();i++) - { - _intChangeSignalDar[i]->intChanged(getValue(),this); - } -} - -void Slider2::paintBackground() -{ - int wide,tall; - getPaintSize(wide,tall); - - if (_vertical) - { - // background behind slider - drawSetColor(40, 40, 40, 0); - drawFilledRect(0, 0, wide, tall); - - // slider front - drawSetColor(0, 0, 0, 0); - drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); - - // slider border - drawSetColor(60, 60, 60, 0); - drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top - drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom - drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left - drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right - } - else - { - //!! doesn't work - - drawSetColor(Scheme::sc_secondary3); - drawFilledRect(0,0,wide,tall); - - drawSetColor(Scheme::sc_black); - drawOutlinedRect(0,0,wide,tall); - - drawSetColor(Scheme::sc_primary2); - drawFilledRect(_nobPos[0],0,_nobPos[1],tall); - - drawSetColor(Scheme::sc_black); - drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); - } -} - -void Slider2::setRange(int min,int max) -{ - if(maxmax) - { - min=max; - } - - _range[0]=min; - _range[1]=max; -} - -void Slider2::getRange(int& min,int& max) -{ - min=_range[0]; - max=_range[1]; -} - -void Slider2::privateCursorMoved(int x,int y,Panel* panel) -{ - if(!_dragging) - { - return; - } - - getApp()->getCursorPos(x,y); - screenToLocal(x,y); - - int wide,tall; - getPaintSize(wide,tall); - - if(_vertical) - { - _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); - _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); - - if(_nobPos[1]>tall) - { - _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); - _nobPos[1]=tall; - } - - if(_nobPos[0]<0) - { - _nobPos[1]=_nobPos[1]-_nobPos[0]; - _nobPos[0]=0; - } - } - else - { - _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); - _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); - - if(_nobPos[1]>wide) - { - _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); - _nobPos[1]=wide; - } - - if(_nobPos[0]<0) - { - _nobPos[1]=_nobPos[1]-_nobPos[0]; - _nobPos[0]=0; - } - } - - recomputeValueFromNobPos(); - repaint(); - fireIntChangeSignal(); -} - -void Slider2::privateMousePressed(MouseCode code,Panel* panel) -{ - int x,y; - getApp()->getCursorPos(x,y); - screenToLocal(x,y); - - if(_vertical) - { - if((y>=_nobPos[0])&&(y<_nobPos[1])) - { - _dragging=true; - getApp()->setMouseCapture(this); - _nobDragStartPos[0]=_nobPos[0]; - _nobDragStartPos[1]=_nobPos[1]; - _dragStartPos[0]=x; - _dragStartPos[1]=y; - } - } - else - { - if((x>=_nobPos[0])&&(x<_nobPos[1])) - { - _dragging=true; - getApp()->setMouseCapture(this); - _nobDragStartPos[0]=_nobPos[0]; - _nobDragStartPos[1]=_nobPos[1]; - _dragStartPos[0]=x; - _dragStartPos[1]=y; - } - } - -} - -void Slider2::privateMouseReleased(MouseCode code,Panel* panel) -{ - _dragging=false; - getApp()->setMouseCapture(null); -} - -void Slider2::getNobPos(int& min, int& max) -{ - min=_nobPos[0]; - max=_nobPos[1]; -} - -void Slider2::setRangeWindow(int rangeWindow) -{ - _rangeWindow=rangeWindow; -} - -void Slider2::setRangeWindowEnabled(bool state) -{ - _rangeWindowEnabled=state; -} - -void Slider2::setButtonOffset(int buttonOffset) -{ - _buttonOffset=buttonOffset; +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: New version of the slider bar +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Slider2.h" + +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooDefaultSliderSignal : public InputSignal +{ +private: + Slider2* _slider; +public: + FooDefaultSliderSignal(Slider2* slider) + { + _slider=slider; + } +public: + void cursorMoved(int x,int y,Panel* panel) + { + _slider->privateCursorMoved(x,y,panel); + } + void cursorEntered(Panel* panel){} + void cursorExited(Panel* panel){} + void mouseDoublePressed(MouseCode code,Panel* panel){} + void mousePressed(MouseCode code,Panel* panel) + { + _slider->privateMousePressed(code,panel); + } + void mouseReleased(MouseCode code,Panel* panel) + { + _slider->privateMouseReleased(code,panel); + } + void mouseWheeled(int delta,Panel* panel){} + void keyPressed(KeyCode code,Panel* panel){} + void keyTyped(KeyCode code,Panel* panel){} + void keyReleased(KeyCode code,Panel* panel){} + void keyFocusTicked(Panel* panel){} +}; +} + +Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _vertical=vertical; + _dragging=false; + _value=0; + _range[0]=0; + _range[1]=299; + _rangeWindow=0; + _rangeWindowEnabled=false; + _buttonOffset=0; + recomputeNobPosFromValue(); + addInputSignal(new FooDefaultSliderSignal(this)); +} + +void Slider2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + recomputeNobPosFromValue(); +} + +bool Slider2::isVertical() +{ + return _vertical; +} + +void Slider2::setValue(int value) +{ + int oldValue=_value; + + if(value<_range[0]) + { + value=_range[0]; + } + + if(value>_range[1]) + { + value=_range[1]; + } + + _value=value; + recomputeNobPosFromValue(); + + if(_value!=oldValue) + { + fireIntChangeSignal(); + } +} + +int Slider2::getValue() +{ + return _value; +} + +void Slider2::recomputeNobPosFromValue() +{ + int wide,tall; + + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fper=fvalue/frange; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + float freepixels = ftall - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-((int)fnobsize); + _nobPos[1]=tall; + } + } + else + { + float fnobsize=frangewindow; + float freepixels = fwide - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-((int)fnobsize); + _nobPos[1]=wide; + } + } + } + + repaint(); +} + +void Slider2::recomputeValueFromNobPos() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fnob=(float)_nobPos[0]; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(ftall-fnobsize)); + } + else + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(fwide-fnobsize)); + } + } + // Take care of rounding issues. + _value=(int)(fvalue+_range[0]+0.5); + + // Clamp final result + _value = ( _value < _range[1] ) ? _value : _range[1]; +} + +bool Slider2::hasFullRange() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + if( frangewindow <= ( ftall + _buttonOffset ) ) + { + return true; + } + } + else + { + if( frangewindow <= ( fwide + _buttonOffset ) ) + { + return true; + } + } + } + + return false; +} + +void Slider2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); +} + +void Slider2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(getValue(),this); + } +} + +void Slider2::paintBackground() +{ + int wide,tall; + getPaintSize(wide,tall); + + if (_vertical) + { + // background behind slider + drawSetColor(40, 40, 40, 0); + drawFilledRect(0, 0, wide, tall); + + // slider front + drawSetColor(0, 0, 0, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); + + // slider border + drawSetColor(60, 60, 60, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top + drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom + drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left + drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right + } + else + { + //!! doesn't work + + drawSetColor(Scheme::sc_secondary3); + drawFilledRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_primary2); + drawFilledRect(_nobPos[0],0,_nobPos[1],tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); + } +} + +void Slider2::setRange(int min,int max) +{ + if(maxmax) + { + min=max; + } + + _range[0]=min; + _range[1]=max; +} + +void Slider2::getRange(int& min,int& max) +{ + min=_range[0]; + max=_range[1]; +} + +void Slider2::privateCursorMoved(int x,int y,Panel* panel) +{ + if(!_dragging) + { + return; + } + + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + int wide,tall; + getPaintSize(wide,tall); + + if(_vertical) + { + _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); + _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=tall; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + else + { + _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); + _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=wide; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + + recomputeValueFromNobPos(); + repaint(); + fireIntChangeSignal(); +} + +void Slider2::privateMousePressed(MouseCode code,Panel* panel) +{ + int x,y; + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + if(_vertical) + { + if((y>=_nobPos[0])&&(y<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + else + { + if((x>=_nobPos[0])&&(x<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + +} + +void Slider2::privateMouseReleased(MouseCode code,Panel* panel) +{ + _dragging=false; + getApp()->setMouseCapture(null); +} + +void Slider2::getNobPos(int& min, int& max) +{ + min=_nobPos[0]; + max=_nobPos[1]; +} + +void Slider2::setRangeWindow(int rangeWindow) +{ + _rangeWindow=rangeWindow; +} + +void Slider2::setRangeWindowEnabled(bool state) +{ + _rangeWindowEnabled=state; +} + +void Slider2::setButtonOffset(int buttonOffset) +{ + _buttonOffset=buttonOffset; } \ No newline at end of file diff --git a/game_shared/vgui_slider2.h b/game_shared/vgui_slider2.h index ec384210..4edb87f2 100644 --- a/game_shared/vgui_slider2.h +++ b/game_shared/vgui_slider2.h @@ -1,67 +1,67 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_SLIDER2_H -#define VGUI_SLIDER2_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include -#include - -namespace vgui -{ - -enum MouseCode; -class IntChangeSignal; - -class VGUIAPI Slider2 : public Panel -{ -private: - bool _vertical; - bool _dragging; - int _nobPos[2]; - int _nobDragStartPos[2]; - int _dragStartPos[2]; - Dar _intChangeSignalDar; - int _range[2]; - int _value; - int _rangeWindow; - bool _rangeWindowEnabled; - int _buttonOffset; -public: - Slider2(int x,int y,int wide,int tall,bool vertical); -public: - virtual void setValue(int value); - virtual int getValue(); - virtual bool isVertical(); - virtual void addIntChangeSignal(IntChangeSignal* s); - virtual void setRange(int min,int max); - virtual void getRange(int& min,int& max); - virtual void setRangeWindow(int rangeWindow); - virtual void setRangeWindowEnabled(bool state); - virtual void setSize(int wide,int tall); - virtual void getNobPos(int& min, int& max); - virtual bool hasFullRange(); - virtual void setButtonOffset(int buttonOffset); -private: - virtual void recomputeNobPosFromValue(); - virtual void recomputeValueFromNobPos(); -public: //bullshit public - virtual void privateCursorMoved(int x,int y,Panel* panel); - virtual void privateMousePressed(MouseCode code,Panel* panel); - virtual void privateMouseReleased(MouseCode code,Panel* panel); -protected: - virtual void fireIntChangeSignal(); - virtual void paintBackground(); -}; - -} - -#endif // VGUI_SLIDER2_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SLIDER2_H +#define VGUI_SLIDER2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class IntChangeSignal; + +class VGUIAPI Slider2 : public Panel +{ +private: + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + Dar _intChangeSignalDar; + int _range[2]; + int _value; + int _rangeWindow; + bool _rangeWindowEnabled; + int _buttonOffset; +public: + Slider2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual bool isVertical(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void getRange(int& min,int& max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual void getNobPos(int& min, int& max); + virtual bool hasFullRange(); + virtual void setButtonOffset(int buttonOffset); +private: + virtual void recomputeNobPosFromValue(); + virtual void recomputeValueFromNobPos(); +public: //bullshit public + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); +protected: + virtual void fireIntChangeSignal(); + virtual void paintBackground(); +}; + +} + +#endif // VGUI_SLIDER2_H diff --git a/game_shared/voice_banmgr.cpp b/game_shared/voice_banmgr.cpp index 470e80ec..915e854f 100644 --- a/game_shared/voice_banmgr.cpp +++ b/game_shared/voice_banmgr.cpp @@ -1,197 +1,197 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include -#include "voice_banmgr.h" - - -#define BANMGR_FILEVERSION 1 -char const *g_pBanMgrFilename = "voice_ban.dt"; - - - -// Hash a player ID to a byte. -unsigned char HashPlayerID(char const playerID[16]) -{ - unsigned char curHash = 0; - - for(int i=0; i < 16; i++) - curHash += (unsigned char)playerID[i]; - - return curHash; -} - - - -CVoiceBanMgr::CVoiceBanMgr() -{ - Clear(); -} - - -CVoiceBanMgr::~CVoiceBanMgr() -{ - Term(); -} - - -bool CVoiceBanMgr::Init(char const *pGameDir) -{ - Term(); - - char filename[512]; - _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); - - // Load in the squelch file. - FILE *fp = fopen(filename, "rb"); - if(fp) - { - int version; - fread(&version, 1, sizeof(version), fp); - if(version == BANMGR_FILEVERSION) - { - fseek(fp, 0, SEEK_END); - int nIDs = (ftell(fp) - sizeof(version)) / 16; - fseek(fp, sizeof(version), SEEK_SET); - - for(int i=0; i < nIDs; i++) - { - char playerID[16]; - fread(playerID, 1, 16, fp); - AddBannedPlayer(playerID); - } - } - - fclose(fp); - } - - return true; -} - - -void CVoiceBanMgr::Term() -{ - // Free all the player structures. - for(int i=0; i < 256; i++) - { - BannedPlayer *pListHead = &m_PlayerHash[i]; - BannedPlayer *pNext; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) - { - pNext = pCur->m_pNext; - delete pCur; - } - } - - Clear(); -} - - -void CVoiceBanMgr::SaveState(char const *pGameDir) -{ - // Save the file out. - char filename[512]; - _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); - - FILE *fp = fopen(filename, "wb"); - if(fp) - { - int version = BANMGR_FILEVERSION; - fwrite(&version, 1, sizeof(version), fp); - - for(int i=0; i < 256; i++) - { - BannedPlayer *pListHead = &m_PlayerHash[i]; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) - { - fwrite(pCur->m_PlayerID, 1, 16, fp); - } - } - - fclose(fp); - } -} - - -bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) -{ - return !!InternalFindPlayerSquelch(playerID); -} - - -void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) -{ - if(bSquelch) - { - // Is this guy already squelched? - if(GetPlayerBan(playerID)) - return; - - AddBannedPlayer(playerID); - } - else - { - BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); - if(pPlayer) - { - pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; - pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; - delete pPlayer; - } - } -} - - -void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) -{ - for(int i=0; i < 256; i++) - { - for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) - { - callback(pCur->m_PlayerID); - } - } -} - - -void CVoiceBanMgr::Clear() -{ - // Tie off the hash table entries. - for(int i=0; i < 256; i++) - m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; -} - - -CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) -{ - int index = HashPlayerID(playerID); - BannedPlayer *pListHead = &m_PlayerHash[index]; - for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) - { - if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) - return pCur; - } - - return NULL; -} - - -CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) -{ - BannedPlayer *pNew = new BannedPlayer; - if(!pNew) - return NULL; - - int index = HashPlayerID(playerID); - memcpy(pNew->m_PlayerID, playerID, 16); - pNew->m_pNext = &m_PlayerHash[index]; - pNew->m_pPrev = m_PlayerHash[index].m_pPrev; - pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; - return pNew; -} - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "voice_banmgr.h" + + +#define BANMGR_FILEVERSION 1 +char const *g_pBanMgrFilename = "voice_ban.dt"; + + + +// Hash a player ID to a byte. +unsigned char HashPlayerID(char const playerID[16]) +{ + unsigned char curHash = 0; + + for(int i=0; i < 16; i++) + curHash += (unsigned char)playerID[i]; + + return curHash; +} + + + +CVoiceBanMgr::CVoiceBanMgr() +{ + Clear(); +} + + +CVoiceBanMgr::~CVoiceBanMgr() +{ + Term(); +} + + +bool CVoiceBanMgr::Init(char const *pGameDir) +{ + Term(); + + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + // Load in the squelch file. + FILE *fp = fopen(filename, "rb"); + if(fp) + { + int version; + fread(&version, 1, sizeof(version), fp); + if(version == BANMGR_FILEVERSION) + { + fseek(fp, 0, SEEK_END); + int nIDs = (ftell(fp) - sizeof(version)) / 16; + fseek(fp, sizeof(version), SEEK_SET); + + for(int i=0; i < nIDs; i++) + { + char playerID[16]; + fread(playerID, 1, 16, fp); + AddBannedPlayer(playerID); + } + } + + fclose(fp); + } + + return true; +} + + +void CVoiceBanMgr::Term() +{ + // Free all the player structures. + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + BannedPlayer *pNext; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) + { + pNext = pCur->m_pNext; + delete pCur; + } + } + + Clear(); +} + + +void CVoiceBanMgr::SaveState(char const *pGameDir) +{ + // Save the file out. + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + FILE *fp = fopen(filename, "wb"); + if(fp) + { + int version = BANMGR_FILEVERSION; + fwrite(&version, 1, sizeof(version), fp); + + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + fwrite(pCur->m_PlayerID, 1, 16, fp); + } + } + + fclose(fp); + } +} + + +bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) +{ + return !!InternalFindPlayerSquelch(playerID); +} + + +void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) +{ + if(bSquelch) + { + // Is this guy already squelched? + if(GetPlayerBan(playerID)) + return; + + AddBannedPlayer(playerID); + } + else + { + BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); + if(pPlayer) + { + pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; + pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; + delete pPlayer; + } + } +} + + +void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) +{ + for(int i=0; i < 256; i++) + { + for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) + { + callback(pCur->m_PlayerID); + } + } +} + + +void CVoiceBanMgr::Clear() +{ + // Tie off the hash table entries. + for(int i=0; i < 256; i++) + m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) +{ + int index = HashPlayerID(playerID); + BannedPlayer *pListHead = &m_PlayerHash[index]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) + return pCur; + } + + return NULL; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) +{ + BannedPlayer *pNew = new BannedPlayer; + if(!pNew) + return NULL; + + int index = HashPlayerID(playerID); + memcpy(pNew->m_PlayerID, playerID, 16); + pNew->m_pNext = &m_PlayerHash[index]; + pNew->m_pPrev = m_PlayerHash[index].m_pPrev; + pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; + return pNew; +} + diff --git a/game_shared/voice_banmgr.h b/game_shared/voice_banmgr.h index 2f14d8b7..610ad6cf 100644 --- a/game_shared/voice_banmgr.h +++ b/game_shared/voice_banmgr.h @@ -1,57 +1,57 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_BANMGR_H -#define VOICE_BANMGR_H -#ifdef _WIN32 -#pragma once -#endif - - -// This class manages the (persistent) list of squelched players. -class CVoiceBanMgr -{ -public: - - CVoiceBanMgr(); - ~CVoiceBanMgr(); - - // Init loads the list of squelched players from disk. - bool Init(char const *pGameDir); - void Term(); - - // Saves the state into voice_squelch.dt. - void SaveState(char const *pGameDir); - - bool GetPlayerBan(char const playerID[16]); - void SetPlayerBan(char const playerID[16], bool bSquelch); - - // Call your callback for each banned player. - void ForEachBannedPlayer(void (*callback)(char id[16])); - - -protected: - - class BannedPlayer - { - public: - char m_PlayerID[16]; - BannedPlayer *m_pPrev, *m_pNext; - }; - - void Clear(); - BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); - BannedPlayer* AddBannedPlayer(char const playerID[16]); - - -protected: - - BannedPlayer m_PlayerHash[256]; -}; - - -#endif // VOICE_BANMGR_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_BANMGR_H +#define VOICE_BANMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class manages the (persistent) list of squelched players. +class CVoiceBanMgr +{ +public: + + CVoiceBanMgr(); + ~CVoiceBanMgr(); + + // Init loads the list of squelched players from disk. + bool Init(char const *pGameDir); + void Term(); + + // Saves the state into voice_squelch.dt. + void SaveState(char const *pGameDir); + + bool GetPlayerBan(char const playerID[16]); + void SetPlayerBan(char const playerID[16], bool bSquelch); + + // Call your callback for each banned player. + void ForEachBannedPlayer(void (*callback)(char id[16])); + + +protected: + + class BannedPlayer + { + public: + char m_PlayerID[16]; + BannedPlayer *m_pPrev, *m_pNext; + }; + + void Clear(); + BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); + BannedPlayer* AddBannedPlayer(char const playerID[16]); + + +protected: + + BannedPlayer m_PlayerHash[256]; +}; + + +#endif // VOICE_BANMGR_H diff --git a/game_shared/voice_common.h b/game_shared/voice_common.h index 93e9353f..5517d8ee 100644 --- a/game_shared/voice_common.h +++ b/game_shared/voice_common.h @@ -1,24 +1,24 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_COMMON_H -#define VOICE_COMMON_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "bitvec.h" - - -#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). -#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) - -typedef CBitVec CPlayerBitVec; - - -#endif // VOICE_COMMON_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitvec.h" + + +#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec CPlayerBitVec; + + +#endif // VOICE_COMMON_H diff --git a/game_shared/voice_gamemgr.cpp b/game_shared/voice_gamemgr.cpp index b3f16714..829368a6 100644 --- a/game_shared/voice_gamemgr.cpp +++ b/game_shared/voice_gamemgr.cpp @@ -1,274 +1,274 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "voice_gamemgr.h" -#include -#include -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" - - - -#define UPDATE_INTERVAL 0.3 - - -// These are stored off as CVoiceGameMgr is created and deleted. -CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. - // (If it's zero, then the server reports that the game rules are saying the - // player can't hear anyone). - -CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. - // These are indexed as clients and each bit represents a client - // (so player entity is bit+1). - -CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if -CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. -CPlayerBitVec g_bWantModEnable; - -cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; - -// Set game rules to allow all clients to talk to each other. -// Muted players still can't talk to each other. -cvar_t sv_alltalk = {"sv_alltalk", "0"}; - -// ------------------------------------------------------------------------ // -// Static helpers. -// ------------------------------------------------------------------------ // - -// Find a player with a case-insensitive name search. -static CBasePlayer* FindPlayerByName(const char *pTestName) -{ - for(int i=1; i <= gpGlobals->maxClients; i++) - { - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); - if(pEdict) - { - CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); - if(pEnt && pEnt->IsPlayer()) - { - const char *pNetName = STRING(pEnt->pev->netname); - if(stricmp(pNetName, pTestName) == 0) - { - return (CBasePlayer*)pEnt; - } - } - } - } - - return NULL; -} - -static void VoiceServerDebug( char const *pFmt, ... ) -{ - char msg[4096]; - va_list marker; - - if( !voice_serverdebug.value ) - return; - - va_start( marker, pFmt ); - _vsnprintf( msg, sizeof(msg), pFmt, marker ); - va_end( marker ); - - ALERT( at_console, "%s", msg ); -} - - - -// ------------------------------------------------------------------------ // -// CVoiceGameMgr. -// ------------------------------------------------------------------------ // - -CVoiceGameMgr::CVoiceGameMgr() -{ - m_UpdateInterval = 0; - m_nMaxPlayers = 0; -} - - -CVoiceGameMgr::~CVoiceGameMgr() -{ -} - - -bool CVoiceGameMgr::Init( - IVoiceGameMgrHelper *pHelper, - int maxClients) -{ - m_pHelper = pHelper; - m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; - g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); - - m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); - m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); - - // register voice_serverdebug if it hasn't been registered already - if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) - CVAR_REGISTER( &voice_serverdebug ); - - if( !CVAR_GET_POINTER( "sv_alltalk" ) ) - CVAR_REGISTER( &sv_alltalk ); - - return true; -} - - -void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) -{ - m_pHelper = pHelper; -} - - -void CVoiceGameMgr::Update(double frametime) -{ - // Only update periodically. - m_UpdateInterval += frametime; - if(m_UpdateInterval < UPDATE_INTERVAL) - return; - - UpdateMasks(); -} - - -void CVoiceGameMgr::ClientConnected(edict_t *pEdict) -{ - int index = ENTINDEX(pEdict) - 1; - - // Clear out everything we use for deltas on this guy. - g_bWantModEnable[index] = true; - g_SentGameRulesMasks[index].Init(0); - g_SentBanMasks[index].Init(0); -} - -// Called to determine if the Receiver has muted (blocked) the Sender -// Returns true if the receiver has blocked the sender -bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) -{ - int iReceiverIndex, iSenderIndex; - - if ( !pReceiver || !pSender ) - return false; - - iReceiverIndex = pReceiver->entindex() - 1; - iSenderIndex = pSender->entindex() - 1; - - if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) - return false; - - return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); -} - -bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) -{ - int playerClientIndex = pPlayer->entindex() - 1; - if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); - return true; - } - - bool bBan = stricmp(cmd, "vban") == 0; - if(bBan && CMD_ARGC() >= 2) - { - for(int i=1; i < CMD_ARGC(); i++) - { - unsigned long mask = 0; - sscanf(CMD_ARGV(i), "%lx", &mask); - - if(i <= VOICE_MAX_PLAYERS_DW) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); - g_BanMasks[playerClientIndex].SetDWord(i-1, mask); - } - else - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); - } - } - - // Force it to update the masks now. - //UpdateMasks(); - return true; - } - else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) - { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); - g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); - g_bWantModEnable[playerClientIndex] = false; - //UpdateMasks(); - return true; - } - else - { - return false; - } -} - - -void CVoiceGameMgr::UpdateMasks() -{ - m_UpdateInterval = 0; - - bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" ); - - for(int iClient=0; iClient < m_nMaxPlayers; iClient++) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); - if(!pEnt || !pEnt->IsPlayer()) - continue; - - // Request the state of their "VModEnable" cvar. - if(g_bWantModEnable[iClient]) - { - MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); - MESSAGE_END(); - } - - CBasePlayer *pPlayer = (CBasePlayer*)pEnt; - - CPlayerBitVec gameRulesMask; - if( g_PlayerModEnable[iClient] ) - { - // Build a mask of who they can hear based on the game rules. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) - { - pEnt = UTIL_PlayerByIndex(iOtherClient+1); - if(pEnt && pEnt->IsPlayer() && - (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) - { - gameRulesMask[iOtherClient] = true; - } - } - } - - // If this is different from what the client has, send an update. - if(gameRulesMask != g_SentGameRulesMasks[iClient] || - g_BanMasks[iClient] != g_SentBanMasks[iClient]) - { - g_SentGameRulesMasks[iClient] = gameRulesMask; - g_SentBanMasks[iClient] = g_BanMasks[iClient]; - - MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); - int dw; - for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - WRITE_LONG(gameRulesMask.GetDWord(dw)); - WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); - } - MESSAGE_END(); - } - - // Tell the engine. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) - { - bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; - g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); - } - } -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "voice_gamemgr.h" +#include +#include +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" + + + +#define UPDATE_INTERVAL 0.3 + + +// These are stored off as CVoiceGameMgr is created and deleted. +CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. + // (If it's zero, then the server reports that the game rules are saying the + // player can't hear anyone). + +CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. + // These are indexed as clients and each bit represents a client + // (so player entity is bit+1). + +CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if +CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. +CPlayerBitVec g_bWantModEnable; + +cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; + +// Set game rules to allow all clients to talk to each other. +// Muted players still can't talk to each other. +cvar_t sv_alltalk = {"sv_alltalk", "0"}; + +// ------------------------------------------------------------------------ // +// Static helpers. +// ------------------------------------------------------------------------ // + +// Find a player with a case-insensitive name search. +static CBasePlayer* FindPlayerByName(const char *pTestName) +{ + for(int i=1; i <= gpGlobals->maxClients; i++) + { + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); + if(pEdict) + { + CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); + if(pEnt && pEnt->IsPlayer()) + { + const char *pNetName = STRING(pEnt->pev->netname); + if(stricmp(pNetName, pTestName) == 0) + { + return (CBasePlayer*)pEnt; + } + } + } + } + + return NULL; +} + +static void VoiceServerDebug( char const *pFmt, ... ) +{ + char msg[4096]; + va_list marker; + + if( !voice_serverdebug.value ) + return; + + va_start( marker, pFmt ); + _vsnprintf( msg, sizeof(msg), pFmt, marker ); + va_end( marker ); + + ALERT( at_console, "%s", msg ); +} + + + +// ------------------------------------------------------------------------ // +// CVoiceGameMgr. +// ------------------------------------------------------------------------ // + +CVoiceGameMgr::CVoiceGameMgr() +{ + m_UpdateInterval = 0; + m_nMaxPlayers = 0; +} + + +CVoiceGameMgr::~CVoiceGameMgr() +{ +} + + +bool CVoiceGameMgr::Init( + IVoiceGameMgrHelper *pHelper, + int maxClients) +{ + m_pHelper = pHelper; + m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; + g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); + + m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); + m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); + + // register voice_serverdebug if it hasn't been registered already + if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) + CVAR_REGISTER( &voice_serverdebug ); + + if( !CVAR_GET_POINTER( "sv_alltalk" ) ) + CVAR_REGISTER( &sv_alltalk ); + + return true; +} + + +void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) +{ + m_pHelper = pHelper; +} + + +void CVoiceGameMgr::Update(double frametime) +{ + // Only update periodically. + m_UpdateInterval += frametime; + if(m_UpdateInterval < UPDATE_INTERVAL) + return; + + UpdateMasks(); +} + + +void CVoiceGameMgr::ClientConnected(edict_t *pEdict) +{ + int index = ENTINDEX(pEdict) - 1; + + // Clear out everything we use for deltas on this guy. + g_bWantModEnable[index] = true; + g_SentGameRulesMasks[index].Init(0); + g_SentBanMasks[index].Init(0); +} + +// Called to determine if the Receiver has muted (blocked) the Sender +// Returns true if the receiver has blocked the sender +bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) +{ + int iReceiverIndex, iSenderIndex; + + if ( !pReceiver || !pSender ) + return false; + + iReceiverIndex = pReceiver->entindex() - 1; + iSenderIndex = pSender->entindex() - 1; + + if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) + return false; + + return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); +} + +bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) +{ + int playerClientIndex = pPlayer->entindex() - 1; + if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); + return true; + } + + bool bBan = stricmp(cmd, "vban") == 0; + if(bBan && CMD_ARGC() >= 2) + { + for(int i=1; i < CMD_ARGC(); i++) + { + unsigned long mask = 0; + sscanf(CMD_ARGV(i), "%lx", &mask); + + if(i <= VOICE_MAX_PLAYERS_DW) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); + g_BanMasks[playerClientIndex].SetDWord(i-1, mask); + } + else + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); + } + } + + // Force it to update the masks now. + //UpdateMasks(); + return true; + } + else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); + g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); + g_bWantModEnable[playerClientIndex] = false; + //UpdateMasks(); + return true; + } + else + { + return false; + } +} + + +void CVoiceGameMgr::UpdateMasks() +{ + m_UpdateInterval = 0; + + bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" ); + + for(int iClient=0; iClient < m_nMaxPlayers; iClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); + if(!pEnt || !pEnt->IsPlayer()) + continue; + + // Request the state of their "VModEnable" cvar. + if(g_bWantModEnable[iClient]) + { + MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); + MESSAGE_END(); + } + + CBasePlayer *pPlayer = (CBasePlayer*)pEnt; + + CPlayerBitVec gameRulesMask; + if( g_PlayerModEnable[iClient] ) + { + // Build a mask of who they can hear based on the game rules. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + pEnt = UTIL_PlayerByIndex(iOtherClient+1); + if(pEnt && pEnt->IsPlayer() && + (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) + { + gameRulesMask[iOtherClient] = true; + } + } + } + + // If this is different from what the client has, send an update. + if(gameRulesMask != g_SentGameRulesMasks[iClient] || + g_BanMasks[iClient] != g_SentBanMasks[iClient]) + { + g_SentGameRulesMasks[iClient] = gameRulesMask; + g_SentBanMasks[iClient] = g_BanMasks[iClient]; + + MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); + int dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + WRITE_LONG(gameRulesMask.GetDWord(dw)); + WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); + } + MESSAGE_END(); + } + + // Tell the engine. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; + g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); + } + } +} diff --git a/game_shared/voice_gamemgr.h b/game_shared/voice_gamemgr.h index 9605c5c8..de5f3cdc 100644 --- a/game_shared/voice_gamemgr.h +++ b/game_shared/voice_gamemgr.h @@ -1,79 +1,79 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_GAMEMGR_H -#define VOICE_GAMEMGR_H -#pragma once - - -#include "voice_common.h" - - -class CGameRules; -class CBasePlayer; - - -class IVoiceGameMgrHelper -{ -public: - virtual ~IVoiceGameMgrHelper() {} - - // 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: - CVoiceGameMgr(); - virtual ~CVoiceGameMgr(); - - bool Init( - IVoiceGameMgrHelper *m_pHelper, - int maxClients - ); - - void SetHelper(IVoiceGameMgrHelper *pHelper); - - // Updates which players can hear which other players. - // If gameplay mode is DM, then only players within the PVS can hear each other. - // If gameplay mode is teamplay, then only players on the same team can hear each other. - // Player masks are always applied. - void Update(double frametime); - - // Called when a new client connects (unsquelches its entity for everyone). - void ClientConnected(struct edict_s *pEdict); - - // Called on ClientCommand. Checks for the squelch and unsquelch commands. - // Returns true if it handled the command. - bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); - - // Called to determine if the Receiver has muted (blocked) the Sender - // Returns true if the receiver has blocked the sender - bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); - - -private: - - // Force it to update the client masks. - void UpdateMasks(); - - -private: - int m_msgPlayerVoiceMask; - int m_msgRequestState; - - IVoiceGameMgrHelper *m_pHelper; - int m_nMaxPlayers; - double m_UpdateInterval; // How long since the last update. -}; - - -#endif // VOICE_GAMEMGR_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_GAMEMGR_H +#define VOICE_GAMEMGR_H +#pragma once + + +#include "voice_common.h" + + +class CGameRules; +class CBasePlayer; + + +class IVoiceGameMgrHelper +{ +public: + virtual ~IVoiceGameMgrHelper() {} + + // 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: + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); + + bool Init( + IVoiceGameMgrHelper *m_pHelper, + int maxClients + ); + + void SetHelper(IVoiceGameMgrHelper *pHelper); + + // Updates which players can hear which other players. + // If gameplay mode is DM, then only players within the PVS can hear each other. + // If gameplay mode is teamplay, then only players on the same team can hear each other. + // Player masks are always applied. + void Update(double frametime); + + // Called when a new client connects (unsquelches its entity for everyone). + void ClientConnected(struct edict_s *pEdict); + + // Called on ClientCommand. Checks for the squelch and unsquelch commands. + // Returns true if it handled the command. + bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); + + // Called to determine if the Receiver has muted (blocked) the Sender + // Returns true if the receiver has blocked the sender + bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); + + +private: + + // Force it to update the client masks. + void UpdateMasks(); + + +private: + int m_msgPlayerVoiceMask; + int m_msgRequestState; + + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. +}; + + +#endif // VOICE_GAMEMGR_H diff --git a/game_shared/voice_status.cpp b/game_shared/voice_status.cpp index e5378d00..57bc0f16 100644 --- a/game_shared/voice_status.cpp +++ b/game_shared/voice_status.cpp @@ -1,874 +1,874 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// There are hud.h's coming out of the woodwork so this ensures that we get the right one. -#if defined( DMC_BUILD ) - #include "../dmc/cl_dll/hud.h" - #include "../dmc/cl_dll/cl_util.h" -#elif defined( RICOCHET_BUILD ) - #include "../ricochet/cl_dll/hud.h" - #include "../ricochet/cl_dll/cl_util.h" -#else - #include "../cl_dll/hud.h" - #include "../cl_dll/cl_util.h" -#endif - -#include -#include -#include - -#if defined( DMC_BUILD ) - #include "../dmc/cl_dll/parsemsg.h" - #include "../dmc/cl_dll/hud_servers.h" - #include "../dmc/cl_dll/demo.h" -#elif defined( RICOCHET_BUILD ) - #include "../ricochet/cl_dll/parsemsg.h" - #include "../ricochet/cl_dll/hud_servers.h" - #include "../ricochet/cl_dll/demo.h" -#else - #include "../cl_dll/parsemsg.h" - #include "../cl_dll/hud_servers.h" - #include "../cl_dll/demo.h" -#endif - -#include "demo_api.h" -#include "voice_status.h" -#include "r_efx.h" -#include "entity_types.h" -#include "VGUI_ActionSignal.h" -#include "VGUI_Scheme.h" -#include "VGUI_TextImage.h" -#include "vgui_loadtga.h" -#include "vgui_helpers.h" -#include "vgui_mousecode.h" - - - -using namespace vgui; - - -extern int cam_thirdperson; - - -#define VOICE_MODEL_INTERVAL 0.3 -#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. -#define SQUELCHOSCILLATE_PER_SECOND 2.0f - - -extern BitmapTGA *LoadTGA( const char* pImageName ); - - - -// ---------------------------------------------------------------------- // -// The voice manager for the client. -// ---------------------------------------------------------------------- // -CVoiceStatus g_VoiceStatus; - -CVoiceStatus* GetClientVoiceMgr() -{ - return &g_VoiceStatus; -} - - - -// ---------------------------------------------------------------------- // -// CVoiceStatus. -// ---------------------------------------------------------------------- // - -static CVoiceStatus *g_pInternalVoiceStatus = NULL; - -int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) -{ - if(g_pInternalVoiceStatus) - g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); - - return 1; -} - -int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) -{ - if(g_pInternalVoiceStatus) - g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); - - return 1; -} - - -int g_BannedPlayerPrintCount; -void ForEachBannedPlayer(char id[16]) -{ - char str[256]; - sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", - g_BannedPlayerPrintCount++, - id[0], id[1], id[2], id[3], - id[4], id[5], id[6], id[7], - id[8], id[9], id[10], id[11], - id[12], id[13], id[14], id[15] - ); - strupr(str); - gEngfuncs.pfnConsolePrint(str); -} - - -void ShowBannedCallback() -{ - if(g_pInternalVoiceStatus) - { - g_BannedPlayerPrintCount = 0; - gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); - g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); - gEngfuncs.pfnConsolePrint("------------------------------\n"); - } -} - - -// ---------------------------------------------------------------------- // -// CVoiceStatus. -// ---------------------------------------------------------------------- // - -CVoiceStatus::CVoiceStatus() -{ - m_bBanMgrInitialized = false; - m_LastUpdateServerState = 0; - - m_pSpeakerLabelIcon = NULL; - m_pScoreboardNeverSpoken = NULL; - m_pScoreboardNotSpeaking = NULL; - m_pScoreboardSpeaking = NULL; - m_pScoreboardSpeaking2 = NULL; - m_pScoreboardSquelch = NULL; - m_pScoreboardBanned = NULL; - - m_pLocalBitmap = NULL; - m_pAckBitmap = NULL; - - m_bTalking = m_bServerAcked = false; - - memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); - - m_bServerModEnable = -1; - - m_pchGameDir = NULL; -} - - -CVoiceStatus::~CVoiceStatus() -{ - g_pInternalVoiceStatus = NULL; - - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - delete m_Labels[i].m_pLabel; - m_Labels[i].m_pLabel = NULL; - - delete m_Labels[i].m_pIcon; - m_Labels[i].m_pIcon = NULL; - - delete m_Labels[i].m_pBackground; - m_Labels[i].m_pBackground = NULL; - } - - delete m_pLocalLabel; - m_pLocalLabel = NULL; - - FreeBitmaps(); - - if(m_pchGameDir) - { - if(m_bBanMgrInitialized) - { - m_BanMgr.SaveState(m_pchGameDir); - } - - free(m_pchGameDir); - } -} - - -int CVoiceStatus::Init( - IVoiceStatusHelper *pHelper, - Panel **pParentPanel) -{ - // Setup the voice_modenable cvar. - gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); - - gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); - - gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); - - if(gEngfuncs.pfnGetGameDirectory()) - { - m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); - m_bBanMgrInitialized = true; - } - - assert(!g_pInternalVoiceStatus); - g_pInternalVoiceStatus = this; - - m_BlinkTimer = 0; - m_VoiceHeadModel = NULL; - memset(m_Labels, 0, sizeof(m_Labels)); - - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - CVoiceLabel *pLabel = &m_Labels[i]; - - pLabel->m_pBackground = new Label(""); - - if(pLabel->m_pLabel = new Label("")) - { - pLabel->m_pLabel->setVisible( true ); - pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); - pLabel->m_pLabel->setTextAlignment( Label::a_east ); - pLabel->m_pLabel->setContentAlignment( Label::a_east ); - pLabel->m_pLabel->setParent( pLabel->m_pBackground ); - } - - if( pLabel->m_pIcon = new ImagePanel( NULL ) ) - { - pLabel->m_pIcon->setVisible( true ); - pLabel->m_pIcon->setParent( pLabel->m_pBackground ); - } - - pLabel->m_clientindex = -1; - } - - m_pLocalLabel = new ImagePanel(NULL); - - m_bInSquelchMode = false; - - m_pHelper = pHelper; - m_pParentPanel = pParentPanel; - gHUD.AddHudElem(this); - m_iFlags = HUD_ACTIVE; - HOOK_MESSAGE(VoiceMask); - HOOK_MESSAGE(ReqState); - - // Cache the game directory for use when we shut down - const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); - m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); - strcpy(m_pchGameDir, pchGameDirT); - - return 1; -} - - -int CVoiceStatus::VidInit() -{ - FreeBitmaps(); - - - if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) - { - m_pLocalBitmap->setColor(Color(255,255,255,135)); - } - - if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) - { - m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. - } - - m_pLocalLabel->setImage( m_pLocalBitmap ); - m_pLocalLabel->setVisible( false ); - - - if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) - m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. - - if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) - m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) - m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) - m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) - m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) - m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) - m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. - - // Figure out the voice head model height. - m_VoiceHeadModelHeight = 45; - char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); - if(pFile) - { - char token[4096]; - gEngfuncs.COM_ParseFile(pFile, token); - if(token[0] >= '0' && token[0] <= '9') - { - m_VoiceHeadModelHeight = (float)atof(token); - } - - gEngfuncs.COM_FreeFile(pFile); - } - - m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); - return TRUE; -} - - -void CVoiceStatus::Frame(double frametime) -{ - // check server banned players once per second - if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) - { - UpdateServerState(false); - } - - m_BlinkTimer += frametime; - - // Update speaker labels. - if( m_pHelper->CanShowSpeakerLabels() ) - { - for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) - m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); - } - else - { - for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) - m_Labels[i].m_pBackground->setVisible( false ); - } - - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - UpdateBanButton(i); -} - - -void CVoiceStatus::CreateEntities() -{ - if(!m_VoiceHeadModel) - return; - - cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); - - int iOutModel = 0; - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - { - if(!m_VoicePlayers[i]) - continue; - - cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); - - // Don't show an icon if the player is not in our PVS. - if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) - continue; - - // Don't show an icon for dead or spectating players (ie: invisible entities). - if(pClient->curstate.effects & EF_NODRAW) - continue; - - // Don't show an icon for the local player unless we're in thirdperson mode. - if(pClient == localPlayer && !cam_thirdperson) - continue; - - cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; - ++iOutModel; - - memset(pEnt, 0, sizeof(*pEnt)); - - pEnt->curstate.rendermode = kRenderTransAdd; - pEnt->curstate.renderamt = 255; - pEnt->baseline.renderamt = 255; - pEnt->curstate.renderfx = kRenderFxNoDissipation; - pEnt->curstate.framerate = 1; - pEnt->curstate.frame = 0; - pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); - pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; - pEnt->curstate.scale = 0.5f; - - pEnt->origin[0] = pEnt->origin[1] = 0; - pEnt->origin[2] = 45; - - VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); - - // Tell the engine. - gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); - } -} - - -void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) -{ - if(!*m_pParentPanel) - return; - - if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - { - char msg[256]; - _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); - gEngfuncs.pfnConsolePrint( msg ); - } - - // Is it the local player talking? - if( entindex == -1 ) - { - m_bTalking = !!bTalking; - if( bTalking ) - { - // Enable voice for them automatically if they try to talk. - gEngfuncs.pfnClientCmd( "voice_modenable 1" ); - } - } - else if( entindex == -2 ) - { - m_bServerAcked = !!bTalking; - } - else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) - { - int iClient = entindex - 1; - if(iClient < 0) - return; - - CVoiceLabel *pLabel = FindVoiceLabel(iClient); - if(bTalking) - { - m_VoicePlayers[iClient] = true; - m_VoiceEnabledPlayers[iClient] = true; - - // If we don't have a label for this guy yet, then create one. - if(!pLabel) - { - if(pLabel = GetFreeVoiceLabel()) - { - // Get the name from the engine. - hud_player_info_t info; - memset(&info, 0, sizeof(info)); - GetPlayerInfo(entindex, &info); - - char paddedName[512]; - _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); - - int color[3]; - m_pHelper->GetPlayerTextColor( entindex, color ); - - if( pLabel->m_pBackground ) - { - pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); - pLabel->m_pBackground->setParent( *m_pParentPanel ); - pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); - } - - if( pLabel->m_pLabel ) - { - pLabel->m_pLabel->setFgColor( 255, 255, 255, 0 ); - pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); - pLabel->m_pLabel->setText( paddedName ); - } - - pLabel->m_clientindex = iClient; - } - } - } - else - { - m_VoicePlayers[iClient] = false; - - // If we have a label for this guy, kill it. - if(pLabel) - { - pLabel->m_pBackground->setVisible(false); - pLabel->m_clientindex = -1; - } - } - } - - RepositionLabels(); -} - - -void CVoiceStatus::UpdateServerState(bool bForce) -{ - // Can't do anything when we're not in a level. - char const *pLevelName = gEngfuncs.pfnGetLevelName(); - if( pLevelName[0] == 0 ) - { - if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); - } - - return; - } - - int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); - if(bForce || m_bServerModEnable != bCVarModEnable) - { - m_bServerModEnable = bCVarModEnable; - - char str[256]; - _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); - ServerCmd(str); - - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char msg[256]; - sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); - gEngfuncs.pfnConsolePrint(msg); - } - } - - char str[2048]; - sprintf(str, "vban"); - bool bChange = false; - - for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - unsigned long serverBanMask = 0; - unsigned long banMask = 0; - for(unsigned long i=0; i < 32; i++) - { - char playerID[16]; - if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) - continue; - - if(m_BanMgr.GetPlayerBan(playerID)) - banMask |= 1 << i; - - if(m_ServerBannedPlayers[dw*32 + i]) - serverBanMask |= 1 << i; - } - - if(serverBanMask != banMask) - bChange = true; - - // Ok, the server needs to be updated. - char numStr[512]; - sprintf(numStr, " %x", banMask); - strcat(str, numStr); - } - - if(bChange || bForce) - { - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char msg[256]; - sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); - gEngfuncs.pfnConsolePrint(msg); - } - - gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. - } - else - { - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); - } - } - - m_LastUpdateServerState = gEngfuncs.GetClientTime(); -} - -void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) -{ - m_pBanButtons[iPlayer-1] = pLabel; - UpdateBanButton(iPlayer-1); -} - -void CVoiceStatus::UpdateBanButton(int iClient) -{ - Label *pPanel = m_pBanButtons[iClient]; - - if (!pPanel) - return; - - char playerID[16]; - extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); - if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) - return; - - // Figure out if it's blinking or not. - bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; - bool bTalking = !!m_VoicePlayers[iClient]; - bool bBanned = m_BanMgr.GetPlayerBan(playerID); - bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; - - // Get the appropriate image to display on the panel. - if (bBanned) - { - pPanel->setImage(m_pScoreboardBanned); - } - else if (bTalking) - { - if (bBlink) - { - pPanel->setImage(m_pScoreboardSpeaking2); - } - else - { - pPanel->setImage(m_pScoreboardSpeaking); - } - pPanel->setFgColor(255, 170, 0, 1); - } - else if (bNeverSpoken) - { - pPanel->setImage(m_pScoreboardNeverSpoken); - pPanel->setFgColor(100, 100, 100, 1); - } - else - { - pPanel->setImage(m_pScoreboardNotSpeaking); - } -} - - -void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) -{ - BEGIN_READ( pbuf, iSize ); - - unsigned long dw; - for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) - { - m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); - m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); - - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char str[256]; - gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); - - sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); - gEngfuncs.pfnConsolePrint(str); - - sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); - gEngfuncs.pfnConsolePrint(str); - } - } - - m_bServerModEnable = READ_BYTE(); -} - -void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) -{ - if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); - } - - UpdateServerState(true); -} - -void CVoiceStatus::StartSquelchMode() -{ - if(m_bInSquelchMode) - return; - - m_bInSquelchMode = true; - m_pHelper->UpdateCursorState(); -} - -void CVoiceStatus::StopSquelchMode() -{ - m_bInSquelchMode = false; - m_pHelper->UpdateCursorState(); -} - -bool CVoiceStatus::IsInSquelchMode() -{ - return m_bInSquelchMode; -} - -CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) -{ - for(int i=0; i < MAX_VOICE_SPEAKERS; i++) - { - if(m_Labels[i].m_clientindex == clientindex) - return &m_Labels[i]; - } - - return NULL; -} - - -CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() -{ - return FindVoiceLabel(-1); -} - - -void CVoiceStatus::RepositionLabels() -{ - // find starting position to draw from, along right-hand side of screen - int y = ScreenHeight / 2; - - int iconWide = 8, iconTall = 8; - if( m_pSpeakerLabelIcon ) - { - m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); - } - - // Reposition active labels. - for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) - { - CVoiceLabel *pLabel = &m_Labels[i]; - - if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) - { - if( pLabel->m_pBackground ) - pLabel->m_pBackground->setVisible( false ); - - continue; - } - - int textWide, textTall; - pLabel->m_pLabel->getContentSize( textWide, textTall ); - - // Don't let it stretch too far across their screen. - if( textWide > (ScreenWidth*2)/3 ) - textWide = (ScreenWidth*2)/3; - - // Setup the background label to fit everything in. - int border = 2; - int bgWide = textWide + iconWide + border*3; - int bgTall = max( textTall, iconTall ) + border*2; - pLabel->m_pBackground->setBounds( ScreenWidth - bgWide - 8, y, bgWide, bgTall ); - - // Put the text at the left. - pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); - - // Put the icon at the right. - int iconLeft = border + textWide + border; - int iconTop = (bgTall - iconTall) / 2; - if( pLabel->m_pIcon ) - { - pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); - pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); - } - - y += bgTall + 2; - } - - if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) - { - m_pLocalLabel->setParent(*m_pParentPanel); - m_pLocalLabel->setVisible( true ); - - if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) - m_pLocalLabel->setImage( m_pAckBitmap ); - else - m_pLocalLabel->setImage( m_pLocalBitmap ); - - int sizeX, sizeY; - m_pLocalBitmap->getSize(sizeX, sizeY); - - int local_xPos = ScreenWidth - sizeX - 10; - int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; - - m_pLocalLabel->setPos( local_xPos, local_yPos ); - } - else - { - m_pLocalLabel->setVisible( false ); - } -} - - -void CVoiceStatus::FreeBitmaps() -{ - // Delete all the images we have loaded. - delete m_pLocalBitmap; - m_pLocalBitmap = NULL; - - delete m_pAckBitmap; - m_pAckBitmap = NULL; - - delete m_pSpeakerLabelIcon; - m_pSpeakerLabelIcon = NULL; - - delete m_pScoreboardNeverSpoken; - m_pScoreboardNeverSpoken = NULL; - - delete m_pScoreboardNotSpeaking; - m_pScoreboardNotSpeaking = NULL; - - delete m_pScoreboardSpeaking; - m_pScoreboardSpeaking = NULL; - - delete m_pScoreboardSpeaking2; - m_pScoreboardSpeaking2 = NULL; - - delete m_pScoreboardSquelch; - m_pScoreboardSquelch = NULL; - - delete m_pScoreboardBanned; - m_pScoreboardBanned = NULL; - - // Clear references to the images in panels. - for(int i=0; i < VOICE_MAX_PLAYERS; i++) - { - if (m_pBanButtons[i]) - { - m_pBanButtons[i]->setImage(NULL); - } - } - - if(m_pLocalLabel) - m_pLocalLabel->setImage(NULL); -} - -//----------------------------------------------------------------------------- -// Purpose: returns true if the target client has been banned -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CVoiceStatus::IsPlayerBlocked(int iPlayer) -{ - char playerID[16]; - if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) - return false; - - return m_BanMgr.GetPlayerBan(playerID); -} - -//----------------------------------------------------------------------------- -// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CVoiceStatus::IsPlayerAudible(int iPlayer) -{ - return !!m_AudiblePlayers[iPlayer-1]; -} - -//----------------------------------------------------------------------------- -// Purpose: blocks/unblocks the target client from being heard -// Input : playerID - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) -{ - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); - } - - char playerID[16]; - if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) - return; - - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); - } - - // Squelch or (try to) unsquelch this player. - if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) - { - char str[256]; - sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); - gEngfuncs.pfnConsolePrint(str); - } - - m_BanMgr.SetPlayerBan( playerID, blocked ); - UpdateServerState(false); -} +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// There are hud.h's coming out of the woodwork so this ensures that we get the right one. +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/hud.h" + #include "../dmc/cl_dll/cl_util.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/hud.h" + #include "../ricochet/cl_dll/cl_util.h" +#else + #include "../cl_dll/hud.h" + #include "../cl_dll/cl_util.h" +#endif + +#include +#include +#include + +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/parsemsg.h" + #include "../dmc/cl_dll/hud_servers.h" + #include "../dmc/cl_dll/demo.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/parsemsg.h" + #include "../ricochet/cl_dll/hud_servers.h" + #include "../ricochet/cl_dll/demo.h" +#else + #include "../cl_dll/parsemsg.h" + #include "../cl_dll/hud_servers.h" + #include "../cl_dll/demo.h" +#endif + +#include "demo_api.h" +#include "voice_status.h" +#include "r_efx.h" +#include "entity_types.h" +#include "VGUI_ActionSignal.h" +#include "VGUI_Scheme.h" +#include "VGUI_TextImage.h" +#include "vgui_loadtga.h" +#include "vgui_helpers.h" +#include "vgui_mousecode.h" + + + +using namespace vgui; + + +extern int cam_thirdperson; + + +#define VOICE_MODEL_INTERVAL 0.3 +#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. +#define SQUELCHOSCILLATE_PER_SECOND 2.0f + + +extern BitmapTGA *LoadTGA( const char* pImageName ); + + + +// ---------------------------------------------------------------------- // +// The voice manager for the client. +// ---------------------------------------------------------------------- // +CVoiceStatus g_VoiceStatus; + +CVoiceStatus* GetClientVoiceMgr() +{ + return &g_VoiceStatus; +} + + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +static CVoiceStatus *g_pInternalVoiceStatus = NULL; + +int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); + + return 1; +} + +int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); + + return 1; +} + + +int g_BannedPlayerPrintCount; +void ForEachBannedPlayer(char id[16]) +{ + char str[256]; + sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", + g_BannedPlayerPrintCount++, + id[0], id[1], id[2], id[3], + id[4], id[5], id[6], id[7], + id[8], id[9], id[10], id[11], + id[12], id[13], id[14], id[15] + ); + strupr(str); + gEngfuncs.pfnConsolePrint(str); +} + + +void ShowBannedCallback() +{ + if(g_pInternalVoiceStatus) + { + g_BannedPlayerPrintCount = 0; + gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); + g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); + gEngfuncs.pfnConsolePrint("------------------------------\n"); + } +} + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +CVoiceStatus::CVoiceStatus() +{ + m_bBanMgrInitialized = false; + m_LastUpdateServerState = 0; + + m_pSpeakerLabelIcon = NULL; + m_pScoreboardNeverSpoken = NULL; + m_pScoreboardNotSpeaking = NULL; + m_pScoreboardSpeaking = NULL; + m_pScoreboardSpeaking2 = NULL; + m_pScoreboardSquelch = NULL; + m_pScoreboardBanned = NULL; + + m_pLocalBitmap = NULL; + m_pAckBitmap = NULL; + + m_bTalking = m_bServerAcked = false; + + memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); + + m_bServerModEnable = -1; + + m_pchGameDir = NULL; +} + + +CVoiceStatus::~CVoiceStatus() +{ + g_pInternalVoiceStatus = NULL; + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + delete m_Labels[i].m_pLabel; + m_Labels[i].m_pLabel = NULL; + + delete m_Labels[i].m_pIcon; + m_Labels[i].m_pIcon = NULL; + + delete m_Labels[i].m_pBackground; + m_Labels[i].m_pBackground = NULL; + } + + delete m_pLocalLabel; + m_pLocalLabel = NULL; + + FreeBitmaps(); + + if(m_pchGameDir) + { + if(m_bBanMgrInitialized) + { + m_BanMgr.SaveState(m_pchGameDir); + } + + free(m_pchGameDir); + } +} + + +int CVoiceStatus::Init( + IVoiceStatusHelper *pHelper, + Panel **pParentPanel) +{ + // Setup the voice_modenable cvar. + gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); + + gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); + + gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); + + if(gEngfuncs.pfnGetGameDirectory()) + { + m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); + m_bBanMgrInitialized = true; + } + + assert(!g_pInternalVoiceStatus); + g_pInternalVoiceStatus = this; + + m_BlinkTimer = 0; + m_VoiceHeadModel = NULL; + memset(m_Labels, 0, sizeof(m_Labels)); + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + pLabel->m_pBackground = new Label(""); + + if(pLabel->m_pLabel = new Label("")) + { + pLabel->m_pLabel->setVisible( true ); + pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); + pLabel->m_pLabel->setTextAlignment( Label::a_east ); + pLabel->m_pLabel->setContentAlignment( Label::a_east ); + pLabel->m_pLabel->setParent( pLabel->m_pBackground ); + } + + if( pLabel->m_pIcon = new ImagePanel( NULL ) ) + { + pLabel->m_pIcon->setVisible( true ); + pLabel->m_pIcon->setParent( pLabel->m_pBackground ); + } + + pLabel->m_clientindex = -1; + } + + m_pLocalLabel = new ImagePanel(NULL); + + m_bInSquelchMode = false; + + m_pHelper = pHelper; + m_pParentPanel = pParentPanel; + gHUD.AddHudElem(this); + m_iFlags = HUD_ACTIVE; + HOOK_MESSAGE(VoiceMask); + HOOK_MESSAGE(ReqState); + + // Cache the game directory for use when we shut down + const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); + m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); + strcpy(m_pchGameDir, pchGameDirT); + + return 1; +} + + +int CVoiceStatus::VidInit() +{ + FreeBitmaps(); + + + if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) + { + m_pLocalBitmap->setColor(Color(255,255,255,135)); + } + + if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) + { + m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. + } + + m_pLocalLabel->setImage( m_pLocalBitmap ); + m_pLocalLabel->setVisible( false ); + + + if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) + m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. + + if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) + m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) + m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) + m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) + m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) + m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) + m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + // Figure out the voice head model height. + m_VoiceHeadModelHeight = 45; + char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); + if(pFile) + { + char token[4096]; + gEngfuncs.COM_ParseFile(pFile, token); + if(token[0] >= '0' && token[0] <= '9') + { + m_VoiceHeadModelHeight = (float)atof(token); + } + + gEngfuncs.COM_FreeFile(pFile); + } + + m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); + return TRUE; +} + + +void CVoiceStatus::Frame(double frametime) +{ + // check server banned players once per second + if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) + { + UpdateServerState(false); + } + + m_BlinkTimer += frametime; + + // Update speaker labels. + if( m_pHelper->CanShowSpeakerLabels() ) + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); + } + else + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( false ); + } + + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + UpdateBanButton(i); +} + + +void CVoiceStatus::CreateEntities() +{ + if(!m_VoiceHeadModel) + return; + + cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); + + int iOutModel = 0; + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if(!m_VoicePlayers[i]) + continue; + + cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); + + // Don't show an icon if the player is not in our PVS. + if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) + continue; + + // Don't show an icon for dead or spectating players (ie: invisible entities). + if(pClient->curstate.effects & EF_NODRAW) + continue; + + // Don't show an icon for the local player unless we're in thirdperson mode. + if(pClient == localPlayer && !cam_thirdperson) + continue; + + cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; + ++iOutModel; + + memset(pEnt, 0, sizeof(*pEnt)); + + pEnt->curstate.rendermode = kRenderTransAdd; + pEnt->curstate.renderamt = 255; + pEnt->baseline.renderamt = 255; + pEnt->curstate.renderfx = kRenderFxNoDissipation; + pEnt->curstate.framerate = 1; + pEnt->curstate.frame = 0; + pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); + pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; + pEnt->curstate.scale = 0.5f; + + pEnt->origin[0] = pEnt->origin[1] = 0; + pEnt->origin[2] = 45; + + VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); + + // Tell the engine. + gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); + } +} + + +void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) +{ + if(!*m_pParentPanel) + return; + + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + char msg[256]; + _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); + gEngfuncs.pfnConsolePrint( msg ); + } + + // Is it the local player talking? + if( entindex == -1 ) + { + m_bTalking = !!bTalking; + if( bTalking ) + { + // Enable voice for them automatically if they try to talk. + gEngfuncs.pfnClientCmd( "voice_modenable 1" ); + } + } + else if( entindex == -2 ) + { + m_bServerAcked = !!bTalking; + } + else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) + { + int iClient = entindex - 1; + if(iClient < 0) + return; + + CVoiceLabel *pLabel = FindVoiceLabel(iClient); + if(bTalking) + { + m_VoicePlayers[iClient] = true; + m_VoiceEnabledPlayers[iClient] = true; + + // If we don't have a label for this guy yet, then create one. + if(!pLabel) + { + if(pLabel = GetFreeVoiceLabel()) + { + // Get the name from the engine. + hud_player_info_t info; + memset(&info, 0, sizeof(info)); + GetPlayerInfo(entindex, &info); + + char paddedName[512]; + _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); + + int color[3]; + m_pHelper->GetPlayerTextColor( entindex, color ); + + if( pLabel->m_pBackground ) + { + pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); + pLabel->m_pBackground->setParent( *m_pParentPanel ); + pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); + } + + if( pLabel->m_pLabel ) + { + pLabel->m_pLabel->setFgColor( 255, 255, 255, 0 ); + pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); + pLabel->m_pLabel->setText( paddedName ); + } + + pLabel->m_clientindex = iClient; + } + } + } + else + { + m_VoicePlayers[iClient] = false; + + // If we have a label for this guy, kill it. + if(pLabel) + { + pLabel->m_pBackground->setVisible(false); + pLabel->m_clientindex = -1; + } + } + } + + RepositionLabels(); +} + + +void CVoiceStatus::UpdateServerState(bool bForce) +{ + // Can't do anything when we're not in a level. + char const *pLevelName = gEngfuncs.pfnGetLevelName(); + if( pLevelName[0] == 0 ) + { + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); + } + + return; + } + + int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); + if(bForce || m_bServerModEnable != bCVarModEnable) + { + m_bServerModEnable = bCVarModEnable; + + char str[256]; + _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); + ServerCmd(str); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + } + + char str[2048]; + sprintf(str, "vban"); + bool bChange = false; + + for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + unsigned long serverBanMask = 0; + unsigned long banMask = 0; + for(unsigned long i=0; i < 32; i++) + { + char playerID[16]; + if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) + continue; + + if(m_BanMgr.GetPlayerBan(playerID)) + banMask |= 1 << i; + + if(m_ServerBannedPlayers[dw*32 + i]) + serverBanMask |= 1 << i; + } + + if(serverBanMask != banMask) + bChange = true; + + // Ok, the server needs to be updated. + char numStr[512]; + sprintf(numStr, " %x", banMask); + strcat(str, numStr); + } + + if(bChange || bForce) + { + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + + gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. + } + else + { + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); + } + } + + m_LastUpdateServerState = gEngfuncs.GetClientTime(); +} + +void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) +{ + m_pBanButtons[iPlayer-1] = pLabel; + UpdateBanButton(iPlayer-1); +} + +void CVoiceStatus::UpdateBanButton(int iClient) +{ + Label *pPanel = m_pBanButtons[iClient]; + + if (!pPanel) + return; + + char playerID[16]; + extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); + if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) + return; + + // Figure out if it's blinking or not. + bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; + bool bTalking = !!m_VoicePlayers[iClient]; + bool bBanned = m_BanMgr.GetPlayerBan(playerID); + bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; + + // Get the appropriate image to display on the panel. + if (bBanned) + { + pPanel->setImage(m_pScoreboardBanned); + } + else if (bTalking) + { + if (bBlink) + { + pPanel->setImage(m_pScoreboardSpeaking2); + } + else + { + pPanel->setImage(m_pScoreboardSpeaking); + } + pPanel->setFgColor(255, 170, 0, 1); + } + else if (bNeverSpoken) + { + pPanel->setImage(m_pScoreboardNeverSpoken); + pPanel->setFgColor(100, 100, 100, 1); + } + else + { + pPanel->setImage(m_pScoreboardNotSpeaking); + } +} + + +void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + unsigned long dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); + m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); + + sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + + sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + } + } + + m_bServerModEnable = READ_BYTE(); +} + +void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) +{ + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); + } + + UpdateServerState(true); +} + +void CVoiceStatus::StartSquelchMode() +{ + if(m_bInSquelchMode) + return; + + m_bInSquelchMode = true; + m_pHelper->UpdateCursorState(); +} + +void CVoiceStatus::StopSquelchMode() +{ + m_bInSquelchMode = false; + m_pHelper->UpdateCursorState(); +} + +bool CVoiceStatus::IsInSquelchMode() +{ + return m_bInSquelchMode; +} + +CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) +{ + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + if(m_Labels[i].m_clientindex == clientindex) + return &m_Labels[i]; + } + + return NULL; +} + + +CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() +{ + return FindVoiceLabel(-1); +} + + +void CVoiceStatus::RepositionLabels() +{ + // find starting position to draw from, along right-hand side of screen + int y = ScreenHeight / 2; + + int iconWide = 8, iconTall = 8; + if( m_pSpeakerLabelIcon ) + { + m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); + } + + // Reposition active labels. + for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) + { + if( pLabel->m_pBackground ) + pLabel->m_pBackground->setVisible( false ); + + continue; + } + + int textWide, textTall; + pLabel->m_pLabel->getContentSize( textWide, textTall ); + + // Don't let it stretch too far across their screen. + if( textWide > (ScreenWidth*2)/3 ) + textWide = (ScreenWidth*2)/3; + + // Setup the background label to fit everything in. + int border = 2; + int bgWide = textWide + iconWide + border*3; + int bgTall = max( textTall, iconTall ) + border*2; + pLabel->m_pBackground->setBounds( ScreenWidth - bgWide - 8, y, bgWide, bgTall ); + + // Put the text at the left. + pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); + + // Put the icon at the right. + int iconLeft = border + textWide + border; + int iconTop = (bgTall - iconTall) / 2; + if( pLabel->m_pIcon ) + { + pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); + pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); + } + + y += bgTall + 2; + } + + if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) + { + m_pLocalLabel->setParent(*m_pParentPanel); + m_pLocalLabel->setVisible( true ); + + if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + m_pLocalLabel->setImage( m_pAckBitmap ); + else + m_pLocalLabel->setImage( m_pLocalBitmap ); + + int sizeX, sizeY; + m_pLocalBitmap->getSize(sizeX, sizeY); + + int local_xPos = ScreenWidth - sizeX - 10; + int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; + + m_pLocalLabel->setPos( local_xPos, local_yPos ); + } + else + { + m_pLocalLabel->setVisible( false ); + } +} + + +void CVoiceStatus::FreeBitmaps() +{ + // Delete all the images we have loaded. + delete m_pLocalBitmap; + m_pLocalBitmap = NULL; + + delete m_pAckBitmap; + m_pAckBitmap = NULL; + + delete m_pSpeakerLabelIcon; + m_pSpeakerLabelIcon = NULL; + + delete m_pScoreboardNeverSpoken; + m_pScoreboardNeverSpoken = NULL; + + delete m_pScoreboardNotSpeaking; + m_pScoreboardNotSpeaking = NULL; + + delete m_pScoreboardSpeaking; + m_pScoreboardSpeaking = NULL; + + delete m_pScoreboardSpeaking2; + m_pScoreboardSpeaking2 = NULL; + + delete m_pScoreboardSquelch; + m_pScoreboardSquelch = NULL; + + delete m_pScoreboardBanned; + m_pScoreboardBanned = NULL; + + // Clear references to the images in panels. + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if (m_pBanButtons[i]) + { + m_pBanButtons[i]->setImage(NULL); + } + } + + if(m_pLocalLabel) + m_pLocalLabel->setImage(NULL); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the target client has been banned +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerBlocked(int iPlayer) +{ + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return false; + + return m_BanMgr.GetPlayerBan(playerID); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerAudible(int iPlayer) +{ + return !!m_AudiblePlayers[iPlayer-1]; +} + +//----------------------------------------------------------------------------- +// Purpose: blocks/unblocks the target client from being heard +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) +{ + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); + } + + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return; + + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); + } + + // Squelch or (try to) unsquelch this player. + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); + gEngfuncs.pfnConsolePrint(str); + } + + m_BanMgr.SetPlayerBan( playerID, blocked ); + UpdateServerState(false); +} diff --git a/game_shared/voice_status.h b/game_shared/voice_status.h index 7825083a..509902e5 100644 --- a/game_shared/voice_status.h +++ b/game_shared/voice_status.h @@ -1,228 +1,228 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_STATUS_H -#define VOICE_STATUS_H -#pragma once - - -#include "VGUI_Label.h" -#include "VGUI_LineBorder.h" -#include "VGUI_ImagePanel.h" -#include "VGUI_BitmapTGA.h" -#include "VGUI_InputSignal.h" -#include "VGUI_Button.h" -#include "voice_common.h" -#include "cl_entity.h" -#include "voice_banmgr.h" -#include "vgui_checkbutton2.h" -#include "vgui_defaultinputsignal.h" - - -class CVoiceStatus; - - -class CVoiceLabel -{ -public: - vgui::Label *m_pLabel; - vgui::Label *m_pBackground; - vgui::ImagePanel *m_pIcon; // Voice icon next to player name. - int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. -}; - - -// This is provided by each mod to access data that may not be the same across mods. -class IVoiceStatusHelper -{ -public: - virtual ~IVoiceStatusHelper() {} - - // Get RGB color for voice status text about this player. - virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; - - // Force it to update the cursor state. - virtual void UpdateCursorState() = 0; - - // Return the height above the bottom that the voice ack icons should be drawn at. - virtual int GetAckIconHeight() = 0; - - // Return true if the voice manager is allowed to show speaker labels - // (mods usually return false when the scoreboard is up). - virtual bool CanShowSpeakerLabels() = 0; -}; - -//----------------------------------------------------------------------------- -// Purpose: Holds a color for the shared image -//----------------------------------------------------------------------------- -class VoiceImagePanel : public vgui::ImagePanel -{ - virtual void paintBackground() - { - if (_image!=null) - { - vgui::Color col; - getFgColor(col); - _image->setColor(col); - _image->doPaint(this); - } - } -}; - - -class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal -{ -public: - CVoiceStatus(); - virtual ~CVoiceStatus(); - -// CHudBase overrides. -public: - - // Initialize the cl_dll's voice manager. - virtual int Init( - IVoiceStatusHelper *m_pHelper, - vgui::Panel **pParentPanel); - - // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. - virtual int VidInit(); - - -public: - - // Call from HUD_Frame each frame. - void Frame(double frametime); - - // Called when a player starts or stops talking. - // entindex is -1 to represent the local client talking (before the data comes back from the server). - // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). - // entindex is -2 to represent the local client's voice being acked by the server. - void UpdateSpeakerStatus(int entindex, qboolean bTalking); - - // sets the correct image in the label for the player - void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); - - // Call from the HUD_CreateEntities function so it can add sprites above player heads. - void CreateEntities(); - - // Called when the server registers a change to who this client can hear. - void HandleVoiceMaskMsg(int iSize, void *pbuf); - - // The server sends this message initially to tell the client to send their state. - void HandleReqStateMsg(int iSize, void *pbuf); - - -// Squelch mode functions. -public: - - // When you enter squelch mode, pass in - void StartSquelchMode(); - void StopSquelchMode(); - bool IsInSquelchMode(); - - // returns true if the target client has been banned - // playerIndex is of range 1..maxplayers - bool IsPlayerBlocked(int iPlayerIndex); - - // returns false if the player can't hear the other client due to game rules (eg. the other team) - bool IsPlayerAudible(int iPlayerIndex); - - // blocks the target client from being heard - void SetPlayerBlockedState(int iPlayerIndex, bool blocked); - -public: - - CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. - // Returns NULL if none. - // entindex can be -1 if you want a currently-unused voice label. - CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. - - void RepositionLabels(); - - void FreeBitmaps(); - - void UpdateServerState(bool bForce); - - // Update the button artwork to reflect the client's current state. - void UpdateBanButton(int iClient); - - -public: - - enum {MAX_VOICE_SPEAKERS=7}; - - float m_LastUpdateServerState; // Last time we called this function. - int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. - - vgui::Panel **m_pParentPanel; - CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. - - // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on - // and is totally separate from the ban list. Indexed by client index. - CPlayerBitVec m_AudiblePlayers; - - // Players who have spoken at least once in the game so far - CPlayerBitVec m_VoiceEnabledPlayers; - - // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). - // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. - CPlayerBitVec m_ServerBannedPlayers; - - cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just - // a place for it to put data in during CreateEntities. - - IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. - - - // Scoreboard icons. - double m_BlinkTimer; // Blink scoreboard icons.. - vgui::BitmapTGA *m_pScoreboardNeverSpoken; - vgui::BitmapTGA *m_pScoreboardNotSpeaking; - vgui::BitmapTGA *m_pScoreboardSpeaking; - vgui::BitmapTGA *m_pScoreboardSpeaking2; - vgui::BitmapTGA *m_pScoreboardSquelch; - vgui::BitmapTGA *m_pScoreboardBanned; - - vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. - - // Squelch mode stuff. - bool m_bInSquelchMode; - - HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). - float m_VoiceHeadModelHeight; // Height above their head to place the model. - - vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. - - // Lower-right icons telling when the local player is talking.. - vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. - vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. - vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. - - bool m_bTalking; // Set to true when the client thinks it's talking. - bool m_bServerAcked; // Set to true when the server knows the client is talking. - -public: - - CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. - -public: - - bool m_bBanMgrInitialized; - - // Labels telling who is speaking. - CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; - - // Cache the game directory for use when we shut down - char * m_pchGameDir; -}; - - -// Get the (global) voice manager. -CVoiceStatus* GetClientVoiceMgr(); - - -#endif // VOICE_STATUS_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_STATUS_H +#define VOICE_STATUS_H +#pragma once + + +#include "VGUI_Label.h" +#include "VGUI_LineBorder.h" +#include "VGUI_ImagePanel.h" +#include "VGUI_BitmapTGA.h" +#include "VGUI_InputSignal.h" +#include "VGUI_Button.h" +#include "voice_common.h" +#include "cl_entity.h" +#include "voice_banmgr.h" +#include "vgui_checkbutton2.h" +#include "vgui_defaultinputsignal.h" + + +class CVoiceStatus; + + +class CVoiceLabel +{ +public: + vgui::Label *m_pLabel; + vgui::Label *m_pBackground; + vgui::ImagePanel *m_pIcon; // Voice icon next to player name. + int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. +}; + + +// This is provided by each mod to access data that may not be the same across mods. +class IVoiceStatusHelper +{ +public: + virtual ~IVoiceStatusHelper() {} + + // Get RGB color for voice status text about this player. + virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; + + // Force it to update the cursor state. + virtual void UpdateCursorState() = 0; + + // Return the height above the bottom that the voice ack icons should be drawn at. + virtual int GetAckIconHeight() = 0; + + // Return true if the voice manager is allowed to show speaker labels + // (mods usually return false when the scoreboard is up). + virtual bool CanShowSpeakerLabels() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Holds a color for the shared image +//----------------------------------------------------------------------------- +class VoiceImagePanel : public vgui::ImagePanel +{ + virtual void paintBackground() + { + if (_image!=null) + { + vgui::Color col; + getFgColor(col); + _image->setColor(col); + _image->doPaint(this); + } + } +}; + + +class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal +{ +public: + CVoiceStatus(); + virtual ~CVoiceStatus(); + +// CHudBase overrides. +public: + + // Initialize the cl_dll's voice manager. + virtual int Init( + IVoiceStatusHelper *m_pHelper, + vgui::Panel **pParentPanel); + + // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. + virtual int VidInit(); + + +public: + + // Call from HUD_Frame each frame. + void Frame(double frametime); + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). + // entindex is -2 to represent the local client's voice being acked by the server. + void UpdateSpeakerStatus(int entindex, qboolean bTalking); + + // sets the correct image in the label for the player + void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); + + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void CreateEntities(); + + // Called when the server registers a change to who this client can hear. + void HandleVoiceMaskMsg(int iSize, void *pbuf); + + // The server sends this message initially to tell the client to send their state. + void HandleReqStateMsg(int iSize, void *pbuf); + + +// Squelch mode functions. +public: + + // When you enter squelch mode, pass in + void StartSquelchMode(); + void StopSquelchMode(); + bool IsInSquelchMode(); + + // returns true if the target client has been banned + // playerIndex is of range 1..maxplayers + bool IsPlayerBlocked(int iPlayerIndex); + + // returns false if the player can't hear the other client due to game rules (eg. the other team) + bool IsPlayerAudible(int iPlayerIndex); + + // blocks the target client from being heard + void SetPlayerBlockedState(int iPlayerIndex, bool blocked); + +public: + + CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. + // Returns NULL if none. + // entindex can be -1 if you want a currently-unused voice label. + CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. + + void RepositionLabels(); + + void FreeBitmaps(); + + void UpdateServerState(bool bForce); + + // Update the button artwork to reflect the client's current state. + void UpdateBanButton(int iClient); + + +public: + + enum {MAX_VOICE_SPEAKERS=7}; + + float m_LastUpdateServerState; // Last time we called this function. + int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. + + vgui::Panel **m_pParentPanel; + CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. + + // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on + // and is totally separate from the ban list. Indexed by client index. + CPlayerBitVec m_AudiblePlayers; + + // Players who have spoken at least once in the game so far + CPlayerBitVec m_VoiceEnabledPlayers; + + // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). + // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. + CPlayerBitVec m_ServerBannedPlayers; + + cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just + // a place for it to put data in during CreateEntities. + + IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. + + + // Scoreboard icons. + double m_BlinkTimer; // Blink scoreboard icons.. + vgui::BitmapTGA *m_pScoreboardNeverSpoken; + vgui::BitmapTGA *m_pScoreboardNotSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking2; + vgui::BitmapTGA *m_pScoreboardSquelch; + vgui::BitmapTGA *m_pScoreboardBanned; + + vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. + + // Squelch mode stuff. + bool m_bInSquelchMode; + + HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). + float m_VoiceHeadModelHeight; // Height above their head to place the model. + + vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. + + // Lower-right icons telling when the local player is talking.. + vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. + vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. + vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. + + bool m_bTalking; // Set to true when the client thinks it's talking. + bool m_bServerAcked; // Set to true when the server knows the client is talking. + +public: + + CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. + +public: + + bool m_bBanMgrInitialized; + + // Labels telling who is speaking. + CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; + + // Cache the game directory for use when we shut down + char * m_pchGameDir; +}; + + +// Get the (global) voice manager. +CVoiceStatus* GetClientVoiceMgr(); + + +#endif // VOICE_STATUS_H diff --git a/game_shared/voice_vgui_tweakdlg.cpp b/game_shared/voice_vgui_tweakdlg.cpp index b5cde708..07f02ad7 100644 --- a/game_shared/voice_vgui_tweakdlg.cpp +++ b/game_shared/voice_vgui_tweakdlg.cpp @@ -1,289 +1,289 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include "../cl_dll/hud.h" -#include "../cl_dll/cl_util.h" -#include "../cl_dll/vgui_teamfortressviewport.h" - - -#include "vgui_actionsignal.h" -#include "voice_vgui_tweakdlg.h" -#include "voice_vgui_tweakdlg.h" -#include "vgui_panel.h" -#include "vgui_scrollbar.h" -#include "vgui_slider.h" -#include "ivoicetweak.h" -#include "vgui_button.h" -#include "vgui_checkbutton2.h" -#include "vgui_helpers.h" - - -#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. -#define VOICETWEAK_TRANSPARENCY 150 - - -class TweakScroller -{ -public: - TweakScroller(); - void Init(Panel *pParent, char *pText, int yPos); - - // Get/set value. Values are 0-1. - float GetValue(); - void SetValue(float val); - -public: - Label m_Label; - ScrollBar m_Scroll; - Slider m_Slider; -}; - - -class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler -{ -typedef CMenuPanel BaseClass; - -public: - CVoiceVGUITweakDlg(); - ~CVoiceVGUITweakDlg(); - -// CMenuPanel overrides. -public: - virtual void Open(); - virtual void Close(); - - -// ICheckButton2Handler overrides. -public: - - virtual void StateChanged(CCheckButton2 *pButton); - - - -// Panel overrides. -public: - virtual void paintBackground(); - - -private: - - int m_DlgWidth; - int m_DlgHeight; - - Label m_Label; - - IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. - - TweakScroller m_MicVolume; - TweakScroller m_SpeakerVolume; - - CCheckButton2 m_VoiceModEnable; - - Button m_Button_OK; -}; - - - -bool g_bTweakDlgOpen = false; - -bool IsTweakDlgOpen() -{ - return g_bTweakDlgOpen; -} - - - -// ------------------------------------------------------------------------ // -// Global functions. -// ------------------------------------------------------------------------ // - -static CVoiceVGUITweakDlg g_VoiceTweakDlg; -CMenuPanel* GetVoiceTweakDlg() -{ - return &g_VoiceTweakDlg; -} - - -class CVoiceTweakOKButton : public ActionSignal -{ -public: - virtual void actionPerformed(Panel *pPanel) - { - gViewPort->HideVGUIMenu(); - } -}; -CVoiceTweakOKButton g_OKButtonSignal; - - - -// ------------------------------------------------------------------------ // -// TweakScroller -// ------------------------------------------------------------------------ // - -TweakScroller::TweakScroller() : - m_Label(""), - m_Scroll(0,0,0,0,false), - m_Slider(0,0,10,10,false) -{ -} - - -void TweakScroller::Init(Panel *pParent, char *pText, int yPos) -{ - int parentWidth, parentHeight; - pParent->getSize(parentWidth, parentHeight); - - // Setup the volume scroll bar. - m_Label.setParent(pParent); - m_Label.setFont(Scheme::sf_primary1); - m_Label.setContentAlignment(vgui::Label::a_northwest); - m_Label.setBgColor(0, 0, 0, 255); - m_Label.setFgColor(255,255,255,0); - m_Label.setPos(ITEM_BORDER, yPos); - m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); - m_Label.setText(pText); - m_Label.setVisible(true); - - m_Slider.setRangeWindow(10); - m_Slider.setRangeWindowEnabled(true); - - m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); - m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); - m_Scroll.setSlider(&m_Slider); - m_Scroll.setParent(pParent); - m_Scroll.setRange(0, 100); - m_Scroll.setFgColor(255,255,255,0); - m_Scroll.setBgColor(255,255,255,0); -} - - -float TweakScroller::GetValue() -{ - return m_Scroll.getValue() / 100.0f; -} - - -void TweakScroller::SetValue(float val) -{ - m_Scroll.setValue((int)(val * 100.0f)); -} - - -// ------------------------------------------------------------------------ // -// CVoiceVGUITweakDlg implementation. -// ------------------------------------------------------------------------ // - -CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() - : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), - m_Button_OK("",0,0), - m_Label("") -{ - m_pVoiceTweak = NULL; - m_Button_OK.addActionSignal(&g_OKButtonSignal); - m_Label.setBgColor(255,255,255,200); -} - - -CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() -{ -} - - -void CVoiceVGUITweakDlg::Open() -{ - if(g_bTweakDlgOpen) - return; - - g_bTweakDlgOpen = true; - - m_DlgWidth = ScreenWidth; - m_DlgHeight = ScreenHeight; - - m_pVoiceTweak = gEngfuncs.pVoiceTweak; - - // Tell the engine to start voice tweak mode (pipe voice output right to speakers). - m_pVoiceTweak->StartVoiceTweakMode(); - - // Set our size. - setPos((ScreenWidth - m_DlgWidth) / 2, (ScreenHeight - m_DlgHeight) / 2); - setSize(m_DlgWidth, m_DlgHeight); - - int curY = ITEM_BORDER; - m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); - m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); - curY = PanelBottom(&m_MicVolume.m_Label); - - m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); - m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); - curY = PanelBottom(&m_SpeakerVolume.m_Label); - - m_VoiceModEnable.setParent(this); - m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); - m_VoiceModEnable.SetText("Enable Voice In This Mod"); - m_VoiceModEnable.setPos(ITEM_BORDER, curY); - m_VoiceModEnable.SetCheckboxLeft(false); - m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); - m_VoiceModEnable.SetHandler(this); - - // Setup the OK button. - int buttonWidth, buttonHeight; - m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); - m_Button_OK.getSize(buttonWidth, buttonHeight); - m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); - m_Button_OK.setParent(this); - - // Put the label on the top. - m_Label.setBgColor(0, 0, 0, 255); - m_Label.setFgColor(255,255,255,0); - m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); - int labelWidth, labelHeight; - m_Label.getSize(labelWidth, labelHeight); - m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); - m_Label.setParent(this); - - BaseClass::Open(); -} - - -void CVoiceVGUITweakDlg::Close() -{ - m_pVoiceTweak->EndVoiceTweakMode(); - g_bTweakDlgOpen = false; - - BaseClass::Close(); -} - - -void CVoiceVGUITweakDlg::paintBackground() -{ - BaseClass::paintBackground(); - - // Draw our border. - int w,h; - getSize(w,h); - - drawSetColor(128,128,128,1); - drawOutlinedRect(0, 0, w, h); - - float volume = m_MicVolume.GetValue(); - m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); - - m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); -} - - -void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) -{ - if(pButton == &m_VoiceModEnable) - { - if(pButton->IsChecked()) - gEngfuncs.pfnClientCmd("voice_modenable 1"); - else - gEngfuncs.pfnClientCmd("voice_modenable 0"); - } -} - +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/hud.h" +#include "../cl_dll/cl_util.h" +#include "../cl_dll/vgui_teamfortressviewport.h" + + +#include "vgui_actionsignal.h" +#include "voice_vgui_tweakdlg.h" +#include "voice_vgui_tweakdlg.h" +#include "vgui_panel.h" +#include "vgui_scrollbar.h" +#include "vgui_slider.h" +#include "ivoicetweak.h" +#include "vgui_button.h" +#include "vgui_checkbutton2.h" +#include "vgui_helpers.h" + + +#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. +#define VOICETWEAK_TRANSPARENCY 150 + + +class TweakScroller +{ +public: + TweakScroller(); + void Init(Panel *pParent, char *pText, int yPos); + + // Get/set value. Values are 0-1. + float GetValue(); + void SetValue(float val); + +public: + Label m_Label; + ScrollBar m_Scroll; + Slider m_Slider; +}; + + +class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler +{ +typedef CMenuPanel BaseClass; + +public: + CVoiceVGUITweakDlg(); + ~CVoiceVGUITweakDlg(); + +// CMenuPanel overrides. +public: + virtual void Open(); + virtual void Close(); + + +// ICheckButton2Handler overrides. +public: + + virtual void StateChanged(CCheckButton2 *pButton); + + + +// Panel overrides. +public: + virtual void paintBackground(); + + +private: + + int m_DlgWidth; + int m_DlgHeight; + + Label m_Label; + + IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. + + TweakScroller m_MicVolume; + TweakScroller m_SpeakerVolume; + + CCheckButton2 m_VoiceModEnable; + + Button m_Button_OK; +}; + + + +bool g_bTweakDlgOpen = false; + +bool IsTweakDlgOpen() +{ + return g_bTweakDlgOpen; +} + + + +// ------------------------------------------------------------------------ // +// Global functions. +// ------------------------------------------------------------------------ // + +static CVoiceVGUITweakDlg g_VoiceTweakDlg; +CMenuPanel* GetVoiceTweakDlg() +{ + return &g_VoiceTweakDlg; +} + + +class CVoiceTweakOKButton : public ActionSignal +{ +public: + virtual void actionPerformed(Panel *pPanel) + { + gViewPort->HideVGUIMenu(); + } +}; +CVoiceTweakOKButton g_OKButtonSignal; + + + +// ------------------------------------------------------------------------ // +// TweakScroller +// ------------------------------------------------------------------------ // + +TweakScroller::TweakScroller() : + m_Label(""), + m_Scroll(0,0,0,0,false), + m_Slider(0,0,10,10,false) +{ +} + + +void TweakScroller::Init(Panel *pParent, char *pText, int yPos) +{ + int parentWidth, parentHeight; + pParent->getSize(parentWidth, parentHeight); + + // Setup the volume scroll bar. + m_Label.setParent(pParent); + m_Label.setFont(Scheme::sf_primary1); + m_Label.setContentAlignment(vgui::Label::a_northwest); + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setPos(ITEM_BORDER, yPos); + m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); + m_Label.setText(pText); + m_Label.setVisible(true); + + m_Slider.setRangeWindow(10); + m_Slider.setRangeWindowEnabled(true); + + m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); + m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); + m_Scroll.setSlider(&m_Slider); + m_Scroll.setParent(pParent); + m_Scroll.setRange(0, 100); + m_Scroll.setFgColor(255,255,255,0); + m_Scroll.setBgColor(255,255,255,0); +} + + +float TweakScroller::GetValue() +{ + return m_Scroll.getValue() / 100.0f; +} + + +void TweakScroller::SetValue(float val) +{ + m_Scroll.setValue((int)(val * 100.0f)); +} + + +// ------------------------------------------------------------------------ // +// CVoiceVGUITweakDlg implementation. +// ------------------------------------------------------------------------ // + +CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() + : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), + m_Button_OK("",0,0), + m_Label("") +{ + m_pVoiceTweak = NULL; + m_Button_OK.addActionSignal(&g_OKButtonSignal); + m_Label.setBgColor(255,255,255,200); +} + + +CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() +{ +} + + +void CVoiceVGUITweakDlg::Open() +{ + if(g_bTweakDlgOpen) + return; + + g_bTweakDlgOpen = true; + + m_DlgWidth = ScreenWidth; + m_DlgHeight = ScreenHeight; + + m_pVoiceTweak = gEngfuncs.pVoiceTweak; + + // Tell the engine to start voice tweak mode (pipe voice output right to speakers). + m_pVoiceTweak->StartVoiceTweakMode(); + + // Set our size. + setPos((ScreenWidth - m_DlgWidth) / 2, (ScreenHeight - m_DlgHeight) / 2); + setSize(m_DlgWidth, m_DlgHeight); + + int curY = ITEM_BORDER; + m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); + m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); + curY = PanelBottom(&m_MicVolume.m_Label); + + m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); + m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); + curY = PanelBottom(&m_SpeakerVolume.m_Label); + + m_VoiceModEnable.setParent(this); + m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); + m_VoiceModEnable.SetText("Enable Voice In This Mod"); + m_VoiceModEnable.setPos(ITEM_BORDER, curY); + m_VoiceModEnable.SetCheckboxLeft(false); + m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); + m_VoiceModEnable.SetHandler(this); + + // Setup the OK button. + int buttonWidth, buttonHeight; + m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); + m_Button_OK.getSize(buttonWidth, buttonHeight); + m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); + m_Button_OK.setParent(this); + + // Put the label on the top. + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); + int labelWidth, labelHeight; + m_Label.getSize(labelWidth, labelHeight); + m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); + m_Label.setParent(this); + + BaseClass::Open(); +} + + +void CVoiceVGUITweakDlg::Close() +{ + m_pVoiceTweak->EndVoiceTweakMode(); + g_bTweakDlgOpen = false; + + BaseClass::Close(); +} + + +void CVoiceVGUITweakDlg::paintBackground() +{ + BaseClass::paintBackground(); + + // Draw our border. + int w,h; + getSize(w,h); + + drawSetColor(128,128,128,1); + drawOutlinedRect(0, 0, w, h); + + float volume = m_MicVolume.GetValue(); + m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); + + m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); +} + + +void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) +{ + if(pButton == &m_VoiceModEnable) + { + if(pButton->IsChecked()) + gEngfuncs.pfnClientCmd("voice_modenable 1"); + else + gEngfuncs.pfnClientCmd("voice_modenable 0"); + } +} + diff --git a/game_shared/voice_vgui_tweakdlg.h b/game_shared/voice_vgui_tweakdlg.h index 857ffd25..deb83dc2 100644 --- a/game_shared/voice_vgui_tweakdlg.h +++ b/game_shared/voice_vgui_tweakdlg.h @@ -1,25 +1,25 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VOICE_VGUI_TWEAKDLG_H -#define VOICE_VGUI_TWEAKDLG_H -#ifdef _WIN32 -#pragma once -#endif - - -class CMenuPanel; - - -// Returns true if the tweak dialog is currently up. -bool IsTweakDlgOpen(); - -// Returns a global instance of the tweak dialog. -CMenuPanel* GetVoiceTweakDlg(); - - -#endif // VOICE_VGUI_TWEAKDLG_H +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_VGUI_TWEAKDLG_H +#define VOICE_VGUI_TWEAKDLG_H +#ifdef _WIN32 +#pragma once +#endif + + +class CMenuPanel; + + +// Returns true if the tweak dialog is currently up. +bool IsTweakDlgOpen(); + +// Returns a global instance of the tweak dialog. +CMenuPanel* GetVoiceTweakDlg(); + + +#endif // VOICE_VGUI_TWEAKDLG_H diff --git a/pm_shared/pm_debug.c b/pm_shared/pm_debug.c index d9d097db..3baccaef 100644 --- a/pm_shared/pm_debug.c +++ b/pm_shared/pm_debug.c @@ -1,320 +1,320 @@ -/*** -* -* 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 - -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) - -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 +/*** +* +* 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 + +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) + +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/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index 19dd5ea5..5e48ee54 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -1,23 +1,23 @@ -/*** -* -* 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 - -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 ); - +/*** +* +* 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 + +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//PM_DEBUG_H \ No newline at end of file diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index 2a2ee680..7c04d22d 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -1,221 +1,221 @@ -/*** -* -* 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_DEFS_H -#define PM_DEFS_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_CUSTOM_IGNORE 0x00000010 // Ignore entities with SOLID_CUSTOM mode - -// Values for flags parameter of PM_TraceLine -#define PM_TRACELINE_PHYSENTSONLY 0 -#define PM_TRACELINE_ANYVISIBLE 1 - -#include "pm_info.h" - -// PM_PlayerTrace results. -#include "pmtrace.h" - - -#include "usercmd.h" - -// 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; // also contains pev->scale when "sv_allow_studio_scaling" is "1" - 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 - - // 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 ); - long (*RandomLong)( long lLow, long 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 )); - struct msurface_s *(*PM_TraceSurface)( int ground, float *vstart, float *vend ); -} playermove_t; +/*** +* +* 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_DEFS_H +#define PM_DEFS_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_CUSTOM_IGNORE 0x00000010 // Ignore entities with SOLID_CUSTOM mode + +// Values for flags parameter of PM_TraceLine +#define PM_TRACELINE_PHYSENTSONLY 0 +#define PM_TRACELINE_ANYVISIBLE 1 + +#include "pm_info.h" + +// PM_PlayerTrace results. +#include "pmtrace.h" + + +#include "usercmd.h" + +// 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; // also contains pev->scale when "sv_allow_studio_scaling" is "1" + 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 + + // 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 ); + long (*RandomLong)( long lLow, long 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 )); + struct msurface_s *(*PM_TraceSurface)( int ground, float *vstart, float *vend ); +} playermove_t; #endif//PM_DEFS_H \ No newline at end of file diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index e2f434f6..ea54e6db 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -1,20 +1,20 @@ -/*** -* -* 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_INFO_H -#define PM_INFO_H - -#define MAX_PHYSINFO_STRING 256 - +/*** +* +* 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_INFO_H +#define PM_INFO_H + +#define MAX_PHYSINFO_STRING 256 + #endif//PM_INFO_H \ No newline at end of file diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index 47d875e8..8e3b7792 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -1,32 +1,32 @@ -/*** -* -* 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_MATERIALS_H -#define PM_MATERIALS_H - -#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' - +/*** +* +* 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_MATERIALS_H +#define PM_MATERIALS_H + +#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' + #endif//PM_MATERIALS_H \ No newline at end of file diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c index a5d78dc1..8edaa3a4 100644 --- a/pm_shared/pm_math.c +++ b/pm_shared/pm_math.c @@ -1,422 +1,422 @@ -/*** -* -* 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 - -#pragma warning(disable : 4244) - -vec3_t vec3_origin = {0,0,0}; -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; - } -} - - -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; -} - -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; -} - - -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]; -} - - -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]; -} - -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]; -} - -double sqrt(double x); - -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; -} - -float Distance(const vec3_t v1, const vec3_t v2) -{ - vec3_t d; - VectorSubtract(v2,v1,d); - return Length(d); -} - -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; -} - - -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 ); -} - - -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; -} +/*** +* +* 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 + +#pragma warning(disable : 4244) + +vec3_t vec3_origin = {0,0,0}; +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; + } +} + + +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; +} + +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; +} + + +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]; +} + + +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]; +} + +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]; +} + +double sqrt(double x); + +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; +} + +float Distance(const vec3_t v1, const vec3_t v2) +{ + vec3_t d; + VectorSubtract(v2,v1,d); + return Length(d); +} + +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; +} + + +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 ); +} + + +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; +} diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h index 64d9baeb..6360b355 100644 --- a/pm_shared/pm_movevars.h +++ b/pm_shared/pm_movevars.h @@ -1,54 +1,54 @@ -//========= 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; // - int features; // engine features that shared across network - int fog_settings; // Global fog settings (packed color+density) - float wateralpha; // World water alpha 1.0 - solid 0.0 - transparent - float skydir_x; // skybox rotate direction - float skydir_y; // - float skydir_z; // - float skyangle; // skybox rotate angle -}; - -extern movevars_t movevars; - +//========= 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; // + int features; // engine features that shared across network + int fog_settings; // Global fog settings (packed color+density) + float wateralpha; // World water alpha 1.0 - solid 0.0 - transparent + float skydir_x; // skybox rotate direction + float skydir_y; // + float skydir_z; // + float skyangle; // skybox rotate angle +}; + +extern movevars_t movevars; + #endif \ No newline at end of file diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 2216e7e9..292720a1 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -1,3331 +1,3331 @@ -/*** -* -* 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; - float vJumpOrigin[3]; - float vJumpAngles[3]; -#endif - -static int pm_shared_initialized = 0; - -#pragma warning( disable : 4305 ) - -typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; - -playermove_t *pmove = NULL; - -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; - -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 hull_s -{ - dclipnode_t *clipnodes; - mplane_t *planes; - int firstclipnode; - int lastclipnode; - vec3_t clip_mins; - vec3_t clip_maxs; -} hull_t; - -// 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 - -// double to float warning -#pragma warning(disable : 4244) -#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 = 0; - 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 clip; - 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 - clip = 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. - clip = 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 ); - - 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" - - int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; - int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; - - 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 *= 0.333; - pmove->cmd.sidemove *= 0.333; - pmove->cmd.upmove *= 0.333; - } - - 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; - - 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; - - AngleVectors( pmove->angles, vpn, v_right, NULL ); - if ( pmove->cmd.buttons & IN_BACK ) - forward -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_FORWARD ) - forward += MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVELEFT ) - right -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVERIGHT ) - right += MAX_CLIMB_SPEED; - - 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; - } - } - - // 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 ); - } - - // 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; - -// pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground ); - - 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; -} +/*** +* +* 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; + float vJumpOrigin[3]; + float vJumpAngles[3]; +#endif + +static int pm_shared_initialized = 0; + +#pragma warning( disable : 4305 ) + +typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; + +playermove_t *pmove = NULL; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +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 hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +// 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 + +// double to float warning +#pragma warning(disable : 4244) +#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 = 0; + 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 clip; + 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 + clip = 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. + clip = 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 ); + + 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" + + int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; + int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; + + 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 *= 0.333; + pmove->cmd.sidemove *= 0.333; + pmove->cmd.upmove *= 0.333; + } + + 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; + + 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; + + AngleVectors( pmove->angles, vpn, v_right, NULL ); + if ( pmove->cmd.buttons & IN_BACK ) + forward -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_FORWARD ) + forward += MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVELEFT ) + right -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVERIGHT ) + right += MAX_CLIMB_SPEED; + + 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; + } + } + + // 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 ); + } + + // 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; + +// pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground ); + + 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/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index 96a8493a..9743044c 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -1,32 +1,32 @@ -/*** -* -* 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_SHARED_H -#define PM_SHARED_H - -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 - +/*** +* +* 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_SHARED_H +#define PM_SHARED_H + +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//PM_SHARED_H \ No newline at end of file From 79fd3f3056bd3ac104014ead757d261512fd9667 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 4 Jun 2016 18:34:15 +0500 Subject: [PATCH 030/227] Fix typo. --- .gitigonre => .gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .gitigonre => .gitignore (100%) diff --git a/.gitigonre b/.gitignore similarity index 100% rename from .gitigonre rename to .gitignore From feb2aefd88884aa4c084129f87fc36f23e997679 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 5 Jun 2016 08:17:09 +0000 Subject: [PATCH 031/227] Fix copying string to itself --- dlls/teamplay_gamerules.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index 9bc7830e..f8a337a1 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -286,7 +286,8 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea } // copy out the team name from the model - strncpy( pPlayer->m_szTeamName, pTeamName, TEAM_NAME_LENGTH ); + if( pPlayer->m_szTeamName != pTeamName ) + 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 ); From 146b1cfa84833b6bbc240d4585eccd55f5c341bc Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 9 Jun 2016 22:01:27 +0500 Subject: [PATCH 032/227] Fix undefined reference. --- cl_dll/input.cpp | 2 +- cl_dll/inputw32.cpp | 34 ++-------------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp index f89f0232..c6cd841c 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -23,7 +23,7 @@ extern "C" #include "const.h" #include "camera.h" #include "in_defs.h" -#include "view.h" +//#include "view.h" #include #include diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp index 1bacdf07..33144a8b 100644 --- a/cl_dll/inputw32.cpp +++ b/cl_dll/inputw32.cpp @@ -18,7 +18,7 @@ #include "camera.h" #include "in_defs.h" #include "../engine/keydefs.h" -#include "view.h" +//#include "view.h" #include "windows.h" #define MOUSE_BUTTON_COUNT 5 @@ -304,11 +304,6 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) gEngfuncs.GetViewAngles( (float *)viewangles ); - if ( in_mlook.state & 1) - { - V_StopPitchDrift (); - } - //jjb - this disbles normal mouse control if the user is trying to // move the camera, or if the mouse cursor is visible or if we're in intermission if ( !iMouseInUse && !g_iVisibleMouse && !gHUD.m_iIntermission ) @@ -791,18 +786,6 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) { viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; } - V_StopPitchDrift(); - } - else - { - // no pitch movement - // disable pitch return-to-center unless requested by user - // *** this code can be removed when the lookspring bug is fixed - // *** the bug always has the lookspring feature on - if(lookspring->value == 0.0) - { - V_StopPitchDrift(); - } } } else @@ -844,7 +827,6 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) { viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; } - } } break; @@ -863,18 +845,6 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) { viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; } - V_StopPitchDrift(); - } - else - { - // no pitch movement - // disable pitch return-to-center unless requested by user - // *** this code can be removed when the lookspring bug is fixed - // *** the bug always has the lookspring feature on - if( lookspring->value == 0.0 ) - { - V_StopPitchDrift(); - } } } break; @@ -944,4 +914,4 @@ void IN_Init (void) IN_StartupMouse (); IN_StartupJoystick (); -} \ No newline at end of file +} From fe4bedb0fbc6b654fe6531ac40df37e795cf434c Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 12 Jun 2016 09:14:28 +0000 Subject: [PATCH 033/227] Fix win32 support --- dlls/extdll.h | 4 ++-- dlls/h_export.cpp | 7 ++++++- dlls/nodes.cpp | 2 +- pm_shared/pm_shared.c | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dlls/extdll.h b/dlls/extdll.h index a368a2ff..659f9a0a 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -49,14 +49,14 @@ typedef int BOOL; #define MAX_PATH PATH_MAX #include #include +#endif //_WIN32 #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) #endif -#endif //_WIN32 + // Misc C-runtime library headers #include "stdio.h" diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index cae7e59f..1712a70a 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -46,9 +46,14 @@ BOOL WINAPI DllMain( } return TRUE; } + +// stdcall for win32 +#define EXPORT2 WINAPI +#else +#define EXPORT2 #endif -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +extern "C" void DLLEXPORT EXPORT2 GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 18c145dd..d512e54c 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -40,7 +40,7 @@ CGraph WorldGraph; LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); -#ifdef _LINUX +#if defined _LINUX && !defined _WIN32 #include #include #define CreateDirectory(p, n) mkdir(p, 0777) diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 292720a1..9fa5accf 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -21,7 +21,7 @@ #include "pm_shared.h" #include "pm_movevars.h" #include "pm_debug.h" -#include // NULL +//#include // NULL #include // sqrt #include // strcpy #include // atoi From 2c0f598c6d7990b2e1ae1af6178aa4b9e6d82cf6 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 12 Jun 2016 20:43:32 +0000 Subject: [PATCH 034/227] Disable CVoiceGameMgr --- dlls/Android.mk | 6 +++--- dlls/client.cpp | 6 +++++- dlls/multiplay_gamerules.cpp | 11 +++++++++++ dlls/teamplay_gamerules.cpp | 9 +++++++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index e0266879..495abd6a 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -14,7 +14,7 @@ LOCAL_MODULE_FILENAME = libserver_hardfp endif LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \ - -fno-exceptions -w + -fno-exceptions -DNO_VOICEGAMEMGR -w LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti @@ -126,8 +126,8 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ zombie.cpp \ ../pm_shared/pm_debug.c \ ../pm_shared/pm_math.c \ - ../pm_shared/pm_shared.c \ - ../game_shared/voice_gamemgr.cpp + ../pm_shared/pm_shared.c +# ../game_shared/voice_gamemgr.cpp LOCAL_LDLIBS := -llog diff --git a/dlls/client.cpp b/dlls/client.cpp index 02ba4582..14646a32 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -204,9 +204,11 @@ void ClientPutInServer( edict_t *pEntity ) } + +#ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; - +#endif //// HOST_SAY // String comes in as // say blah blah blah @@ -313,9 +315,11 @@ void Host_Say( edict_t *pEntity, int teamonly ) if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) continue; +#ifndef NO_VOICEGAMEMGR // can the receiver hear the sender? or has he muted him? if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) continue; +#endif if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) continue; diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index d79a4128..9b505549 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -43,7 +43,9 @@ extern int g_teamplay; float g_flIntermissionStartTime = 0; +#ifndef NO_VOICEGAMEMGR CVoiceGameMgr g_VoiceGameMgr; +#endif class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper { @@ -63,13 +65,16 @@ public: }; static CMultiplayGameMgrHelper g_GameMgrHelper; + //********************************************************* // Rules for the half-life multiplayer game. //********************************************************* CHalfLifeMultiplay :: CHalfLifeMultiplay() { +#ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); +#endif RefreshSkillData(); m_flIntermissionEndTime = 0; @@ -116,8 +121,10 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { +#ifndef NO_VOICEGAMEMGR if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) return TRUE; +#endif return CGameRules::ClientCommand(pPlayer, pcmd); } @@ -186,7 +193,9 @@ extern cvar_t mp_chattime; //========================================================= void CHalfLifeMultiplay :: Think ( void ) { +#ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.Update(gpGlobals->frametime); +#endif ///// Check game rules ///// static int last_frags; @@ -397,7 +406,9 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI //========================================================= BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) { +#ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.ClientConnected(pEntity); +#endif return TRUE; } diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index f8a337a1..c673d4c6 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -68,9 +68,10 @@ CHalfLifeTeamplay :: CHalfLifeTeamplay() extern cvar_t timeleft, fragsleft; +#ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; - +#endif void CHalfLifeTeamplay :: Think ( void ) { ///// Check game rules ///// @@ -80,8 +81,9 @@ void CHalfLifeTeamplay :: Think ( void ) int frags_remaining = 0; int time_remaining = 0; +#ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.Update(gpGlobals->frametime); - +#endif if ( g_fGameOver ) // someone else quit the game already { CHalfLifeMultiplay::Think(); @@ -145,8 +147,11 @@ void CHalfLifeTeamplay :: Think ( void ) //========================================================= BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { + +#ifndef NO_VOICEGAMEMGR if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) return TRUE; +#endif if ( FStrEq( pcmd, "menuselect" ) ) { From 18668728878ca50827d09c5c5bf92cd65b6eda1a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 13 Jun 2016 18:45:25 +0500 Subject: [PATCH 035/227] Fix access to uninitialized variables. --- cl_dll/entity.cpp | 2 +- dlls/func_break.cpp | 2 +- dlls/soundent.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index 0228e70d..8dbdd383 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -775,7 +775,7 @@ void DLLEXPORT HUD_TempEntUpdate ( if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) { - vec3_t traceNormal; + vec3_t traceNormal( 0.0f, 0.0f, 0.0f ); float traceFraction = 1; if ( pTemp->flags & FTENT_COLLIDEALL ) diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index ff63ef56..e6ba74f7 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -283,7 +283,7 @@ void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, void CBreakable::Precache( void ) { - const char *pGibName; + const char *pGibName = NULL; switch (m_Material) { diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index c567d7a5..ad5ef337 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -230,7 +230,7 @@ void CSoundEnt :: Initialize ( void ) int i; int iSound; - m_cLastActiveSounds; + m_cLastActiveSounds = 0; m_iFreeSound = 0; m_iActiveSound = SOUNDLIST_EMPTY; From a9796904ec385cf0c7b4d623803e75db55572748 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 13 Jun 2016 18:48:17 +0500 Subject: [PATCH 036/227] Remove unused check. --- dlls/sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 6c5bfc90..e745b995 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1176,7 +1176,7 @@ int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, name[0] = 0; ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick > 0 && name) + if( ipick > 0 ) EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); return ipick; } From 2facf77f01414a5e93e99ac0e974c538df8923e7 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 13 Jun 2016 18:50:38 +0500 Subject: [PATCH 037/227] Fix buffer limit. --- cl_dll/death.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 97d4900e..095d48bd 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -167,8 +167,7 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p char killedwith[32]; strcpy( killedwith, "d_" ); - strncat( killedwith, READ_STRING(), 32 ); - + strncat( killedwith, READ_STRING(), sizeof(killedwith) - strlen(killedwith) - 1 ); gHUD.m_Spectator.DeathMessage(victim); From 3a691b21a4ae745c33d4659dcd8329f807b25fd9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 13 Jun 2016 19:29:45 +0500 Subject: [PATCH 038/227] Partially fix -Wswitch. --- dlls/agrunt.cpp | 9 ++++++--- dlls/barney.cpp | 4 +++- dlls/bullsquid.cpp | 6 +++++- dlls/controller.cpp | 11 +++++------ dlls/func_break.cpp | 17 +++++++++++++++-- dlls/hassassin.cpp | 16 +++++++++------- dlls/hgrunt.cpp | 19 +++++++++++-------- dlls/houndeye.cpp | 9 ++++----- dlls/ichthyosaur.cpp | 7 +++++-- dlls/islave.cpp | 4 +++- dlls/monsterstate.cpp | 4 ++++ dlls/scientist.cpp | 6 ++++++ dlls/squadmonster.cpp | 2 ++ dlls/turret.cpp | 2 ++ dlls/util.cpp | 12 +++++++----- 15 files changed, 87 insertions(+), 41 deletions(-) diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index b1022694..2b834276 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -1081,7 +1081,7 @@ Schedule_t *CAGrunt :: GetSchedule ( void ) { case MONSTERSTATE_COMBAT: { -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. @@ -1093,7 +1093,7 @@ Schedule_t *CAGrunt :: GetSchedule ( void ) return GetScheduleOfType( SCHED_WAKE_ANGRY ); } - // zap player! + // zap player! if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) { AttackSound();// this is a total hack. Should be parto f the schedule @@ -1105,7 +1105,7 @@ Schedule_t *CAGrunt :: GetSchedule ( void ) return GetScheduleOfType( SCHED_SMALL_FLINCH ); } - // can attack + // can attack if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) { return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); @@ -1118,6 +1118,9 @@ Schedule_t *CAGrunt :: GetSchedule ( void ) return GetScheduleOfType ( SCHED_STANDOFF ); } + break; + default: + break; } return CSquadMonster :: GetSchedule(); diff --git a/dlls/barney.cpp b/dlls/barney.cpp index 095de85d..baaf6148 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -702,7 +702,7 @@ Schedule_t *CBarney :: GetSchedule ( void ) { case MONSTERSTATE_COMBAT: { -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. @@ -756,6 +756,8 @@ Schedule_t *CBarney :: GetSchedule ( void ) // try to say something about smells TrySmellTalk(); break; + default: + break; } return CTalkMonster::GetSchedule(); diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 4a14f247..73f432f1 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -1060,7 +1060,7 @@ Schedule_t *CBullsquid :: GetSchedule( void ) } case MONSTERSTATE_COMBAT: { -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. @@ -1116,6 +1116,8 @@ Schedule_t *CBullsquid :: GetSchedule( void ) break; } + default: + break; } return CBaseMonster :: GetSchedule(); @@ -1266,6 +1268,8 @@ MONSTERSTATE CBullsquid :: GetIdealState ( void ) } break; } + default: + break; } m_IdealMonsterState = CBaseMonster :: GetIdealState(); diff --git a/dlls/controller.cpp b/dlls/controller.cpp index 629714d6..39f9742b 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -731,12 +731,6 @@ Schedule_t *CController :: GetSchedule ( void ) { switch ( m_MonsterState ) { - case MONSTERSTATE_IDLE: - break; - - case MONSTERSTATE_ALERT: - break; - case MONSTERSTATE_COMBAT: { Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); @@ -752,6 +746,11 @@ Schedule_t *CController :: GetSchedule ( void ) } } break; + case MONSTERSTATE_IDLE: + case MONSTERSTATE_ALERT: + break; + default: + break; } return CSquadMonster :: GetSchedule(); diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index e6ba74f7..0a107b43 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -338,6 +338,11 @@ void CBreakable::Precache( void ) PRECACHE_SOUND ("debris/bustceiling.wav"); break; + case matNone: + case matLastMaterial: + break; + default: + break; } MaterialSoundPrecache( m_Material ); if ( m_iszGibModel ) @@ -510,11 +515,13 @@ void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; } } - break; + break; case matUnbreakableGlass: UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - break; + break; + default: + break; } } @@ -664,6 +671,12 @@ void CBreakable::Die( void ) case matCeilingTile: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); break; + case matNone: + case matLastMaterial: + case matUnbreakableGlass: + break; + default: + break; } diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index e5d84182..56ceec3c 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -858,7 +858,7 @@ Schedule_t *CHAssassin :: GetSchedule ( void ) case MONSTERSTATE_COMBAT: { -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. @@ -907,21 +907,21 @@ Schedule_t *CHAssassin :: GetSchedule ( void ) m_iFrustration++; } - // jump player! + // jump player! if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) { // ALERT( at_console, "melee attack 1\n"); return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); } - // throw grenade + // throw grenade if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) ) { // ALERT( at_console, "range attack 2\n"); return GetScheduleOfType ( SCHED_RANGE_ATTACK2 ); } - // spotted + // spotted if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) { // ALERT( at_console, "exposed\n"); @@ -929,7 +929,7 @@ Schedule_t *CHAssassin :: GetSchedule ( void ) return GetScheduleOfType ( SCHED_ASSASSIN_EXPOSED ); } - // can attack + // can attack if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) { // ALERT( at_console, "range attack 1\n"); @@ -943,7 +943,7 @@ Schedule_t *CHAssassin :: GetSchedule ( void ) return GetScheduleOfType ( SCHED_COMBAT_FACE ); } - // new enemy + // new enemy if ( HasConditions ( bits_COND_NEW_ENEMY ) ) { // ALERT( at_console, "take cover\n"); @@ -954,6 +954,8 @@ Schedule_t *CHAssassin :: GetSchedule ( void ) return GetScheduleOfType ( SCHED_ALERT_STAND ); } break; + default: + break; } return CBaseMonster :: GetSchedule(); @@ -1012,4 +1014,4 @@ Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) return CBaseMonster :: GetScheduleOfType( Type ); } -#endif \ No newline at end of file +#endif diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index e0330696..b31248db 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -2035,14 +2035,14 @@ Schedule_t *CHGrunt :: GetSchedule( void ) { case MONSTERSTATE_COMBAT: { -// dead enemy + // 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 + // new enemy if ( HasConditions(bits_COND_NEW_ENEMY) ) { if ( InSquad() ) @@ -2089,7 +2089,7 @@ Schedule_t *CHGrunt :: GetSchedule( void ) } } } -// no ammo + // no ammo else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) { //!!!KELLY - this individual just realized he's out of bullet ammo. @@ -2098,7 +2098,7 @@ Schedule_t *CHGrunt :: GetSchedule( void ) return GetScheduleOfType ( SCHED_GRUNT_COVER_AND_RELOAD ); } -// damaged just a little + // damaged just a little else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) { // if hurt: @@ -2124,19 +2124,19 @@ Schedule_t *CHGrunt :: GetSchedule( void ) return GetScheduleOfType( SCHED_SMALL_FLINCH ); } } -// can kick + // can kick else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) { return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); } -// can grenade launch + // 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 + // can shoot else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) { if ( InSquad() ) @@ -2167,7 +2167,7 @@ Schedule_t *CHGrunt :: GetSchedule( void ) return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); } } -// can't see enemy + // can't see enemy else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) { if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) @@ -2212,6 +2212,9 @@ Schedule_t *CHGrunt :: GetSchedule( void ) return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); } } + break; + default: + break; } // no special cases here, call the base class diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index aa99cc68..182d3df1 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -219,14 +219,11 @@ void CHoundeye :: SetYawSpeed ( void ) 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; } @@ -1298,6 +1295,8 @@ Schedule_t *CHoundeye :: GetSchedule( void ) } break; } + default: + break; } return CSquadMonster :: GetSchedule(); diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index 281dfd00..b10227da 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -534,11 +534,11 @@ Schedule_t* CIchthyosaur::GetSchedule() case MONSTERSTATE_IDLE: m_flightSpeed = 80; return GetScheduleOfType( SCHED_IDLE_WALK ); - + break; case MONSTERSTATE_ALERT: m_flightSpeed = 150; return GetScheduleOfType( SCHED_IDLE_WALK ); - + break; case MONSTERSTATE_COMBAT: m_flMaxSpeed = 400; // eat them @@ -561,6 +561,9 @@ Schedule_t* CIchthyosaur::GetSchedule() } return GetScheduleOfType( SCHED_STANDOFF ); + break; + default: + break; } return CFlyingMonster :: GetSchedule(); diff --git a/dlls/islave.cpp b/dlls/islave.cpp index 9c3964e3..d4ad75b4 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -668,7 +668,7 @@ Schedule_t *CISlave :: GetSchedule( void ) switch (m_MonsterState) { case MONSTERSTATE_COMBAT: -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. @@ -692,6 +692,8 @@ Schedule_t *CISlave :: GetSchedule( void ) } } break; + default: + break; } return CSquadMonster::GetSchedule( ); } diff --git a/dlls/monsterstate.cpp b/dlls/monsterstate.cpp index 14518e1c..3c1620aa 100644 --- a/dlls/monsterstate.cpp +++ b/dlls/monsterstate.cpp @@ -50,6 +50,8 @@ void CBaseMonster :: SetState ( MONSTERSTATE State ) ALERT ( at_aiconsole, "Stripped\n" ); } break; + default: + break; } m_MonsterState = State; @@ -227,6 +229,8 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) case MONSTERSTATE_DEAD: m_IdealMonsterState = MONSTERSTATE_DEAD; break; + default: + break; } return m_IdealMonsterState; diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index b021b1d7..0b7c6eac 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -617,6 +617,8 @@ void CScientist :: SetYawSpeed ( void ) case ACT_TURN_RIGHT: ys = 120; break; + default: + break; } pev->yaw_speed = ys; @@ -996,6 +998,8 @@ Schedule_t *CScientist :: GetSchedule ( void ) return slScientistCover; // Run & Cower break; + default: + break; } return CTalkMonster::GetSchedule(); @@ -1058,6 +1062,8 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) } } break; + default: + break; } return CTalkMonster::GetIdealState(); diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp index 993e877c..c2d85351 100644 --- a/dlls/squadmonster.cpp +++ b/dlls/squadmonster.cpp @@ -533,6 +533,8 @@ MONSTERSTATE CSquadMonster :: GetIdealState ( void ) SquadMakeEnemy ( m_hEnemy ); } break; + default: + break; } return CBaseMonster :: GetIdealState(); diff --git a/dlls/turret.cpp b/dlls/turret.cpp index 10a0c839..f940cbb1 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -813,6 +813,8 @@ void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) case TURRET_ANIM_DIE: pev->framerate = 1.0; break; + default: + break; } //ALERT(at_console, "Turret anim #%d\n", anim); } diff --git a/dlls/util.cpp b/dlls/util.cpp index 5f25f79f..8391d944 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2098,19 +2098,21 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p { case FIELD_EVARS: entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); - break; + break; case FIELD_CLASSPTR: entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); - break; + break; case FIELD_EDICT: entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); - break; + break; case FIELD_ENTITY: entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); - break; + break; case FIELD_EHANDLE: entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); - break; + break; + default: + break; } } WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); From 1aac42f5041ae166a21a8d13bb327963b782cd85 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 21:33:39 +0500 Subject: [PATCH 039/227] Remove extra commas and semicolons. Format. --- cl_dll/ammo.cpp | 42 ++-- cl_dll/ammo_secondary.cpp | 4 +- cl_dll/ammohistory.h | 2 +- cl_dll/battery.cpp | 6 +- cl_dll/death.cpp | 2 +- cl_dll/ev_hldm.cpp | 8 +- cl_dll/ev_hldm.h | 6 +- cl_dll/flashlight.cpp | 6 +- cl_dll/geiger.cpp | 4 +- cl_dll/hud.h | 12 +- cl_dll/input.cpp | 6 +- cl_dll/menu.cpp | 4 +- cl_dll/message.cpp | 4 +- common/const.h | 6 +- common/triangleapi.h | 4 +- dlls/activity.h | 2 +- dlls/aflock.cpp | 14 +- dlls/agrunt.cpp | 17 +- dlls/airtank.cpp | 8 +- dlls/animating.cpp | 8 +- dlls/animation.cpp | 17 +- dlls/apache.cpp | 39 +--- dlls/barnacle.cpp | 22 +- dlls/barney.cpp | 39 +--- dlls/basemonster.h | 15 +- dlls/bigmomma.cpp | 76 ++---- dlls/bloater.cpp | 17 +- dlls/bmodels.cpp | 70 ++---- dlls/bullsquid.cpp | 25 +- dlls/buttons.cpp | 64 ++--- dlls/cbase.cpp | 51 ++-- dlls/controller.cpp | 82 +------ dlls/crossbow.cpp | 4 +- dlls/crowbar.cpp | 4 +- dlls/decals.h | 5 +- dlls/doors.cpp | 84 +++---- dlls/effects.cpp | 146 +++--------- dlls/egon.cpp | 18 +- dlls/explode.cpp | 8 +- dlls/flyingmonster.cpp | 17 +- dlls/flyingmonster.h | 8 +- dlls/func_break.cpp | 92 +++----- dlls/func_tank.cpp | 62 ++--- dlls/gamerules.h | 109 ++++----- dlls/gargantua.cpp | 69 ++---- dlls/gauss.cpp | 23 +- dlls/genericmonster.cpp | 3 +- dlls/ggrenade.cpp | 16 +- dlls/glock.cpp | 36 +-- dlls/gman.cpp | 9 +- dlls/h_battery.cpp | 7 +- dlls/h_cine.cpp | 31 ++- dlls/h_cycler.cpp | 47 +--- dlls/handgrenade.cpp | 14 +- dlls/hassassin.cpp | 39 +--- dlls/headcrab.cpp | 26 +-- dlls/healthkit.cpp | 23 +- dlls/hgrunt.cpp | 87 +++---- dlls/hornet.cpp | 30 +-- dlls/hornetgun.cpp | 24 +- dlls/houndeye.cpp | 35 ++- dlls/ichthyosaur.cpp | 63 ++--- dlls/islave.cpp | 69 ++---- dlls/items.cpp | 24 +- dlls/items.h | 1 - dlls/leech.cpp | 48 +--- dlls/lights.cpp | 17 +- dlls/maprules.cpp | 79 ++----- dlls/maprules.h | 5 +- dlls/monsterevent.h | 3 +- dlls/monstermaker.cpp | 31 ++- dlls/monsters.cpp | 211 ++++++----------- dlls/monsters.h | 10 +- dlls/monsterstate.cpp | 7 +- dlls/mortar.cpp | 19 +- dlls/mp5.cpp | 50 +--- dlls/mpstubb.cpp | 10 +- dlls/multiplay_gamerules.cpp | 49 ++-- dlls/nihilanth.cpp | 96 ++------ dlls/nodes.cpp | 379 +++++++++++++++--------------- dlls/nodes.h | 6 +- dlls/osprey.cpp | 31 +-- dlls/pathcorner.cpp | 28 +-- dlls/physcallback.h | 2 +- dlls/plane.cpp | 3 +- dlls/plats.cpp | 223 ++++++------------ dlls/player.cpp | 428 ++++++++++++---------------------- dlls/player.h | 43 ++-- dlls/playermonster.cpp | 7 +- dlls/prop.cpp | 34 +-- dlls/python.cpp | 19 +- dlls/rat.cpp | 5 +- dlls/rpg.cpp | 26 +-- dlls/satchel.cpp | 23 +- dlls/saverestore.h | 4 +- dlls/schedule.cpp | 66 +++--- dlls/schedule.h | 11 +- dlls/scientist.cpp | 101 +++----- dlls/scripted.cpp | 120 +++------- dlls/scripted.h | 8 +- dlls/scriptevent.h | 2 +- dlls/shotgun.cpp | 19 +- dlls/singleplay_gamerules.cpp | 3 +- dlls/skill.cpp | 5 +- dlls/skill.h | 16 +- dlls/sound.cpp | 212 +++++++---------- dlls/soundent.cpp | 11 +- dlls/soundent.h | 6 +- dlls/spectator.cpp | 9 +- dlls/squad.h | 5 +- dlls/squadmonster.cpp | 29 +-- dlls/squadmonster.h | 2 - dlls/squeakgrenade.cpp | 36 +-- dlls/stats.cpp | 6 +- dlls/subs.cpp | 71 +++--- dlls/talkmonster.cpp | 90 ++----- dlls/talkmonster.h | 15 +- dlls/teamplay_gamerules.cpp | 23 +- dlls/tempmonster.cpp | 5 +- dlls/tentacle.cpp | 73 +----- dlls/trains.h | 5 +- dlls/triggers.cpp | 313 ++++++++++--------------- dlls/tripmine.cpp | 40 +--- dlls/turret.cpp | 88 +++---- dlls/util.cpp | 261 ++++++--------------- dlls/util.h | 67 ++++-- dlls/vector.h | 9 +- dlls/weapons.cpp | 127 ++++------ dlls/weapons.h | 62 ++--- dlls/world.cpp | 116 ++++----- dlls/xen.cpp | 83 ++----- dlls/zombie.cpp | 34 +-- engine/custom.h | 4 +- engine/customentity.h | 4 +- engine/eiface.h | 6 +- 135 files changed, 1955 insertions(+), 4019 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index d748176e..d55a9f5e 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -230,27 +230,27 @@ int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and HSPRITE ghsprBuckets; // Sprite for top row of weapons menu -DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip -DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type -DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count -DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record -DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record -DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily -DECLARE_MESSAGE(m_Ammo, ItemPickup); +DECLARE_MESSAGE(m_Ammo, CurWeapon ) // Current weapon and clip +DECLARE_MESSAGE(m_Ammo, WeaponList) // new weapon type +DECLARE_MESSAGE(m_Ammo, AmmoX) // update known ammo type's count +DECLARE_MESSAGE(m_Ammo, AmmoPickup) // flashes an ammo pickup record +DECLARE_MESSAGE(m_Ammo, WeapPickup) // flashes a weapon pickup record +DECLARE_MESSAGE(m_Ammo, HideWeapon) // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE(m_Ammo, ItemPickup) -DECLARE_COMMAND(m_Ammo, Slot1); -DECLARE_COMMAND(m_Ammo, Slot2); -DECLARE_COMMAND(m_Ammo, Slot3); -DECLARE_COMMAND(m_Ammo, Slot4); -DECLARE_COMMAND(m_Ammo, Slot5); -DECLARE_COMMAND(m_Ammo, Slot6); -DECLARE_COMMAND(m_Ammo, Slot7); -DECLARE_COMMAND(m_Ammo, Slot8); -DECLARE_COMMAND(m_Ammo, Slot9); -DECLARE_COMMAND(m_Ammo, Slot10); -DECLARE_COMMAND(m_Ammo, Close); -DECLARE_COMMAND(m_Ammo, NextWeapon); -DECLARE_COMMAND(m_Ammo, PrevWeapon); +DECLARE_COMMAND(m_Ammo, Slot1) +DECLARE_COMMAND(m_Ammo, Slot2) +DECLARE_COMMAND(m_Ammo, Slot3) +DECLARE_COMMAND(m_Ammo, Slot4) +DECLARE_COMMAND(m_Ammo, Slot5) +DECLARE_COMMAND(m_Ammo, Slot6) +DECLARE_COMMAND(m_Ammo, Slot7) +DECLARE_COMMAND(m_Ammo, Slot8) +DECLARE_COMMAND(m_Ammo, Slot9) +DECLARE_COMMAND(m_Ammo, Slot10) +DECLARE_COMMAND(m_Ammo, Close) +DECLARE_COMMAND(m_Ammo, NextWeapon) +DECLARE_COMMAND(m_Ammo, PrevWeapon) // width of ammo fonts #define AMMO_SMALL_WIDTH 10 @@ -295,7 +295,7 @@ int CHudAmmo::Init(void) gHR.Init(); return 1; -}; +} void CHudAmmo::Reset(void) { diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index e2a2f591..8038c216 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -24,8 +24,8 @@ #include #include "parsemsg.h" -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ) +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ) int CHudAmmoSecondary :: Init( void ) { diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 48eeafca..3d7d5947 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -100,7 +100,7 @@ enum { HISTSLOT_EMPTY, HISTSLOT_AMMO, HISTSLOT_WEAP, - HISTSLOT_ITEM, + HISTSLOT_ITEM }; class HistoryResource diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp index dc9a3fbe..4d08892d 100644 --- a/cl_dll/battery.cpp +++ b/cl_dll/battery.cpp @@ -38,7 +38,7 @@ int CHudBattery::Init(void) gHUD.AddHudElem(this); return 1; -}; +} int CHudBattery::VidInit(void) @@ -52,7 +52,7 @@ int CHudBattery::VidInit(void) m_iHeight = m_prc2->bottom - m_prc1->top; m_fFade = 0; return 1; -}; +} int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) { @@ -135,4 +135,4 @@ int CHudBattery::Draw(float flTime) x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); return 1; -} \ No newline at end of file +} diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 095d48bd..70c0393f 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -22,7 +22,7 @@ #include #include -DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); +DECLARE_MESSAGE( m_DeathNotice, DeathMsg ) struct DeathNoticeItem { char szKiller[MAX_PLAYER_NAME_LENGTH*2]; diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 5a4162fb..bd20da95 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1181,7 +1181,7 @@ enum crossbow_e { CROSSBOW_DRAW1, // full CROSSBOW_DRAW2, // empty CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty + CROSSBOW_HOLSTER2 // empty }; //===================== @@ -1322,7 +1322,7 @@ enum rpg_e { RPG_HOLSTER2, // unloaded RPG_DRAW_UL, // unloaded RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget + RPG_FIDGET_UL // unloaded fidget }; void EV_FireRpg( event_args_t *args ) @@ -1552,7 +1552,7 @@ enum tripmine_e { TRIPMINE_HOLSTER, TRIPMINE_DRAW, TRIPMINE_WORLD, - TRIPMINE_GROUND, + TRIPMINE_GROUND }; //We only check if it's possible to put a trip mine @@ -1697,4 +1697,4 @@ void EV_TrainPitchAdjust( event_args_t *args ) int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) { return 0; -} \ No newline at end of file +} diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h index 5fd90c1a..57c99216 100644 --- a/cl_dll/ev_hldm.h +++ b/cl_dll/ev_hldm.h @@ -20,7 +20,7 @@ typedef enum BULLET_MONSTER_9MM, BULLET_MONSTER_MP5, - BULLET_MONSTER_12MM, + BULLET_MONSTER_12MM } Bullet; enum glock_e { @@ -58,7 +58,7 @@ enum mp5_e MP5_DEPLOY, MP5_FIRE1, MP5_FIRE2, - MP5_FIRE3, + MP5_FIRE3 }; enum python_e { @@ -92,4 +92,4 @@ void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); -#endif // EV_HLDMH \ No newline at end of file +#endif // EV_HLDMH diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index 23b0691e..ac011a5c 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -45,7 +45,7 @@ int CHudFlashlight::Init(void) gHUD.AddHudElem(this); return 1; -}; +} void CHudFlashlight::Reset(void) { @@ -68,7 +68,7 @@ int CHudFlashlight::VidInit(void) m_iWidth = m_prc2->right - m_prc2->left; return 1; -}; +} int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) { @@ -155,4 +155,4 @@ int CHudFlashlight::Draw(float flTime) return 1; -} \ No newline at end of file +} diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 71f97923..4e5e5991 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -40,12 +40,12 @@ int CHudGeiger::Init(void) srand( (unsigned)time( NULL ) ); return 1; -}; +} int CHudGeiger::VidInit(void) { return 1; -}; +} int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) { diff --git a/cl_dll/hud.h b/cl_dll/hud.h index aa535d80..73423c0d 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -44,7 +44,7 @@ enum { MAX_PLAYERS = 64, MAX_TEAMS = 64, - MAX_TEAM_NAME = 16, + MAX_TEAM_NAME = 16 }; typedef struct { @@ -277,7 +277,7 @@ protected: enum { MAX_STATUSTEXT_LENGTH = 128, MAX_STATUSBAR_VALUES = 8, - MAX_STATUSBAR_LINES = 2, + MAX_STATUSBAR_LINES = 2 }; char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn @@ -547,9 +547,8 @@ public: enum { MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, - MAX_ICONSPRITES = 4, + MAX_ICONSPRITES = 4 }; - //had to make these public so CHud could access them (to enable concussion icon) //could use a friend declaration instead... @@ -574,8 +573,6 @@ private: //----------------------------------------------------- // - - class CHud { private: @@ -631,7 +628,6 @@ public: { return m_rgrcRects[index]; } - int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array @@ -653,7 +649,6 @@ public: CHudScoreboard m_Scoreboard; CHudMOTD m_MOTD; - void Init( void ); void VidInit( void ); void Think(void); @@ -691,7 +686,6 @@ public: }; - extern CHud gHUD; extern int g_iPlayerClass; diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp index c6cd841c..8c2a6a3b 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -27,8 +27,6 @@ extern "C" #include #include - - extern "C" { struct kbutton_s DLLEXPORT *KB_Find( const char *name ); @@ -381,8 +379,8 @@ int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding return 1; } -void IN_BreakDown( void ) { KeyDown( &in_break );}; -void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_BreakDown( void ) { KeyDown( &in_break ); } +void IN_BreakUp( void ) { KeyUp( &in_break ); } void IN_KLookDown (void) {KeyDown(&in_klook);} void IN_KLookUp (void) {KeyUp(&in_klook);} void IN_JLookDown (void) {KeyDown(&in_jlook);} diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index e46cf06d..2ed362fb 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -20,18 +20,16 @@ #include "hud.h" #include "cl_util.h" #include "parsemsg.h" - #include #include - #define MAX_MENU_STRING 512 char g_szMenuString[MAX_MENU_STRING]; char g_szPrelocalisedMenuString[MAX_MENU_STRING]; int KB_ConvertString( char *in, char **ppout ); -DECLARE_MESSAGE( m_Menu, ShowMenu ); +DECLARE_MESSAGE( m_Menu, ShowMenu ) int CHudMenu :: Init( void ) { diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index c9b71aa5..bb93bb5a 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -42,7 +42,7 @@ int CHudMessage::Init(void) Reset(); return 1; -}; +} int CHudMessage::VidInit( void ) { @@ -50,7 +50,7 @@ int CHudMessage::VidInit( void ) m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); return 1; -}; +} void CHudMessage::Reset( void ) diff --git a/common/const.h b/common/const.h index 28a31a3f..b885e44e 100644 --- a/common/const.h +++ b/common/const.h @@ -699,7 +699,7 @@ enum kRenderGlow, // src*a+dest -- No Z buffer checks kRenderTransAlpha, // src*srca+dest*(1-srca) kRenderTransAdd, // src*a+dest - kRenderWorldGlow, // Same as kRenderGlow but not fixed size in screen space + kRenderWorldGlow // Same as kRenderGlow but not fixed size in screen space }; enum @@ -724,7 +724,7 @@ enum kRenderFxDeadPlayer, // kRenderAmt is the player index kRenderFxExplode, // Scale up really big! kRenderFxGlowShell, // Glowing Shell - kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) + kRenderFxClampMinScale // Keep this sprite from getting very small (SPRITES only!) }; typedef unsigned int func_t; @@ -777,4 +777,4 @@ typedef struct int hitgroup; // 0 == generic, non zero is specific body part } trace_t; -#endif//CONST_H \ No newline at end of file +#endif//CONST_H diff --git a/common/triangleapi.h b/common/triangleapi.h index f83c7ff0..f2e9a309 100644 --- a/common/triangleapi.h +++ b/common/triangleapi.h @@ -19,7 +19,7 @@ typedef enum { TRI_FRONT = 0, - TRI_NONE = 1, + TRI_NONE = 1 } TRICULLSTYLE; #define TRI_API_VERSION 1 @@ -59,4 +59,4 @@ typedef struct triangleapi_s void (*FogParams)( float flDensity, int iFogSkybox ); } triangleapi_t; -#endif//TRIANGLEAPI_H \ No newline at end of file +#endif//TRIANGLEAPI_H diff --git a/dlls/activity.h b/dlls/activity.h index 6fd3a188..b467e5c7 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -94,7 +94,7 @@ typedef enum { ACT_FLINCH_LEFTARM, ACT_FLINCH_RIGHTARM, ACT_FLINCH_LEFTLEG, - ACT_FLINCH_RIGHTLEG, + ACT_FLINCH_RIGHTLEG } Activity; diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index 24532eeb..9bf03d5e 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -55,7 +55,7 @@ TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ) //========================================================= //========================================================= @@ -106,8 +106,9 @@ public: float m_flAlertTime; float m_flFlockNextSoundTime; }; -LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ); -LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ); + +LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ) +LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ) TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = { @@ -125,7 +126,7 @@ TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = // DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save }; -IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ) //========================================================= //========================================================= @@ -163,7 +164,6 @@ void CFlockingFlyerFlock :: Precache( ) PrecacheFlockSounds(); } - void CFlockingFlyerFlock :: PrecacheFlockSounds( void ) { PRECACHE_SOUND("boid/boid_alert1.wav" ); @@ -549,7 +549,6 @@ BOOL CFlockingFlyer :: FPathBlocked( ) return fBlocked; } - //========================================================= // Leader boids use this think every tenth //========================================================= @@ -785,7 +784,6 @@ void CFlockingFlyer :: FlockFollowerThink( void ) // if we make it this far, boids path is CLEAR! m_fCourseAdjust = FALSE; */ - //========================================================= // @@ -813,6 +811,7 @@ void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) m_pSquadNext = pAdd; pAdd->m_pSquadLeader = this; } + //========================================================= // // SquadRemove(), remove pRemove from my squad. @@ -872,6 +871,7 @@ void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) else SquadDisband(); } + //========================================================= // // SquadCount(), return the number of members of this squad diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index 2b834276..2612dc47 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -32,7 +32,7 @@ enum { SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_AGRUNT_THREAT_DISPLAY, + SCHED_AGRUNT_THREAT_DISPLAY }; //========================================================= @@ -41,7 +41,7 @@ enum enum { TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, - TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, + TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE }; int iAgruntMuzzleFlash; @@ -98,7 +98,7 @@ public: int IRelationship( CBaseEntity *pTarget ); void StopTalking ( void ); BOOL ShouldSpeak( void ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); @@ -122,7 +122,8 @@ public: float m_flNextWordTime; int m_iLastWord; }; -LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ); + +LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ) TYPEDESCRIPTION CAGrunt::m_SaveData[] = { @@ -134,7 +135,7 @@ TYPEDESCRIPTION CAGrunt::m_SaveData[] = DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ); +IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ) const char *CAGrunt::pAttackHitSounds[] = { @@ -627,7 +628,6 @@ void CAGrunt :: Precache() for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) PRECACHE_SOUND((char *)pAlertSounds[i]); - PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); @@ -757,7 +757,6 @@ Schedule_t slAGruntRangeAttack1[] = }, }; - Task_t tlAGruntHiddenRangeAttack1[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, @@ -884,7 +883,7 @@ DEFINE_CUSTOM_SCHEDULES( CAGrunt ) slAGruntThreatDisplay, }; -IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ) //========================================================= // FCanCheckAttacks - this is overridden for alien grunts @@ -1130,7 +1129,7 @@ Schedule_t *CAGrunt :: GetSchedule ( void ) //========================================================= Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) { - switch ( Type ) + switch( Type ) { case SCHED_TAKE_COVER_FROM_ENEMY: return &slAGruntTakeCoverFromEnemy[ 0 ]; diff --git a/dlls/airtank.cpp b/dlls/airtank.cpp index 9a914021..ddfe51e9 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -37,15 +37,14 @@ class CAirtank : public CGrenade int m_state; }; +LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ) -LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ); TYPEDESCRIPTION CAirtank::m_SaveData[] = { DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ); - +IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ) void CAirtank :: Spawn( void ) { @@ -74,7 +73,6 @@ void CAirtank::Precache( void ) PRECACHE_SOUND("doors/aliendoor3.wav"); } - void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) { pev->owner = ENT( pevAttacker ); @@ -84,7 +82,6 @@ void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) Explode( pev->origin, Vector( 0, 0, -1 ) ); } - void CAirtank::TankThink( void ) { // Fire trigger @@ -92,7 +89,6 @@ void CAirtank::TankThink( void ) SUB_UseTargets( this, USE_TOGGLE, 0 ); } - void CAirtank::TankTouch( CBaseEntity *pOther ) { if ( !pOther->IsPlayer() ) diff --git a/dlls/animating.cpp b/dlls/animating.cpp index 808cdd29..fdfd93f8 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -35,8 +35,7 @@ TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ), }; -IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ); - +IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ) //========================================================= // StudioFrameAdvance - advance the animation frame up to the current time @@ -104,7 +103,6 @@ int CBaseAnimating :: LookupSequence ( const char *label ) return ::LookupSequence( pmodel, label ); } - //========================================================= //========================================================= void CBaseAnimating :: ResetSequenceInfo ( ) @@ -119,8 +117,6 @@ void CBaseAnimating :: ResetSequenceInfo ( ) m_flLastEventCheck = gpGlobals->time; } - - //========================================================= //========================================================= BOOL CBaseAnimating :: GetSequenceFlags( ) @@ -165,7 +161,6 @@ void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) } } - //========================================================= //========================================================= float CBaseAnimating :: SetBoneController ( int iController, float flValue ) @@ -246,7 +241,6 @@ 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 ); diff --git a/dlls/animation.cpp b/dlls/animation.cpp index fa44348a..c59edc90 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -53,8 +53,6 @@ extern globalvars_t *gpGlobals; #pragma warning( disable : 4244 ) - - int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) { studiohdr_t *pstudiohdr; @@ -78,7 +76,6 @@ int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) return 1; } - int LookupActivity( void *pmodel, entvars_t *pev, int activity ) { studiohdr_t *pstudiohdr; @@ -106,7 +103,6 @@ int LookupActivity( void *pmodel, entvars_t *pev, int activity ) return seq; } - int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) { studiohdr_t *pstudiohdr; @@ -172,7 +168,6 @@ int LookupSequence( void *pmodel, const char *label ) return -1; } - int IsSoundEvent( int eventNumber ) { if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) @@ -180,7 +175,6 @@ int IsSoundEvent( int eventNumber ) return 0; } - void SequencePrecache( void *pmodel, const char *pSequenceName ) { int index = LookupSequence( pmodel, pSequenceName ); @@ -219,8 +213,6 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) } } - - void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) { studiohdr_t *pstudiohdr; @@ -253,7 +245,6 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * } } - int GetSequenceFlags( void *pmodel, entvars_t *pev ) { studiohdr_t *pstudiohdr; @@ -268,7 +259,6 @@ int GetSequenceFlags( void *pmodel, entvars_t *pev ) return pseqdesc->flags; } - int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) { studiohdr_t *pstudiohdr; @@ -370,7 +360,6 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu 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; @@ -412,9 +401,6 @@ float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) 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; @@ -503,7 +489,6 @@ void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); } - int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) { studiohdr_t *pstudiohdr; @@ -523,4 +508,4 @@ int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; return iCurrent; -} \ No newline at end of file +} diff --git a/dlls/apache.cpp b/dlls/apache.cpp index ee3a86a2..53998388 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -88,7 +88,8 @@ class CApache : public CBaseMonster int m_iDoSmokePuff; CBeam *m_pBeam; }; -LINK_ENTITY_TO_CLASS( monster_apache, CApache ); + +LINK_ENTITY_TO_CLASS( monster_apache, CApache ) TYPEDESCRIPTION CApache::m_SaveData[] = { @@ -111,8 +112,8 @@ TYPEDESCRIPTION CApache::m_SaveData[] = DEFINE_FIELD( CApache, m_flGoalSpeed, FIELD_FLOAT ), DEFINE_FIELD( CApache, m_iDoSmokePuff, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ) void CApache :: Spawn( void ) { @@ -151,7 +152,6 @@ void CApache :: Spawn( void ) m_iRockets = 10; } - void CApache::Precache( void ) { PRECACHE_MODEL("models/apache.mdl"); @@ -175,15 +175,12 @@ void CApache::Precache( void ) 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 ); @@ -407,7 +404,6 @@ void CApache :: DyingThink( void ) } } - void CApache::FlyTouch( CBaseEntity *pOther ) { // bounce if we hit something solid @@ -420,7 +416,6 @@ void CApache::FlyTouch( CBaseEntity *pOther ) } } - void CApache::CrashTouch( CBaseEntity *pOther ) { // only crash if we hit something solid @@ -432,14 +427,11 @@ void CApache::CrashTouch( CBaseEntity *pOther ) } } - - 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( ); @@ -587,7 +579,6 @@ void CApache :: HuntThink( void ) } } - void CApache :: Flight( void ) { // tilt model 5 degrees @@ -742,7 +733,6 @@ void CApache :: Flight( void ) } } - void CApache :: FireRocket( void ) { static float side = 1.0; @@ -782,8 +772,6 @@ void CApache :: FireRocket( void ) side = - side; } - - BOOL CApache :: FireGun( ) { UTIL_MakeAimVectors( pev->angles ); @@ -865,8 +853,6 @@ BOOL CApache :: FireGun( ) return FALSE; } - - void CApache :: ShowDamage( void ) { if (m_iDoSmokePuff > 0 || RANDOM_LONG(0,99) > pev->health) @@ -885,7 +871,6 @@ void CApache :: ShowDamage( void ) m_iDoSmokePuff--; } - int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { if (pevInflictor->owner == edict()) @@ -908,8 +893,6 @@ int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa 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 ); @@ -933,10 +916,6 @@ void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir } } - - - - class CApacheHVR : public CGrenade { void Spawn( void ); @@ -951,7 +930,8 @@ class CApacheHVR : public CGrenade int m_iTrail; Vector m_vecForward; }; -LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ); + +LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ) TYPEDESCRIPTION CApacheHVR::m_SaveData[] = { @@ -959,7 +939,7 @@ TYPEDESCRIPTION CApacheHVR::m_SaveData[] = DEFINE_FIELD( CApacheHVR, m_vecForward, FIELD_VECTOR ), }; -IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ); +IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ) void CApacheHVR :: Spawn( void ) { @@ -984,7 +964,6 @@ void CApacheHVR :: Spawn( void ) pev->dmg = 150; } - void CApacheHVR :: Precache( void ) { PRECACHE_MODEL("models/HVR.mdl"); @@ -992,7 +971,6 @@ void CApacheHVR :: Precache( void ) PRECACHE_SOUND ("weapons/rocket1.wav"); } - void CApacheHVR :: IgniteThink( void ) { // pev->movetype = MOVETYPE_TOSS; @@ -1023,8 +1001,7 @@ void CApacheHVR :: IgniteThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - -void CApacheHVR :: AccelerateThink( void ) +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) @@ -1045,6 +1022,4 @@ void CApacheHVR :: AccelerateThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - - #endif diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp index dddcc50e..9570dbbe 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -65,7 +65,8 @@ public: } #endif }; -LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ); + +LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ) TYPEDESCRIPTION CBarnacle::m_SaveData[] = { @@ -78,8 +79,7 @@ TYPEDESCRIPTION CBarnacle::m_SaveData[] = DEFINE_FIELD( CBarnacle, m_flCachedLength, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ) //========================================================= // Classify - indicates this monster's place in the @@ -173,8 +173,7 @@ void CBarnacle :: BarnacleThink ( void ) if ( m_hEnemy != NULL ) { -// barnacle has prey. - + // barnacle has prey. if ( !m_hEnemy->IsAlive() ) { // someone (maybe even the barnacle) killed the prey. Reset barnacle. @@ -193,7 +192,7 @@ void CBarnacle :: BarnacleThink ( void ) return; } - // still pulling prey. + // still pulling prey. Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; vecNewEnemyOrigin.x = pev->origin.x; vecNewEnemyOrigin.y = pev->origin.y; @@ -207,7 +206,7 @@ void CBarnacle :: BarnacleThink ( void ) 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 ) + // 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 ); @@ -227,8 +226,7 @@ void CBarnacle :: BarnacleThink ( void ) } else { - // prey is lifted fully into feeding position and is dangling there. - + // prey is lifted fully into feeding position and is dangling there. pVictim = m_hEnemy->MyMonsterPointer(); if ( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) @@ -260,14 +258,14 @@ void CBarnacle :: BarnacleThink ( void ) } else { -// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. - + // 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. + { + // this is done so barnacle will fidget. SetActivity ( ACT_IDLE ); m_flTongueAdj = -100; } diff --git a/dlls/barney.cpp b/dlls/barney.cpp index baaf6148..6e4e4198 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -85,10 +85,10 @@ public: // UNDONE: What is this for? It isn't used? float m_flPlayerDamage;// how much pain has the player inflicted on me? - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES }; -LINK_ENTITY_TO_CLASS( monster_barney, CBarney ); +LINK_ENTITY_TO_CLASS( monster_barney, CBarney ) TYPEDESCRIPTION CBarney::m_SaveData[] = { @@ -99,7 +99,7 @@ TYPEDESCRIPTION CBarney::m_SaveData[] = DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ); +IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ) //========================================================= // AI Schedules Specific to this monster @@ -171,7 +171,6 @@ Schedule_t slBaFaceTarget[] = }, }; - Task_t tlIdleBaStand[] = { { TASK_STOP_MOVING, 0 }, @@ -212,8 +211,7 @@ DEFINE_CUSTOM_SCHEDULES( CBarney ) slIdleBaStand, }; - -IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ) void CBarney :: StartTask( Task_t *pTask ) { @@ -237,9 +235,6 @@ void CBarney :: RunTask( Task_t *pTask ) } } - - - //========================================================= // ISoundMask - returns a bit mask indicating which types // of sounds this monster regards. @@ -276,8 +271,8 @@ void CBarney :: AlertSound( void ) 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. @@ -307,7 +302,6 @@ void CBarney :: SetYawSpeed ( void ) pev->yaw_speed = ys; } - //========================================================= // CheckRangeAttack1 //========================================================= @@ -335,7 +329,6 @@ BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) return FALSE; } - //========================================================= // BarneyFirePistol - shoots one round from the pistol at // the enemy barney is facing. @@ -453,8 +446,7 @@ void CBarney :: Precache() // Init talk data void CBarney :: TalkInit() -{ - +{ CTalkMonster::TalkInit(); // scientists speach group names (group names are in sentences.txt) @@ -487,7 +479,6 @@ void CBarney :: TalkInit() m_voicePitch = 100; } - static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) { Vector vecDir = (reference - pevTest->origin); @@ -497,6 +488,7 @@ static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) 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 { @@ -505,7 +497,6 @@ static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) 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... @@ -545,7 +536,6 @@ int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return ret; } - //========================================================= // PainSound @@ -600,6 +590,7 @@ void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir flDamage = 0.01; } } + // always a head shot ptr->iHitgroup = HITGROUP_HEAD; break; @@ -608,11 +599,11 @@ void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); } - void CBarney::Killed( entvars_t *pevAttacker, int iGib ) { if ( pev->body < BARNEY_BODY_GUNGONE ) - {// drop the gun! + { + // drop the gun! Vector vecGunPos; Vector vecGunAngles; @@ -768,17 +759,11 @@ MONSTERSTATE CBarney :: GetIdealState ( void ) return CTalkMonster::GetIdealState(); } - - void CBarney::DeclineFollowing( void ) { PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); } - - - - //========================================================= // DEAD BARNEY PROP // @@ -814,7 +799,7 @@ void CDeadBarney::KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } -LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ); +LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ) //========================================================= // ********** DeadBarney SPAWN ********** @@ -839,5 +824,3 @@ void CDeadBarney :: Spawn( ) MonsterInitDead(); } - - diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 190965d9..7a482490 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -31,7 +31,7 @@ public: 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, + SCRIPT_RUN_TO_MARK } SCRIPTSTATE; @@ -104,7 +104,7 @@ public: Vector m_HackedGunPos; // HACK until we can query end of gun -// Scripted sequence Info + // Scripted sequence Info SCRIPTSTATE m_scriptState; // internal cinematic state CCineMonster *m_pCine; @@ -115,11 +115,11 @@ public: void KeyValue( KeyValueData *pkvd ); -// monster use function + // 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 + // overrideable Monster member functions virtual int BloodColor( void ) { return m_bloodColor; } @@ -131,14 +131,14 @@ public: virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } virtual BOOL ShouldFadeOnDeath( void ); -// Basic Monster AI functions + // 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 + // stuff written for new state machine virtual void MonsterThink( void ); void EXPORT CallMonsterThink( void ) { this->MonsterThink(); } virtual int IRelationship ( CBaseEntity *pTarget ); @@ -333,7 +333,4 @@ public: CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. }; - - - #endif // BASEMONSTER_H diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index d22cb464..e9b5a988 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -51,20 +51,19 @@ public: int m_preSequence; }; -LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ); +LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ) TYPEDESCRIPTION CInfoBM::m_SaveData[] = { DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ); +IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ) void CInfoBM::Spawn( void ) { } - void CInfoBM::KeyValue( KeyValueData* pkvd ) { if (FStrEq(pkvd->szKeyName, "radius")) @@ -115,15 +114,14 @@ public: int m_maxFrame; }; -LINK_ENTITY_TO_CLASS( bmortar, CBMortar ); +LINK_ENTITY_TO_CLASS( bmortar, CBMortar ) TYPEDESCRIPTION CBMortar::m_SaveData[] = { DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); - +IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ) //========================================================= // Monster's Anim Events Go Here @@ -147,8 +145,6 @@ IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); #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 @@ -157,7 +153,6 @@ IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); #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) @@ -167,7 +162,6 @@ 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" @@ -303,7 +297,7 @@ public: static const char *pPainSounds[]; static const char *pFootSounds[]; - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES private: float m_nodeTime; @@ -312,7 +306,8 @@ private: float m_painSoundTime; int m_crabCount; }; -LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ); + +LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ) TYPEDESCRIPTION CBigMomma::m_SaveData[] = { @@ -323,7 +318,7 @@ TYPEDESCRIPTION CBigMomma::m_SaveData[] = DEFINE_FIELD( CBigMomma, m_crabCount, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ) const char *CBigMomma::pChildDieSounds[] = { @@ -344,49 +339,48 @@ const char *CBigMomma::pDeathSounds[] = "gonarch/gon_die1.wav", }; -const char *CBigMomma::pAttackSounds[] = +const char *CBigMomma::pAttackSounds[] = { "gonarch/gon_attack1.wav", "gonarch/gon_attack2.wav", "gonarch/gon_attack3.wav", }; -const char *CBigMomma::pAttackHitSounds[] = + +const char *CBigMomma::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CBigMomma::pBirthSounds[] = +const char *CBigMomma::pBirthSounds[] = { "gonarch/gon_birth1.wav", "gonarch/gon_birth2.wav", "gonarch/gon_birth3.wav", }; -const char *CBigMomma::pAlertSounds[] = +const char *CBigMomma::pAlertSounds[] = { "gonarch/gon_alert1.wav", "gonarch/gon_alert2.wav", "gonarch/gon_alert3.wav", }; -const char *CBigMomma::pPainSounds[] = +const char *CBigMomma::pPainSounds[] = { "gonarch/gon_pain2.wav", "gonarch/gon_pain4.wav", "gonarch/gon_pain5.wav", }; -const char *CBigMomma::pFootSounds[] = +const char *CBigMomma::pFootSounds[] = { "gonarch/gon_step1.wav", "gonarch/gon_step2.wav", "gonarch/gon_step3.wav", }; - - void CBigMomma :: KeyValue( KeyValueData *pkvd ) { #if 0 @@ -575,11 +569,9 @@ void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve 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 @@ -625,8 +617,6 @@ void CBigMomma :: LayHeadcrab( void ) m_crabCount++; } - - void CBigMomma::DeathNotice( entvars_t *pevChild ) { if ( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then @@ -638,7 +628,6 @@ void CBigMomma::DeathNotice( entvars_t *pevChild ) } } - void CBigMomma::LaunchMortar( void ) { m_mortarTime = gpGlobals->time + RANDOM_FLOAT( 2, 15 ); @@ -702,14 +691,12 @@ void CBigMomma :: Precache() PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); } - void CBigMomma::Activate( void ) { if ( m_hTargetEnt == NULL ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up } - void CBigMomma::NodeStart( int iszNextNode ) { pev->netname = iszNextNode; @@ -735,7 +722,6 @@ void CBigMomma::NodeStart( int iszNextNode ) m_hTargetEnt = pTarget; } - void CBigMomma::NodeReach( void ) { CBaseEntity *pTarget = m_hTargetEnt; @@ -760,8 +746,7 @@ void CBigMomma::NodeReach( void ) Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node } - - // Slash +// Slash BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) { if (flDot >= 0.7) @@ -772,7 +757,6 @@ BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) return FALSE; } - // Lay a crab BOOL CBigMomma::CheckMeleeAttack2( float flDot, float flDist ) { @@ -806,7 +790,7 @@ BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) enum { SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, - SCHED_NODE_FAIL, + SCHED_NODE_FAIL }; enum @@ -818,10 +802,9 @@ enum 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_NODE_YAW // Get the best facing direction for this node }; - Task_t tlBigNode[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_NODE_FAIL }, @@ -849,7 +832,6 @@ Schedule_t slBigNode[] = }, }; - Task_t tlNodeFail[] = { { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds @@ -873,10 +855,7 @@ DEFINE_CUSTOM_SCHEDULES( CBigMomma ) slNodeFail, }; -IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ); - - - +IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ) Schedule_t *CBigMomma::GetScheduleOfType( int Type ) { @@ -894,7 +873,6 @@ Schedule_t *CBigMomma::GetScheduleOfType( int Type ) return CBaseMonster::GetScheduleOfType( Type ); } - BOOL CBigMomma::ShouldGoToNode( void ) { if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) @@ -905,8 +883,6 @@ BOOL CBigMomma::ShouldGoToNode( void ) return FALSE; } - - Schedule_t *CBigMomma::GetSchedule( void ) { if ( ShouldGoToNode() ) @@ -917,7 +893,6 @@ Schedule_t *CBigMomma::GetSchedule( void ) return CBaseMonster::GetSchedule(); } - void CBigMomma::StartTask( Task_t *pTask ) { switch ( pTask->iTask ) @@ -1053,9 +1028,7 @@ void CBigMomma::RunTask( Task_t *pTask ) } } } - break; - case TASK_WAIT_NODE: if ( m_hTargetEnt != NULL && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) return; @@ -1064,7 +1037,6 @@ void CBigMomma::RunTask( Task_t *pTask ) TaskComplete(); ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); break; - case TASK_PLAY_NODE_PRESEQUENCE: case TASK_PLAY_NODE_SEQUENCE: if ( m_fSequenceFinished ) @@ -1073,15 +1045,12 @@ void CBigMomma::RunTask( Task_t *pTask ) TaskComplete(); } break; - default: CBaseMonster::RunTask( pTask ); break; } } - - Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ) { TraceResult tr; @@ -1125,9 +1094,6 @@ Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot return vecGrenadeVel; } - - - // --------------------------------- // // Mortar @@ -1150,7 +1116,6 @@ void MortarSpray( const Vector &position, const Vector &direction, int spriteMod 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 ) { @@ -1204,7 +1169,6 @@ CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity return pSpit; } - void CBMortar::Touch( CBaseEntity *pOther ) { TraceResult tr; @@ -1237,6 +1201,7 @@ void CBMortar::Touch( CBaseEntity *pOther ) tr.vecEndPos = pev->origin; tr.vecPlaneNormal = -1 * pev->velocity.Normalize(); } + // make some flecks MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); @@ -1247,5 +1212,4 @@ void CBMortar::Touch( CBaseEntity *pOther ) RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); UTIL_Remove( this ); } - #endif diff --git a/dlls/bloater.cpp b/dlls/bloater.cpp index 1f14840d..e6ffcb2a 100644 --- a/dlls/bloater.cpp +++ b/dlls/bloater.cpp @@ -22,13 +22,11 @@ #include "monsters.h" #include "schedule.h" - //========================================================= // Monster's Anim Events Go Here //========================================================= #define BLOATER_AE_ATTACK_MELEE1 0x01 - class CBloater : public CBaseMonster { public: @@ -49,7 +47,7 @@ public: int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); }; -LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ); +LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ) //========================================================= // Classify - indicates this monster's place in the @@ -69,13 +67,11 @@ void CBloater :: SetYawSpeed ( void ) int ys; ys = 120; - #if 0 switch ( m_Activity ) { } #endif - pev->yaw_speed = ys; } @@ -161,7 +157,6 @@ void CBloater :: AttackSnd( void ) #endif } - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -171,11 +166,11 @@ void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) switch( pEvent->event ) { case BLOATER_AE_ATTACK_MELEE1: - { - // do stuff for this event. - AttackSnd(); - } - break; + { + // do stuff for this event. + AttackSnd(); + } + break; default: CBaseMonster::HandleAnimEvent( pEvent ); diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index 15d35c7c..d6fa32b8 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -60,7 +60,7 @@ public: virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; -LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); +LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ) void CFuncWall :: Spawn( void ) { @@ -73,14 +73,12 @@ void CFuncWall :: Spawn( void ) 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 @@ -93,7 +91,7 @@ public: BOOL IsOn( void ); }; -LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); +LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ) void CFuncWallToggle :: Spawn( void ) { @@ -102,7 +100,6 @@ void CFuncWallToggle :: Spawn( void ) TurnOff(); } - void CFuncWallToggle :: TurnOff( void ) { pev->solid = SOLID_NOT; @@ -110,7 +107,6 @@ void CFuncWallToggle :: TurnOff( void ) UTIL_SetOrigin( pev, pev->origin ); } - void CFuncWallToggle :: TurnOn( void ) { pev->solid = SOLID_BSP; @@ -118,7 +114,6 @@ void CFuncWallToggle :: TurnOn( void ) UTIL_SetOrigin( pev, pev->origin ); } - BOOL CFuncWallToggle :: IsOn( void ) { if ( pev->solid == SOLID_NOT ) @@ -126,7 +121,6 @@ BOOL CFuncWallToggle :: IsOn( void ) return TRUE; } - void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int status = IsOn(); @@ -140,7 +134,6 @@ void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ } } - #define SF_CONVEYOR_VISUAL 0x0001 #define SF_CONVEYOR_NOTSOLID 0x0002 @@ -152,7 +145,8 @@ public: void UpdateSpeed( float speed ); }; -LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); +LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ) + void CFuncConveyor :: Spawn( void ) { SetMovedir( pev ); @@ -174,7 +168,6 @@ void CFuncConveyor :: Spawn( void ) 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 ) { @@ -190,15 +183,12 @@ void CFuncConveyor :: UpdateSpeed( float speed ) 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 ============================================== @@ -214,7 +204,7 @@ public: virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; -LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); +LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ) void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) { @@ -240,7 +230,6 @@ void CFuncIllusionary :: Spawn( void ) // MAKE_STATIC(ENT(pev)); } - // ------------------------------------------------------------------------------- // // Monster only clip brush @@ -259,7 +248,7 @@ public: 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 ); +LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ) void CFuncMonsterClip::Spawn( void ) { @@ -269,7 +258,6 @@ void CFuncMonsterClip::Spawn( void ) pev->flags |= FL_MONSTERCLIP; } - // =================== FUNC_ROTATING ============================================== class CFuncRotating : public CBaseEntity { @@ -307,10 +295,9 @@ TYPEDESCRIPTION CFuncRotating::m_SaveData[] = DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER ) }; -IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ) - -LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); +LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ) void CFuncRotating :: KeyValue( KeyValueData* pkvd) { @@ -358,7 +345,6 @@ check either the X_AXIS or Y_AXIS box to change that. REVERSE will cause the it to rotate in the opposite direction. */ - void CFuncRotating :: Spawn( ) { // set final pitch. Must not be PITCH_NORM, since we @@ -443,7 +429,6 @@ void CFuncRotating :: Spawn( ) Precache( ); } - void CFuncRotating :: Precache( void ) { char* szSoundFile = (char*) STRING(pev->message); @@ -457,7 +442,8 @@ void CFuncRotating :: Precache( void ) PRECACHE_SOUND(szSoundFile); pev->noiseRunning = ALLOC_STRING(szSoundFile); - } else + } + else { // otherwise use preset sound switch (m_sounds) @@ -509,8 +495,6 @@ void CFuncRotating :: Precache( void ) } } - - // // Touch - will hurt others based on how fast the brush is spinning // @@ -573,10 +557,8 @@ void CFuncRotating :: RampPitchVol (int fUp) 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); - } // @@ -592,9 +574,9 @@ void CFuncRotating :: SpinUp( void ) vecAVel = pev->avelocity;// cache entity's rotational velocity // if we've met or exceeded target speed, set target speed and stop thinking - if ( fabs(vecAVel.x) >= fabs(pev->movedir.x * pev->speed) && - fabs(vecAVel.y) >= fabs(pev->movedir.y * pev->speed) && - fabs(vecAVel.z) >= fabs(pev->movedir.z * pev->speed) ) + if( fabs( vecAVel.x ) >= fabs( pev->movedir.x * pev->speed ) && + fabs( vecAVel.y ) >= fabs( pev->movedir.y * pev->speed ) && + fabs( vecAVel.z ) >= fabs( 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), @@ -706,24 +688,14 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller } } - // // 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: @@ -751,9 +723,9 @@ public: vec3_t m_start; }; -LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); +LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ) -TYPEDESCRIPTION CPendulum::m_SaveData[] = +TYPEDESCRIPTION CPendulum::m_SaveData[] = { DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ), DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ), @@ -765,9 +737,7 @@ TYPEDESCRIPTION CPendulum::m_SaveData[] = DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ), }; -IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ); - - +IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ) void CPendulum :: KeyValue( KeyValueData *pkvd ) { @@ -785,7 +755,6 @@ void CPendulum :: KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } - void CPendulum :: Spawn( void ) { // set the axis of rotation @@ -824,7 +793,6 @@ void CPendulum :: Spawn( void ) } } - 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 @@ -855,7 +823,6 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US } } - void CPendulum :: Stop( void ) { pev->angles = m_start; @@ -864,13 +831,11 @@ void CPendulum :: Stop( void ) pev->avelocity = g_vecZero; } - void CPendulum::Blocked( CBaseEntity *pOther ) { m_time = gpGlobals->time; } - void CPendulum :: Swing( void ) { float delta, dt; @@ -912,7 +877,6 @@ void CPendulum :: Swing( void ) } } - void CPendulum :: Touch ( CBaseEntity *pOther ) { entvars_t *pevOther = pOther->pev; @@ -954,5 +918,3 @@ void CPendulum :: RopeTouch ( CBaseEntity *pOther ) pevOther->velocity = g_vecZero; pevOther->movetype = MOVETYPE_NONE; } - - diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 73f432f1..e295ffb5 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -31,7 +31,6 @@ int iSquidSpitSprite; - //========================================================= // monster-specific schedule types //========================================================= @@ -42,7 +41,7 @@ enum SCHED_SQUID_SEECRAB, SCHED_SQUID_EAT, SCHED_SQUID_SNIFF_AND_EAT, - SCHED_SQUID_WALLOW, + SCHED_SQUID_WALLOW }; //========================================================= @@ -50,7 +49,7 @@ enum //========================================================= enum { - TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1, + TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1 }; //========================================================= @@ -72,14 +71,14 @@ public: int m_maxFrame; }; -LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ); +LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ) TYPEDESCRIPTION CSquidSpit::m_SaveData[] = { DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ) void CSquidSpit:: Spawn( void ) { @@ -225,16 +224,17 @@ public: 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[] = +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 ); +IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ) //========================================================= // IgnoreConditions @@ -258,7 +258,6 @@ int CBullsquid::IgnoreConditions ( void ) } } - return iIgnore; } @@ -626,7 +625,6 @@ void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, 0, 0 ); - if ( pHurt ) { // croonchy bite sound @@ -729,7 +727,6 @@ void CBullsquid :: Precache() PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); - } //========================================================= @@ -767,7 +764,6 @@ void CBullsquid :: AttackSound ( void ) } } - //======================================================== // RunAI - overridden for bullsquid because there are things // that need to be checked every think. @@ -796,7 +792,6 @@ void CBullsquid :: RunAI ( void ) pev->framerate = 1.25; } } - } //======================================================== @@ -1014,7 +1009,7 @@ DEFINE_CUSTOM_SCHEDULES( CBullsquid ) slSquidWallow }; -IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ) //========================================================= // GetSchedule @@ -1240,7 +1235,6 @@ void CBullsquid :: RunTask ( Task_t *pTask ) } } - //========================================================= // GetIdealState - Overridden for Bullsquid to deal with // the feature that makes it lose interest in headcrabs for @@ -1276,4 +1270,3 @@ MONSTERSTATE CBullsquid :: GetIdealState ( void ) return m_IdealMonsterState; } - diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 5856cd11..bbbe3a1c 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -26,7 +26,6 @@ #include "saverestore.h" #include "doors.h" - #define SF_BUTTON_DONTMOVE 1 #define SF_ROTBUTTON_NOTSOLID 1 #define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated @@ -59,9 +58,9 @@ TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = DEFINE_FIELD( CEnvGlobal, m_initialstate, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CEnvGlobal, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CEnvGlobal, CBaseEntity ) -LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal ); +LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal ) void CEnvGlobal::KeyValue( KeyValueData *pkvd ) { @@ -91,7 +90,6 @@ void CEnvGlobal::Spawn( void ) } } - void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { GLOBALESTATE oldState = gGlobalState.EntityGetState( m_globalstate ); @@ -102,15 +100,12 @@ void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us 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 ) @@ -138,9 +133,10 @@ TYPEDESCRIPTION CMultiSource::m_SaveData[] = DEFINE_FIELD( CMultiSource, m_globalstate, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CMultiSource, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CMultiSource, CBaseEntity ) + +LINK_ENTITY_TO_CLASS( multisource, CMultiSource ) -LINK_ENTITY_TO_CLASS( multisource, CMultiSource ); // // Cache user-entity-field values until spawn is called. // @@ -207,7 +203,6 @@ void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } - BOOL CMultiSource::IsTriggered( CBaseEntity * ) { // Is everything triggered? @@ -264,7 +259,6 @@ void CMultiSource::Register(void) pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "classname", "multi_manager" ); } - pev->spawnflags &= ~SF_MULTI_INIT; } @@ -283,8 +277,7 @@ TYPEDESCRIPTION CBaseButton::m_SaveData[] = // DEFINE_FIELD( CBaseButton, m_ls, FIELD_??? ), // This is restored in Precache() }; - -IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ); +IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ) void CBaseButton::Precache( void ) { @@ -436,8 +429,8 @@ where it can be triggered again. 2) metallic click 3) in-out */ -LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); +LINK_ENTITY_TO_CLASS( func_button, CBaseButton ) void CBaseButton::Spawn( ) { @@ -504,7 +497,6 @@ void CBaseButton::Spawn( ) } } - // Button sound table. // Also used by CBaseDoor to get 'touched' door lock/unlock sounds @@ -530,8 +522,8 @@ char *ButtonSound( int sound ) 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 - + // 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; @@ -573,7 +565,6 @@ void CBaseButton::ButtonSpark ( void ) DoSpark( pev, pev->mins ); } - // // Button's Use function // @@ -599,7 +590,6 @@ void CBaseButton::ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE ButtonActivate( ); } - CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) { // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. @@ -621,7 +611,6 @@ CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) return BUTTON_NOTHING; } - // // Touching a button simply "activates" it. // @@ -723,7 +712,6 @@ void CBaseButton::TriggerAndWait( void ) SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); } - // // Starts the button moving "out/down". // @@ -741,7 +729,6 @@ void CBaseButton::ButtonReturn( void ) pev->frame = 0; // use normal textures } - // // Button has returned to start state. Quiesce it. // @@ -777,16 +764,16 @@ void CBaseButton::ButtonBackHome( void ) } } -// Re-instate touch method, movement cycle is complete. + // 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 + // All buttons are now use only SetTouch( NULL ); } else SetTouch( &CBaseButton::ButtonTouch ); -// reset think for a sparking button + // reset think for a sparking button if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) { SetThink( &CBaseButton::ButtonSpark ); @@ -794,8 +781,6 @@ void CBaseButton::ButtonBackHome( void ) } } - - // // Rotating button (aka "lever") // @@ -805,7 +790,7 @@ public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); +LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ) void CRotButton::Spawn( void ) { @@ -865,7 +850,6 @@ void CRotButton::Spawn( void ) //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 @@ -907,6 +891,7 @@ public: vec3_t m_end; int m_sounds; }; + TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = { DEFINE_FIELD( CMomentaryRotButton, m_lastUsed, FIELD_INTEGER ), @@ -917,9 +902,9 @@ TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = DEFINE_FIELD( CMomentaryRotButton, m_sounds, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle ); +IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle ) -LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); +LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ) void CMomentaryRotButton::Spawn( void ) { @@ -1094,7 +1079,6 @@ void CMomentaryRotButton::Return( void ) UpdateTarget( value ); } - void CMomentaryRotButton::UpdateSelfReturn( float value ) { if ( value <= 0 ) @@ -1111,7 +1095,6 @@ void CMomentaryRotButton::UpdateSelfReturn( float value ) } } - //---------------------------------------------------------------- // Spark //---------------------------------------------------------------- @@ -1134,16 +1117,15 @@ public: float m_flDelay; }; - TYPEDESCRIPTION CEnvSpark::m_SaveData[] = { DEFINE_FIELD( CEnvSpark, m_flDelay, FIELD_FLOAT), }; -IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ) -LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark); -LINK_ENTITY_TO_CLASS(env_debris, CEnvSpark); +LINK_ENTITY_TO_CLASS( env_spark, CEnvSpark ) +LINK_ENTITY_TO_CLASS( env_debris, CEnvSpark ) void CEnvSpark::Spawn(void) { @@ -1171,7 +1153,6 @@ void CEnvSpark::Spawn(void) Precache( ); } - void CEnvSpark::Precache(void) { PRECACHE_SOUND( "buttons/spark1.wav" ); @@ -1228,11 +1209,10 @@ 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 ); - + int ObjectCaps( void ); }; -LINK_ENTITY_TO_CLASS( button_target, CButtonTarget ); +LINK_ENTITY_TO_CLASS( button_target, CButtonTarget ) void CButtonTarget::Spawn( void ) { @@ -1256,7 +1236,6 @@ void CButtonTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE SUB_UseTargets( pActivator, USE_OFF, 0 ); } - int CButtonTarget :: ObjectCaps( void ) { int caps = CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; @@ -1267,7 +1246,6 @@ int CButtonTarget :: ObjectCaps( void ) return caps; } - int CButtonTarget::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { Use( Instance(pevAttacker), this, USE_TOGGLE, 0 ); diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index e00ef46f..eacb5124 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -128,7 +129,6 @@ int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) } #endif - int DispatchSpawn( edict_t *pent ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); @@ -202,10 +202,10 @@ void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) 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 ) @@ -218,7 +218,6 @@ void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) pEntity->Touch( pOther ); } - void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed); @@ -281,7 +280,6 @@ void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) } } - // 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 ) @@ -300,7 +298,6 @@ CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname ) return pReturn; } - int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); @@ -322,7 +319,6 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity 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 @@ -368,14 +364,12 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity // 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 ) { @@ -412,7 +406,6 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity return 0; } - void DispatchObjectCollsionBox( edict_t *pent ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); @@ -424,21 +417,18 @@ void DispatchObjectCollsionBox( edict_t *pent ) 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) @@ -449,7 +439,7 @@ edict_t * EHANDLE::Get( void ) return NULL; } return NULL; -}; +} edict_t * EHANDLE::Set( edict_t *pent ) { @@ -457,14 +447,12 @@ edict_t * EHANDLE::Set( edict_t *pent ) if (pent) m_serialnumber = m_pent->serialnumber; return pent; -}; - +} EHANDLE :: operator CBaseEntity *() { return (CBaseEntity *)GET_PRIVATE( Get( ) ); -}; - +} CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) { @@ -492,14 +480,13 @@ CBaseEntity * EHANDLE :: operator -> () return (CBaseEntity *)GET_PRIVATE( Get( ) ); } - // give health int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { if (!pev->takedamage) return 0; -// heal + // heal if ( pev->health >= pev->max_health ) return 0; @@ -534,12 +521,11 @@ int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); } -// this global is still used for glass and other non-monster killables, along with decals. + // 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) + // 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; @@ -552,7 +538,7 @@ int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, pev->velocity = pev->velocity + vecDir * flForce; } -// do the damage + // do the damage pev->health -= flDamage; if (pev->health <= 0) { @@ -563,7 +549,6 @@ int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, return 1; } - void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) { pev->takedamage = DAMAGE_NO; @@ -571,7 +556,6 @@ void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) UTIL_Remove( this ); } - CBaseEntity *CBaseEntity::GetNextTarget( void ) { if ( FStringNull( pev->target ) ) @@ -594,7 +578,6 @@ TYPEDESCRIPTION CBaseEntity::m_SaveData[] = DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ), }; - int CBaseEntity::Save( CSave &save ) { if ( save.WriteEntVars( "ENTVARS", pev ) ) @@ -611,13 +594,12 @@ int CBaseEntity::Restore( CRestore &restore ) if ( status ) status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - if ( pev->modelindex != 0 && !FStringNull(pev->model) ) + 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 @@ -626,7 +608,6 @@ int CBaseEntity::Restore( CRestore &restore ) return status; } - // Initialize absmin & absmax to the appropriate box void SetObjectCollisionBox( entvars_t *pev ) { @@ -666,14 +647,12 @@ void SetObjectCollisionBox( entvars_t *pev ) pev->absmax.z += 1; } - void CBaseEntity::SetObjectCollisionBox( void ) { ::SetObjectCollisionBox( pev ); } - -int CBaseEntity :: Intersects( CBaseEntity *pOther ) +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { if ( pOther->pev->absmin.x > pev->absmax.x || pOther->pev->absmin.y > pev->absmax.y || @@ -737,7 +716,7 @@ int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) } -int CBaseEntity :: DamageDecal( int bitsDamageType ) +int CBaseEntity :: DamageDecal( int bitsDamageType ) { if ( pev->rendermode == kRenderTransAlpha ) return -1; @@ -748,8 +727,6 @@ int CBaseEntity :: DamageDecal( int bitsDamageType ) 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( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) @@ -770,5 +747,3 @@ CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const DispatchSpawn( pEntity->edict() ); return pEntity; } - - diff --git a/dlls/controller.cpp b/dlls/controller.cpp index 39f9742b..c3f57e0f 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -101,7 +101,7 @@ public: int m_fInCombat; }; -LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ); +LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ) TYPEDESCRIPTION CController::m_SaveData[] = { @@ -111,8 +111,8 @@ TYPEDESCRIPTION CController::m_SaveData[] = DEFINE_ARRAY( CController, m_iBallCurrent, FIELD_INTEGER, 2 ), DEFINE_FIELD( CController, m_vecEstVelocity, FIELD_VECTOR ), }; -IMPLEMENT_SAVERESTORE( CController, CSquadMonster ); +IMPLEMENT_SAVERESTORE( CController, CSquadMonster ) const char *CController::pAttackSounds[] = { @@ -150,7 +150,6 @@ const char *CController::pDeathSounds[] = "controller/con_die2.wav", }; - //========================================================= // Classify - indicates this monster's place in the // relationship table. @@ -169,13 +168,11 @@ void CController :: SetYawSpeed ( void ) int ys; ys = 120; - #if 0 switch ( m_Activity ) { } #endif - pev->yaw_speed = ys; } @@ -187,7 +184,6 @@ int CController :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } - void CController::Killed( entvars_t *pevAttacker, int iGib ) { // shut off balls @@ -213,7 +209,6 @@ void CController::Killed( entvars_t *pevAttacker, int iGib ) CSquadMonster::Killed( pevAttacker, iGib ); } - void CController::GibMonster( void ) { // delete balls @@ -230,9 +225,6 @@ void CController::GibMonster( void ) CSquadMonster::GibMonster( ); } - - - void CController :: PainSound( void ) { if (RANDOM_LONG(0,5) < 2) @@ -324,7 +316,6 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) m_iBall[1] = 0; } break; - case CONTROLLER_AE_SMALL_SHOOT: { AttackSound( ); @@ -399,7 +390,6 @@ void CController :: Precache() // AI Schedules Specific to this monster //========================================================= - // Chase enemy schedule Task_t tlControllerChaseEnemy[] = { @@ -420,8 +410,6 @@ Schedule_t slControllerChaseEnemy[] = }, }; - - Task_t tlControllerStrafe[] = { { TASK_WAIT, (float)0.2 }, @@ -441,7 +429,6 @@ Schedule_t slControllerStrafe[] = }, }; - Task_t tlControllerTakeCover[] = { { TASK_WAIT, (float)0.2 }, @@ -461,7 +448,6 @@ Schedule_t slControllerTakeCover[] = }, }; - Task_t tlControllerFail[] = { { TASK_STOP_MOVING, 0 }, @@ -481,8 +467,6 @@ Schedule_t slControllerFail[] = }, }; - - DEFINE_CUSTOM_SCHEDULES( CController ) { slControllerChaseEnemy, @@ -491,9 +475,7 @@ DEFINE_CUSTOM_SCHEDULES( CController ) slControllerFail, }; -IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ); - - +IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ) //========================================================= // StartTask @@ -547,7 +529,6 @@ void CController :: StartTask ( Task_t *pTask ) } } - Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) { Vector vecTo = vecDst - vecSrc; @@ -585,7 +566,6 @@ Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) return vecHit.Normalize( ) * flSpeed; } - int CController::LookupFloat( ) { if (m_velocity.Length( ) < 32.0) @@ -621,7 +601,6 @@ int CController::LookupFloat( ) } } - //========================================================= // RunTask //========================================================= @@ -720,7 +699,6 @@ void CController :: RunTask ( Task_t *pTask ) } } - //========================================================= // GetSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls @@ -756,8 +734,6 @@ Schedule_t *CController :: GetSchedule ( void ) return CSquadMonster :: GetSchedule(); } - - //========================================================= //========================================================= Schedule_t* CController :: GetScheduleOfType ( int Type ) @@ -781,10 +757,6 @@ Schedule_t* CController :: GetScheduleOfType ( int Type ) return CBaseMonster :: GetScheduleOfType( Type ); } - - - - //========================================================= // CheckRangeAttack1 - shoot a bigass energy ball out of their head // @@ -798,7 +770,6 @@ BOOL CController :: CheckRangeAttack1 ( float flDot, float flDist ) return FALSE; } - BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) { if ( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) @@ -808,13 +779,11 @@ BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) return FALSE; } - BOOL CController :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } - void CController :: SetActivity ( Activity NewActivity ) { CBaseMonster::SetActivity( NewActivity ); @@ -830,8 +799,6 @@ void CController :: SetActivity ( Activity NewActivity ) } } - - //========================================================= // RunAI //========================================================= @@ -882,7 +849,6 @@ void CController :: RunAI( void ) } } - extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); void CController::Stop( void ) @@ -890,8 +856,8 @@ void CController::Stop( void ) m_IdealActivity = GetStoppedActivity(); } - #define DIST_TO_CHECK 200 + void CController :: Move ( float flInterval ) { float flWaypointDist; @@ -928,7 +894,6 @@ void CController :: Move ( float flInterval ) // 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; @@ -994,7 +959,7 @@ void CController :: Move ( float flInterval ) { // Wait for a second m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - // ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); + //ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); return; } } @@ -1008,7 +973,7 @@ void CController :: Move ( float flInterval ) } else { - ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); + ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); Stop(); if ( m_moveWaitTime > 0 ) { @@ -1072,8 +1037,6 @@ void CController :: Move ( float flInterval ) } } - - BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) { if ( flWaypointDist <= 32 ) @@ -1084,7 +1047,6 @@ BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) return FALSE; } - int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { TraceResult tr; @@ -1110,7 +1072,6 @@ int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd return LOCALMOVE_VALID; } - void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { if ( m_IdealActivity != m_movementActivity ) @@ -1123,13 +1084,9 @@ void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, fl 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 ); - + UTIL_MoveToOrigin ( ENT(pev), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); } - - - //========================================================= // Controller bouncy ball attack //========================================================= @@ -1147,9 +1104,8 @@ class CControllerHeadBall : public CBaseMonster Vector m_vecIdeal; EHANDLE m_hOwner; }; -LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ); - +LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ) void CControllerHeadBall :: Spawn( void ) { @@ -1180,7 +1136,6 @@ void CControllerHeadBall :: Spawn( void ) pev->dmgtime = gpGlobals->time; } - void CControllerHeadBall :: Precache( void ) { PRECACHE_MODEL("sprites/xspark1.spr"); @@ -1188,7 +1143,6 @@ void CControllerHeadBall :: Precache( void ) PRECACHE_SOUND("weapons/electro4.wav"); } - void CControllerHeadBall :: HuntThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -1260,16 +1214,14 @@ void CControllerHeadBall :: HuntThink( void ) pev->nextthink = gpGlobals->time + 0.3; } - // Crawl( ); + //Crawl( ); } - void CControllerHeadBall :: DieThink( void ) { UTIL_Remove( this ); } - void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) { // accelerate @@ -1288,8 +1240,6 @@ void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) pev->velocity = m_vecIdeal; } - - void CControllerHeadBall :: Crawl( void ) { @@ -1316,7 +1266,6 @@ void CControllerHeadBall :: Crawl( void ) MESSAGE_END(); } - void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) { Vector vecDir = m_vecIdeal.Normalize( ); @@ -1330,9 +1279,6 @@ void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) m_vecIdeal = vecDir * m_vecIdeal.Length(); } - - - class CControllerZapBall : public CBaseMonster { void Spawn( void ); @@ -1342,8 +1288,8 @@ class CControllerZapBall : public CBaseMonster EHANDLE m_hOwner; }; -LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ); +LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ) void CControllerZapBall :: Spawn( void ) { @@ -1371,7 +1317,6 @@ void CControllerZapBall :: Spawn( void ) pev->nextthink = gpGlobals->time + 0.1; } - void CControllerZapBall :: Precache( void ) { PRECACHE_MODEL("sprites/xspark4.spr"); @@ -1379,7 +1324,6 @@ void CControllerZapBall :: Precache( void ) // PRECACHE_SOUND("weapons/electro4.wav"); } - void CControllerZapBall :: AnimateThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -1393,7 +1337,6 @@ void CControllerZapBall :: AnimateThink( void ) } } - void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) { if (pOther->pev->takedamage) @@ -1420,7 +1363,4 @@ void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) UTIL_Remove( this ); } - - - -#endif // !OEM && !HLDEMO +#endif //!OEM && !HLDEMO diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 28bd8cfd..f84e6122 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -247,10 +247,10 @@ enum crossbow_e { CROSSBOW_DRAW1, // full CROSSBOW_DRAW2, // empty CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty + CROSSBOW_HOLSTER2 // empty }; -LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ); +LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ) void CCrossbow::Spawn( ) { diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 7225e747..7ff7911b 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -26,9 +26,7 @@ #define CROWBAR_BODYHIT_VOLUME 128 #define CROWBAR_WALLHIT_VOLUME 512 -LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ); - - +LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ) enum gauss_e { CROWBAR_IDLE = 0, diff --git a/dlls/decals.h b/dlls/decals.h index 95fa44f5..dd13fafe 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -61,7 +61,7 @@ enum decal_e DECAL_SMALLSCORCH2, // Small scorch mark DECAL_SMALLSCORCH3, // Small scorch mark DECAL_MOMMABIRTH, // Big momma birth splatter - DECAL_MOMMASPLAT, + DECAL_MOMMASPLAT }; typedef struct @@ -71,5 +71,4 @@ typedef struct } DLL_DECALLIST; extern DLL_DECALLIST gDecals[]; - -#endif // DECALS_H +#endif //DECALS_H diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 553e459b..75e1fb17 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -23,7 +23,6 @@ #include "cbase.h" #include "doors.h" - extern void SetMovedir(entvars_t* ev); #define noiseMoving noise1 @@ -38,7 +37,6 @@ public: 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) @@ -76,8 +74,7 @@ public: BYTE m_bUnlockedSentence; }; - -TYPEDESCRIPTION CBaseDoor::m_SaveData[] = +TYPEDESCRIPTION CBaseDoor::m_SaveData[] = { DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ), DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ), @@ -90,8 +87,7 @@ TYPEDESCRIPTION CBaseDoor::m_SaveData[] = }; -IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ); - +IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ) #define DOOR_SENTENCEWAIT 6 #define DOOR_SOUNDWAIT 3 @@ -269,12 +265,11 @@ touch or takedamage doors). 4) screechy metal */ -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); +LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ) // // func_water - same as a door. // -LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); - +LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ) void CBaseDoor::Spawn( ) { @@ -282,14 +277,16 @@ void CBaseDoor::Spawn( ) SetMovedir (pev); if ( pev->skin == 0 ) - {//normal door + { + //normal door if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) pev->solid = SOLID_NOT; else pev->solid = SOLID_BSP; } else - {// special contents + { + // special contents pev->solid = SOLID_NOT; SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now } @@ -302,11 +299,13 @@ void CBaseDoor::Spawn( ) 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 + { + // swap pos1 and pos2, put door at pos2 UTIL_SetOrigin(pev, m_vecPosition2); m_vecPosition2 = m_vecPosition1; m_vecPosition1 = pev->origin; @@ -323,7 +322,6 @@ void CBaseDoor::Spawn( ) SetTouch( &CBaseDoor::DoorTouch ); } - void CBaseDoor :: SetToggleState( int state ) { if ( state == TS_AT_TOP ) @@ -332,12 +330,11 @@ void CBaseDoor :: SetToggleState( int state ) UTIL_SetOrigin( pev, m_vecPosition1 ); } - void CBaseDoor::Precache( void ) { char *pszSound; -// set the door's "in-motion" sound + // set the door's "in-motion" sound switch (m_bMoveSnd) { case 0: @@ -388,7 +385,7 @@ void CBaseDoor::Precache( void ) break; } -// set the door's 'reached destination' stop sound + // set the door's 'reached destination' stop sound switch (m_bStopSnd) { case 0: @@ -432,7 +429,6 @@ void CBaseDoor::Precache( void ) } // get door button sounds, for doors which are directly 'touched' to open - if (m_bLockedSound) { pszSound = ButtonSound( (int)m_bLockedSound ); @@ -448,7 +444,6 @@ void CBaseDoor::Precache( void ) } // 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 @@ -512,7 +507,6 @@ void CBaseDoor::DoorTouch( CBaseEntity *pOther ) SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. } - // // Used by SUB_UseTargets, when a door is the target of a button. // @@ -533,15 +527,17 @@ int CBaseDoor::DoorActivate( ) return 0; if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - {// door should close + { + // door should close DoorGoDown(); } else - {// door should open - + { + // door should open if ( m_hActivator != NULL && m_hActivator->IsPlayer() ) - {// give health if player opened the door (medikit) - // VARS( m_eoActivator )->health += m_bHealthValue; + { + // give health if player opened the door (medikit) + //VARS( m_eoActivator )->health += m_bHealthValue; m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); @@ -592,7 +588,7 @@ void CBaseDoor::DoorGoUp( void ) angles.x = 0; angles.z = 0; UTIL_MakeVectors (angles); - // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - pev->origin; + //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 ) @@ -605,7 +601,6 @@ void CBaseDoor::DoorGoUp( void ) LinearMove(m_vecPosition2, pev->speed); } - // // The door has reached the "up" position. Either go back down, or wait for another activation. // @@ -646,7 +641,6 @@ void CBaseDoor::DoorHitTop( void ) SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished } - // // Starts the door going to its "down" position (simply ToggleData->vecPosition1). // @@ -654,8 +648,7 @@ 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); - + 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 @@ -684,7 +677,8 @@ void CBaseDoor::DoorHitBottom( void ) // Re-instate touch method, cycle is complete if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - {// use only door + { + // use only door SetTouch( NULL ); } else // touchable door @@ -700,8 +694,7 @@ void CBaseDoor::DoorHitBottom( void ) void CBaseDoor::Blocked( CBaseEntity *pOther ) { edict_t *pentTarget = NULL; - CBaseDoor *pDoor = NULL; - + CBaseDoor *pDoor = NULL; // Hurt the blocker a little. if ( pev->dmg ) @@ -770,7 +763,6 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) } } - /*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 @@ -809,6 +801,7 @@ button or trigger field activates the door. 3) stone chain 4) screechy metal */ + class CRotDoor : public CBaseDoor { public: @@ -816,8 +809,7 @@ public: virtual void SetToggleState( int state ); }; -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - +LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ) void CRotDoor::Spawn( void ) { @@ -829,7 +821,7 @@ void CRotDoor::Spawn( void ) if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) pev->movedir = pev->movedir * -1; - //m_flWait = 2; who the hell did this? (sjb) + //m_flWait = 2; who the hell did this? (sjb) m_vecAngle1 = pev->angles; m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; @@ -847,10 +839,11 @@ void CRotDoor::Spawn( void ) 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 + // 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 + { + // swap pos1 and pos2, put door at pos2, invert movement direction pev->angles = m_vecAngle2; Vector vecSav = m_vecAngle1; m_vecAngle2 = m_vecAngle1; @@ -868,7 +861,6 @@ void CRotDoor::Spawn( void ) SetTouch( &CBaseDoor::DoorTouch ); } - void CRotDoor :: SetToggleState( int state ) { if ( state == TS_AT_TOP ) @@ -879,7 +871,6 @@ void CRotDoor :: SetToggleState( int state ) UTIL_SetOrigin( pev, pev->origin ); } - class CMomentaryDoor : public CBaseToggle { public: @@ -899,7 +890,7 @@ public: BYTE m_bStopSnd; // sound a door makes when it stops }; -LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); +LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ) TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = { @@ -907,7 +898,7 @@ TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, FIELD_CHARACTER ), }; -IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ); +IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ) void CMomentaryDoor::Spawn( void ) { @@ -942,8 +933,7 @@ void CMomentaryDoor::Spawn( void ) void CMomentaryDoor::Precache( void ) { - -// set the door's "in-motion" sound + // set the door's "in-motion" sound switch (m_bMoveSnd) { case 0: @@ -986,7 +976,7 @@ void CMomentaryDoor::Precache( void ) break; } -// set the door's 'reached destination' stop sound + // set the door's 'reached destination' stop sound switch (m_bStopSnd) { case 0: @@ -1045,7 +1035,7 @@ void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) } else if (FStrEq(pkvd->szKeyName, "healthvalue")) { -// m_bHealthValue = atof(pkvd->szValue); + //m_bHealthValue = atof(pkvd->szValue); pkvd->fHandled = TRUE; } else diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 62430bcf..bd8bb160 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -27,10 +28,8 @@ #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 ); - +LINK_ENTITY_TO_CLASS( info_target, CPointEntity ) class CBubbling : public CBaseEntity { @@ -53,19 +52,18 @@ public: int m_state; }; -LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ); +LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ) -TYPEDESCRIPTION CBubbling::m_SaveData[] = +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 ), + //DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ); - +IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ) #define SF_BUBBLES_STARTOFF 0x0001 @@ -100,7 +98,6 @@ 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 ) ) @@ -118,7 +115,6 @@ void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } } - void CBubbling::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "density")) @@ -140,7 +136,6 @@ void CBubbling::KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } - void CBubbling::FizzThink( void ) { MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); @@ -162,7 +157,7 @@ void CBubbling::FizzThink( void ) // // -------------------------------------------------- -LINK_ENTITY_TO_CLASS( beam, CBeam ); +LINK_ENTITY_TO_CLASS( beam, CBeam ) void CBeam::Spawn( void ) { @@ -190,7 +185,6 @@ void CBeam::SetEndEntity( int entityIndex ) pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); } - // These don't take attachments into account const Vector &CBeam::GetStartPos( void ) { @@ -202,7 +196,6 @@ const Vector &CBeam::GetStartPos( void ) return pev->origin; } - const Vector &CBeam::GetEndPos( void ) { int type = GetType(); @@ -217,7 +210,6 @@ const Vector &CBeam::GetEndPos( void ) return pev->angles; } - CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { // Create a new entity with CBeam private data @@ -229,7 +221,6 @@ CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) return pBeam; } - void CBeam::BeamInit( const char *pSpriteName, int width ) { pev->flags |= FL_CUSTOMENTITY; @@ -246,7 +237,6 @@ void CBeam::BeamInit( const char *pSpriteName, int width ) pev->rendermode = 0; } - void CBeam::PointsInit( const Vector &start, const Vector &end ) { SetType( BEAM_POINTS ); @@ -257,7 +247,6 @@ void CBeam::PointsInit( const Vector &start, const Vector &end ) RelinkBeam(); } - void CBeam::HoseInit( const Vector &start, const Vector &direction ) { SetType( BEAM_HOSE ); @@ -268,7 +257,6 @@ void CBeam::HoseInit( const Vector &start, const Vector &direction ) RelinkBeam(); } - void CBeam::PointEntInit( const Vector &start, int endIndex ) { SetType( BEAM_ENTPOINT ); @@ -289,7 +277,6 @@ void CBeam::EntsInit( int startIndex, int endIndex ) RelinkBeam(); } - void CBeam::RelinkBeam( void ) { const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); @@ -321,7 +308,6 @@ void CBeam::SetObjectCollisionBox( void ) } #endif - void CBeam::TriggerTouch( CBaseEntity *pOther ) { if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) @@ -335,7 +321,6 @@ void CBeam::TriggerTouch( CBaseEntity *pOther ) } } - CBaseEntity *CBeam::RandomTargetname( const char *szName ) { int total = 0; @@ -351,7 +336,6 @@ CBaseEntity *CBeam::RandomTargetname( const char *szName ) return pEntity; } - void CBeam::DoSparks( const Vector &start, const Vector &end ) { if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) @@ -367,7 +351,6 @@ void CBeam::DoSparks( const Vector &start, const Vector &end ) } } - class CLightning : public CBeam { public: @@ -413,8 +396,8 @@ public: float m_radius; }; -LINK_ENTITY_TO_CLASS( env_lightning, CLightning ); -LINK_ENTITY_TO_CLASS( env_beam, CLightning ); +LINK_ENTITY_TO_CLASS( env_lightning, CLightning ) +LINK_ENTITY_TO_CLASS( env_beam, CLightning ) // UNDONE: Jay -- This is only a test #if _DEBUG @@ -422,7 +405,8 @@ class CTripBeam : public CLightning { void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); + +LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ) void CTripBeam::Spawn( void ) { @@ -433,8 +417,6 @@ void CTripBeam::Spawn( void ) } #endif - - TYPEDESCRIPTION CLightning::m_SaveData[] = { DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), @@ -452,8 +434,7 @@ TYPEDESCRIPTION CLightning::m_SaveData[] = DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CLightning, CBeam ); - +IMPLEMENT_SAVERESTORE( CLightning, CBeam ) void CLightning::Spawn( void ) { @@ -510,14 +491,12 @@ void CLightning::Precache( void ) CBeam::Precache(); } - void CLightning::Activate( void ) { if ( ServerSide() ) BeamUpdateVars(); } - void CLightning::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "LightningStart")) @@ -579,7 +558,6 @@ void CLightning::KeyValue( KeyValueData *pkvd ) CBeam::KeyValue( pkvd ); } - void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !ShouldToggle( useType, m_active ) ) @@ -603,7 +581,6 @@ void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T } } - void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !ShouldToggle( useType, m_active ) ) @@ -624,7 +601,6 @@ void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T SetUse( NULL ); } - int IsPointEntity( CBaseEntity *pEnt ) { if ( !pEnt->pev->modelindex ) @@ -635,7 +611,6 @@ int IsPointEntity( CBaseEntity *pEnt ) return 0; } - void CLightning::StrikeThink( void ) { if ( m_life != 0 ) @@ -741,7 +716,6 @@ void CLightning::StrikeThink( void ) } } - void CBeam::BeamDamage( TraceResult *ptr ) { RelinkBeam(); @@ -763,7 +737,6 @@ void CBeam::BeamDamage( TraceResult *ptr ) pev->dmgtime = gpGlobals->time; } - void CLightning::DamageThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -772,8 +745,6 @@ void CLightning::DamageThink( void ) BeamDamage( &tr ); } - - void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) { #if 1 @@ -856,7 +827,6 @@ void CLightning::RandomArea( void ) } } - void CLightning::RandomPoint( Vector &vecSrc ) { int iLoops = 0; @@ -879,8 +849,6 @@ void CLightning::RandomPoint( Vector &vecSrc ) } } - - void CLightning::BeamUpdateVars( void ) { int beamType; @@ -945,8 +913,7 @@ void CLightning::BeamUpdateVars( void ) SetFlags( BEAM_FSHADEOUT ); } - -LINK_ENTITY_TO_CLASS( env_laser, CLaser ); +LINK_ENTITY_TO_CLASS( env_laser, CLaser ) TYPEDESCRIPTION CLaser::m_SaveData[] = { @@ -955,7 +922,7 @@ TYPEDESCRIPTION CLaser::m_SaveData[] = DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ), }; -IMPLEMENT_SAVERESTORE( CLaser, CBeam ); +IMPLEMENT_SAVERESTORE( CLaser, CBeam ) void CLaser::Spawn( void ) { @@ -993,7 +960,6 @@ void CLaser::Precache( void ) PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); } - void CLaser::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "LaserTarget")) @@ -1040,7 +1006,6 @@ void CLaser::KeyValue( KeyValueData *pkvd ) CBeam::KeyValue( pkvd ); } - int CLaser::IsOn( void ) { if (pev->effects & EF_NODRAW) @@ -1048,7 +1013,6 @@ int CLaser::IsOn( void ) return 1; } - void CLaser::TurnOff( void ) { pev->effects |= EF_NODRAW; @@ -1057,7 +1021,6 @@ void CLaser::TurnOff( void ) m_pSprite->TurnOff(); } - void CLaser::TurnOn( void ) { pev->effects &= ~EF_NODRAW; @@ -1067,7 +1030,6 @@ void CLaser::TurnOn( void ) pev->nextthink = gpGlobals->time; } - void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int active = IsOn(); @@ -1084,7 +1046,6 @@ void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp } } - void CLaser::FireAtPoint( TraceResult &tr ) { SetEndPos( tr.vecEndPos ); @@ -1109,8 +1070,6 @@ void CLaser::StrikeThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - - class CGlow : public CPointEntity { public: @@ -1125,7 +1084,7 @@ public: float m_maxFrame; }; -LINK_ENTITY_TO_CLASS( env_glow, CGlow ); +LINK_ENTITY_TO_CLASS( env_glow, CGlow ) TYPEDESCRIPTION CGlow::m_SaveData[] = { @@ -1133,7 +1092,7 @@ TYPEDESCRIPTION CGlow::m_SaveData[] = DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ); +IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ) void CGlow::Spawn( void ) { @@ -1152,7 +1111,6 @@ void CGlow::Spawn( void ) m_lastTime = gpGlobals->time; } - void CGlow::Think( void ) { Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); @@ -1161,15 +1119,13 @@ void CGlow::Think( void ) 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 ); +LINK_ENTITY_TO_CLASS( env_sprite, CSprite ) TYPEDESCRIPTION CSprite::m_SaveData[] = { @@ -1177,7 +1133,7 @@ TYPEDESCRIPTION CSprite::m_SaveData[] = DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ); +IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ) void CSprite::Spawn( void ) { @@ -1203,7 +1159,6 @@ void CSprite::Spawn( void ) } } - void CSprite::Precache( void ) { PRECACHE_MODEL( (char *)STRING(pev->model) ); @@ -1219,7 +1174,6 @@ void CSprite::Precache( void ) } } - void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) { pev->model = MAKE_STRING(pSpriteName); @@ -1240,7 +1194,6 @@ CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, B return pSprite; } - void CSprite::AnimateThink( void ) { Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); @@ -1270,7 +1223,6 @@ void CSprite::Expand( float scaleSpeed, float fadeSpeed ) m_lastTime = gpGlobals->time; } - void CSprite::ExpandThink( void ) { float frametime = gpGlobals->time - m_lastTime; @@ -1288,7 +1240,6 @@ void CSprite::ExpandThink( void ) } } - void CSprite::Animate( float frames ) { pev->frame += frames; @@ -1306,14 +1257,12 @@ void CSprite::Animate( float frames ) } } - void CSprite::TurnOff( void ) { pev->effects = EF_NODRAW; pev->nextthink = 0; } - void CSprite::TurnOn( void ) { pev->effects = 0; @@ -1326,7 +1275,6 @@ void CSprite::TurnOn( void ) pev->frame = 0; } - void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int on = pev->effects != EF_NODRAW; @@ -1343,7 +1291,6 @@ void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy } } - class CGibShooter : public CBaseDelay { public: @@ -1379,9 +1326,8 @@ TYPEDESCRIPTION CGibShooter::m_SaveData[] = DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ); -LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ); - +IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ) +LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ) void CGibShooter :: Precache ( void ) { @@ -1395,7 +1341,6 @@ void CGibShooter :: Precache ( void ) } } - void CGibShooter::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "m_iGibs")) @@ -1451,7 +1396,6 @@ void CGibShooter::Spawn( void ) pev->body = MODEL_FRAMES( m_iGibModelIndex ); } - CGib *CGibShooter :: CreateGib ( void ) { if ( CVAR_GET_FLOAT("violence_hgibs") == 0 ) @@ -1471,7 +1415,6 @@ CGib *CGibShooter :: CreateGib ( void ) return pGib; } - void CGibShooter :: ShootThink ( void ) { pev->nextthink = gpGlobals->time + m_flDelay; @@ -1522,7 +1465,6 @@ void CGibShooter :: ShootThink ( void ) } } - class CEnvShooter : public CGibShooter { void Precache( void ); @@ -1531,7 +1473,7 @@ class CEnvShooter : public CGibShooter CGib *CreateGib( void ); }; -LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); +LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ) void CEnvShooter :: KeyValue( KeyValueData *pkvd ) { @@ -1574,14 +1516,12 @@ void CEnvShooter :: KeyValue( KeyValueData *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 ); @@ -1607,9 +1547,6 @@ CGib *CEnvShooter :: CreateGib ( void ) return pGib; } - - - class CTestEffect : public CBaseDelay { public: @@ -1626,8 +1563,7 @@ public: float m_flStartTime; }; - -LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ); +LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ) void CTestEffect::Spawn( void ) { @@ -1664,7 +1600,6 @@ void CTestEffect::TestThink( void ) 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 ); @@ -1705,7 +1640,6 @@ void CTestEffect::TestThink( void ) } } - void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { SetThink( &CTestEffect::TestThink ); @@ -1713,8 +1647,6 @@ void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u m_flStartTime = gpGlobals->time; } - - // Blood effects class CBlood : public CPointEntity { @@ -1735,9 +1667,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( env_blood, CBlood ); - - +LINK_ENTITY_TO_CLASS( env_blood, CBlood ) #define SF_BLOOD_RANDOM 0x0001 #define SF_BLOOD_STREAM 0x0002 @@ -1753,7 +1683,6 @@ void CBlood::Spawn( void ) SetMovedir( pev ); } - void CBlood::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "color")) @@ -1780,7 +1709,6 @@ void CBlood::KeyValue( KeyValueData *pkvd ) CPointEntity::KeyValue( pkvd ); } - Vector CBlood::Direction( void ) { if ( pev->spawnflags & SF_BLOOD_RANDOM ) @@ -1789,7 +1717,6 @@ Vector CBlood::Direction( void ) return pev->movedir; } - Vector CBlood::BloodPosition( CBaseEntity *pActivator ) { if ( pev->spawnflags & SF_BLOOD_PLAYER ) @@ -1809,7 +1736,6 @@ Vector CBlood::BloodPosition( CBaseEntity *pActivator ) return pev->origin; } - void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( pev->spawnflags & SF_BLOOD_STREAM ) @@ -1829,8 +1755,6 @@ void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp } } - - // Screen shake class CShake : public CPointEntity { @@ -1851,7 +1775,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( env_shake, CShake ); +LINK_ENTITY_TO_CLASS( env_shake, CShake ) // pev->scale is amplitude // pev->dmg_save is frequency @@ -1876,7 +1800,6 @@ void CShake::Spawn( void ) pev->dmg = 0; } - void CShake::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "amplitude")) @@ -1903,7 +1826,6 @@ void CShake::KeyValue( KeyValueData *pkvd ) CPointEntity::KeyValue( pkvd ); } - void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); @@ -1925,7 +1847,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( env_fade, CFade ); +LINK_ENTITY_TO_CLASS( env_fade, CFade ) // pev->dmg_take is duration // pev->dmg_save is hold duration @@ -1941,7 +1863,6 @@ void CFade::Spawn( void ) pev->frame = 0; } - void CFade::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "duration")) @@ -1958,7 +1879,6 @@ void CFade::KeyValue( KeyValueData *pkvd ) CPointEntity::KeyValue( pkvd ); } - void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int fadeFlags = 0; @@ -1983,7 +1903,6 @@ void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType SUB_UseTargets( this, USE_TOGGLE, 0 ); } - class CMessage : public CPointEntity { public: @@ -1994,8 +1913,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( env_message, CMessage ); - +LINK_ENTITY_TO_CLASS( env_message, CMessage ) void CMessage::Spawn( void ) { @@ -2030,7 +1948,6 @@ void CMessage::Spawn( void ) pev->scale = 1.0; } - void CMessage::Precache( void ) { if ( pev->noise ) @@ -2058,7 +1975,6 @@ void CMessage::KeyValue( KeyValueData *pkvd ) CPointEntity::KeyValue( pkvd ); } - void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CBaseEntity *pPlayer = NULL; @@ -2086,8 +2002,6 @@ void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT SUB_UseTargets( this, USE_TOGGLE, 0 ); } - - //========================================================= // FunnelEffect //========================================================= @@ -2106,7 +2020,7 @@ void CEnvFunnel :: Precache ( void ) m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); } -LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ); +LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ) void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -2126,7 +2040,6 @@ void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us WRITE_SHORT( 0 ); } - MESSAGE_END(); SetThink( &CBaseEntity::SUB_Remove ); @@ -2159,7 +2072,7 @@ void CEnvBeverage :: Precache ( void ) PRECACHE_SOUND( "weapons/g_bounce3.wav" ); } -LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ); +LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ) void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -2217,7 +2130,7 @@ void CItemSoda :: Precache ( void ) { } -LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); +LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ) void CItemSoda::Spawn( void ) { @@ -2250,7 +2163,6 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) } // spoit sound here - pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. if ( !FNullEnt( pev->owner ) ) diff --git a/dlls/egon.cpp b/dlls/egon.cpp index b5333cd7..b624cea8 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -49,7 +49,7 @@ enum egon_e { EGON_HOLSTER }; -LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); +LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ) void CEgon::Spawn( ) { @@ -62,7 +62,6 @@ void CEgon::Spawn( ) FallInit();// get ready to fall down. } - void CEgon::Precache( void ) { PRECACHE_MODEL("models/w_egon.mdl"); @@ -277,10 +276,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) m_pSprite->pev->effects |= EF_NODRAW; } } - - #endif - float timedist; switch ( m_fireMode ) @@ -408,14 +404,11 @@ void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, floa m_pSprite->pev->frame = 0; m_pNoise->SetStartPos( endPoint ); - #endif - } void CEgon::CreateEffect( void ) { - #ifndef CLIENT_DLL DestroyEffect(); @@ -458,10 +451,8 @@ void CEgon::CreateEffect( void ) m_pNoise->SetNoise( 2 ); } #endif - } - void CEgon::DestroyEffect( void ) { @@ -485,11 +476,8 @@ void CEgon::DestroyEffect( void ) m_pSprite = NULL; } #endif - } - - void CEgon::WeaponIdle( void ) { ResetEmptySound( ); @@ -563,6 +551,6 @@ class CEgonAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); +LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ) -#endif \ No newline at end of file +#endif diff --git a/dlls/explode.cpp b/dlls/explode.cpp index 4e5f1c15..6d40960b 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -34,7 +34,7 @@ class CShower : public CBaseEntity int ObjectCaps( void ) { return FCAP_DONT_SAVE; } }; -LINK_ENTITY_TO_CLASS( spark_shower, CShower ); +LINK_ENTITY_TO_CLASS( spark_shower, CShower ) void CShower::Spawn( void ) { @@ -57,7 +57,6 @@ void CShower::Spawn( void ) pev->angles = g_vecZero; } - void CShower::Think( void ) { UTIL_Sparks( pev->origin ); @@ -103,8 +102,8 @@ TYPEDESCRIPTION CEnvExplosion::m_SaveData[] = DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster ); -LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ); +IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster ) +LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ) void CEnvExplosion::KeyValue( KeyValueData *pkvd ) { @@ -253,7 +252,6 @@ void CEnvExplosion::Smoke( void ) } } - // 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 ) { diff --git a/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp index 0b361ba6..bc037e1b 100644 --- a/dlls/flyingmonster.cpp +++ b/dlls/flyingmonster.cpp @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -22,7 +23,6 @@ #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 ) @@ -57,13 +57,11 @@ int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vec 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 @@ -72,7 +70,6 @@ Activity CFlyingMonster :: GetStoppedActivity( void ) return ACT_HOVER; } - void CFlyingMonster :: Stop( void ) { Activity stopped = GetStoppedActivity(); @@ -86,7 +83,6 @@ void CFlyingMonster :: Stop( void ) m_vecTravel = g_vecZero; } - float CFlyingMonster :: ChangeYaw( int speed ) { if ( pev->movetype == MOVETYPE_FLY ) @@ -106,7 +102,6 @@ float CFlyingMonster :: ChangeYaw( int speed ) return CBaseMonster::ChangeYaw( speed ); } - void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) { pev->movetype = MOVETYPE_STEP; @@ -116,7 +111,6 @@ void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) CBaseMonster::Killed( pevAttacker, iGib ); } - void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) @@ -124,19 +118,16 @@ void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ) @@ -144,7 +135,6 @@ void CFlyingMonster :: Move( float flInterval ) CBaseMonster::Move( flInterval ); } - BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) { // Get true 3D distance to the goal so we actually reach the correct height @@ -157,7 +147,6 @@ BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) return FALSE; } - void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { if ( pev->movetype == MOVETYPE_FLY ) @@ -180,7 +169,7 @@ void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, } else m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime ); - + if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) ) { m_vecTravel = (vecMove - pev->origin); @@ -198,7 +187,6 @@ void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval ); } - float CFlyingMonster::CeilingZ( const Vector &position ) { TraceResult tr; @@ -278,4 +266,3 @@ float CFlyingMonster::FloorZ( const Vector &position ) return down.z; } - diff --git a/dlls/flyingmonster.h b/dlls/flyingmonster.h index 616194db..17d4e90a 100644 --- a/dlls/flyingmonster.h +++ b/dlls/flyingmonster.h @@ -37,8 +37,7 @@ public: 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 @@ -47,7 +46,4 @@ protected: float m_momentum; // Weight for desired vs. momentum velocity const char *m_pFlapSound; }; - - -#endif //FLYINGMONSTER_H - +#endif //FLYINGMONSTER_H diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 0a107b43..7c9705e6 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -93,7 +93,7 @@ void CBreakable::KeyValue( KeyValueData* pkvd ) } else if (FStrEq(pkvd->szKeyName, "shards")) { -// m_iShards = atof(pkvd->szValue); + //m_iShards = atof(pkvd->szValue); pkvd->fHandled = TRUE; } else if (FStrEq(pkvd->szKeyName, "gibmodel") ) @@ -123,7 +123,8 @@ void CBreakable::KeyValue( KeyValueData* pkvd ) // // func_breakable - bmodel that breaks into pieces after taking damage // -LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ); +LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ) + TYPEDESCRIPTION CBreakable::m_SaveData[] = { DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ), @@ -139,7 +140,7 @@ TYPEDESCRIPTION CBreakable::m_SaveData[] = // Explosion magnitude is stored in pev->impulse }; -IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ) void CBreakable::Spawn( void ) { @@ -151,8 +152,8 @@ void CBreakable::Spawn( void ) pev->takedamage = DAMAGE_YES; pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - m_angle = pev->angles.y; + 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 @@ -173,7 +174,6 @@ void CBreakable::Spawn( void ) pev->flags |= FL_WORLDBRUSH; } - const char *CBreakable::pSoundsWood[] = { "debris/wood1.wav", @@ -205,7 +205,6 @@ const char *CBreakable::pSoundsConcrete[] = "debris/concrete3.wav", }; - const char *CBreakable::pSoundsGlass[] = { "debris/glass1.wav", @@ -217,7 +216,7 @@ const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &sou { const char **pSoundList = NULL; - switch ( precacheMaterial ) + switch ( precacheMaterial ) { case matWood: pSoundList = pSoundsWood; @@ -280,12 +279,11 @@ void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, 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) + switch (m_Material) { case matWood: pGibName = "models/woodgibs.mdl"; @@ -390,21 +388,18 @@ void CBreakable::DamageSound( void ) 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"; @@ -414,7 +409,6 @@ void CBreakable::DamageSound( void ) rgpsz[5] = "debris/flesh7.wav"; i = 6; break; - case matRocks: case matCinderBlock: rgpsz[0] = "debris/concrete1.wav"; @@ -422,7 +416,6 @@ void CBreakable::DamageSound( void ) rgpsz[2] = "debris/concrete3.wav"; i = 3; break; - case matCeilingTile: // UNDONE: no ceiling tile shard sound yet i = 0; @@ -445,7 +438,8 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) } if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) - {// can be broken when run into + { + // can be broken when run into flDamage = pevToucher->velocity.Length() * 0.01; if (flDamage >= pev->health) @@ -459,26 +453,24 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) } if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) - {// can be broken when stood upon - + { + // 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? + { + // !!!BUGBUG - why doesn't zero delay work? m_flDelay = 0.1; } pev->nextthink = pev->ltime + m_flDelay; - } - } - // // Smash the our breakable object // @@ -515,8 +507,7 @@ void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; } } - break; - + break; case matUnbreakableGlass: UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); break; @@ -565,10 +556,10 @@ int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f if ( bitsDamageType & DMG_POISON ) flDamage *= 0.1; -// this global is still used for glass and other non-monster killables, along with decals. + // this global is still used for glass and other non-monster killables, along with decals. g_vecAttackDir = vecTemp.Normalize(); - -// do the damage + + // do the damage pev->health -= flDamage; if (pev->health <= 0) { @@ -579,7 +570,6 @@ int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f // Make a shard noise each time func breakable is hit. // Don't play shard noise if cbreakable actually died. - DamageSound(); return 1; @@ -608,7 +598,6 @@ void CBreakable::Die( void ) if (fvol > 1.0) fvol = 1.0; - switch (m_Material) { case matGlass: @@ -621,7 +610,6 @@ void CBreakable::Die( void ) } cFlag = BREAK_GLASS; break; - case matWood: switch ( RANDOM_LONG(0,1) ) { @@ -632,7 +620,6 @@ void CBreakable::Die( void ) } cFlag = BREAK_WOOD; break; - case matComputer: case matMetal: switch ( RANDOM_LONG(0,1) ) @@ -644,7 +631,6 @@ void CBreakable::Die( void ) } cFlag = BREAK_METAL; break; - case matFlesh: switch ( RANDOM_LONG(0,1) ) { @@ -655,7 +641,6 @@ void CBreakable::Die( void ) } cFlag = BREAK_FLESH; break; - case matRocks: case matCinderBlock: switch ( RANDOM_LONG(0,1) ) @@ -667,7 +652,6 @@ void CBreakable::Die( void ) } cFlag = BREAK_CONCRETE; break; - case matCeilingTile: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); break; @@ -678,8 +662,7 @@ void CBreakable::Die( void ) default: break; } - - + if (m_Explosion == expDirected) vecVelocity = g_vecAttackDir * 200; else @@ -753,6 +736,7 @@ void CBreakable::Die( void ) pev->targetname = 0; pev->solid = SOLID_NOT; + // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); @@ -761,22 +745,18 @@ void CBreakable::Die( void ) 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 ) +int CBreakable :: DamageDecal( int bitsDamageType ) { if ( m_Material == matGlass ) return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); @@ -787,7 +767,6 @@ int CBreakable :: DamageDecal( int bitsDamageType ) return CBaseEntity::DamageDecal( bitsDamageType ); } - class CPushable : public CBreakable { public: @@ -798,17 +777,17 @@ public: 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 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 char *m_soundNames[3]; @@ -817,19 +796,18 @@ public: float m_soundTime; }; -TYPEDESCRIPTION CPushable::m_SaveData[] = +TYPEDESCRIPTION CPushable::m_SaveData[] = { DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ), DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CPushable, CBreakable ); +IMPLEMENT_SAVERESTORE( CPushable, CBreakable ) -LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); +LINK_ENTITY_TO_CLASS( func_pushable, CPushable ) char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; - void CPushable :: Spawn( void ) { if ( pev->spawnflags & SF_PUSH_BREAKABLE ) @@ -856,7 +834,6 @@ void CPushable :: Spawn( void ) m_soundTime = 0; } - void CPushable :: Precache( void ) { for ( int i = 0; i < 3; i++ ) @@ -866,7 +843,6 @@ void CPushable :: Precache( void ) CBreakable::Precache( ); } - void CPushable :: KeyValue( KeyValueData *pkvd ) { if ( FStrEq(pkvd->szKeyName, "size") ) @@ -879,21 +855,17 @@ void CPushable :: KeyValue( KeyValueData *pkvd ) 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") ) { @@ -904,7 +876,6 @@ void CPushable :: KeyValue( KeyValueData *pkvd ) CBreakable::KeyValue( pkvd ); } - // Pull the func_pushable void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -919,7 +890,6 @@ void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u Move( pActivator, 0 ); } - void CPushable :: Touch( CBaseEntity *pOther ) { if ( FClassnameIs( pOther->pev, "worldspawn" ) ) @@ -928,7 +898,6 @@ void CPushable :: Touch( CBaseEntity *pOther ) Move( pOther, 1 ); } - void CPushable :: Move( CBaseEntity *pOther, int push ) { entvars_t* pevToucher = pOther->pev; @@ -990,8 +959,8 @@ void CPushable :: Move( CBaseEntity *pOther, int push ) { 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; + //SetThink( &StopSound ); + //pev->nextthink = pev->ltime + 0.1; } else STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); @@ -1015,4 +984,3 @@ int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return 1; } - diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 2997e943..81b20986 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -21,7 +22,6 @@ #include "player.h" - #define SF_TANK_ACTIVE 0x0001 #define SF_TANK_PLAYER 0x0002 #define SF_TANK_HUMANS 0x0004 @@ -35,7 +35,7 @@ enum TANKBULLET TANK_BULLET_NONE = 0, TANK_BULLET_9MM = 1, TANK_BULLET_MP5 = 2, - TANK_BULLET_12MM = 3, + TANK_BULLET_12MM = 3 }; // Custom damage @@ -94,7 +94,6 @@ public: void StopControl( void ); void ControllerPostFrame( void ); - protected: CBasePlayer* m_pController; float m_flNextAttack; @@ -130,7 +129,6 @@ protected: int m_iszMaster; // Master entity (game_team_master or multisource) }; - TYPEDESCRIPTION CFuncTank::m_SaveData[] = { DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), @@ -161,7 +159,7 @@ TYPEDESCRIPTION CFuncTank::m_SaveData[] = DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ) static Vector gTankSpread[] = { @@ -171,8 +169,8 @@ static Vector gTankSpread[] = 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) +#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) void CFuncTank :: Spawn( void ) { @@ -198,7 +196,6 @@ void CFuncTank :: Spawn( void ) pev->oldorigin = pev->origin; } - void CFuncTank :: Precache( void ) { if ( m_iszSpriteSmoke ) @@ -210,7 +207,6 @@ void CFuncTank :: Precache( void ) PRECACHE_SOUND( (char *)STRING(pev->noise) ); } - void CFuncTank :: KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "yawrate")) @@ -416,7 +412,6 @@ void CFuncTank :: ControllerPostFrame( void ) } ////////////// END NEW STUFF ////////////// - void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( pev->spawnflags & SF_TANK_CANCONTROL ) @@ -451,14 +446,11 @@ void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u } } - edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) { return pPlayer; } - - BOOL CFuncTank :: InRange( float range ) { if ( range < m_minRange ) @@ -469,7 +461,6 @@ BOOL CFuncTank :: InRange( float range ) return TRUE; } - void CFuncTank :: Think( void ) { pev->avelocity = g_vecZero; @@ -539,10 +530,9 @@ void CFuncTank::TrackTarget( void ) } // Track sight origin - -// !!! I'm not sure what i changed + // !!! I'm not sure what i changed direction = m_sightOrigin - pev->origin; -// direction = m_sightOrigin - barrelEnd; + //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) @@ -623,7 +613,6 @@ void CFuncTank::TrackTarget( void ) m_fireLast = 0; } - // If barrel is offset, add in additional rotation void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) { @@ -647,7 +636,6 @@ void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) } } - // Fire targets and spawn sprites void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { @@ -676,7 +664,6 @@ void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t m_fireLast = gpGlobals->time; } - void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) { // get circular gaussian spread @@ -694,7 +681,6 @@ void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, con vecEnd = vecStart + vecDir * 4096; UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); } - void CFuncTank::StartRotSound( void ) { @@ -704,7 +690,6 @@ void CFuncTank::StartRotSound( void ) EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); } - void CFuncTank::StopRotSound( void ) { if ( pev->spawnflags & SF_TANK_SOUNDON ) @@ -717,7 +702,8 @@ class CFuncTankGun : public CFuncTank public: void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); }; -LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); + +LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ) void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { @@ -759,8 +745,6 @@ void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars CFuncTank::Fire( barrelEnd, forward, pevAttacker ); } - - class CFuncTankLaser : public CFuncTank { public: @@ -778,7 +762,8 @@ private: CLaser *m_pLaser; float m_laserTime; }; -LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); + +LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ) TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = { @@ -786,7 +771,7 @@ TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); +IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ) void CFuncTankLaser::Activate( void ) { @@ -801,7 +786,6 @@ void CFuncTankLaser::Activate( void ) } } - void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "laserentity")) @@ -813,7 +797,6 @@ void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) CFuncTank::KeyValue( pkvd ); } - CLaser *CFuncTankLaser::GetLaser( void ) { if ( m_pLaser ) @@ -837,7 +820,6 @@ CLaser *CFuncTankLaser::GetLaser( void ) return m_pLaser; } - void CFuncTankLaser::Think( void ) { if ( m_pLaser && (gpGlobals->time > m_laserTime) ) @@ -846,7 +828,6 @@ void CFuncTankLaser::Think( void ) CFuncTank::Think(); } - void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { int i; @@ -886,7 +867,8 @@ public: void Precache( void ); void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); }; -LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); + +LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ) void CFuncTankRocket::Precache( void ) { @@ -894,8 +876,6 @@ void CFuncTankRocket::Precache( void ) CFuncTank::Precache(); } - - void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { int i; @@ -916,15 +896,14 @@ void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entv 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 ); +LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) { @@ -937,7 +916,6 @@ void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) CFuncTank::KeyValue( pkvd ); } - void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { if ( m_fireLast != 0 ) @@ -962,8 +940,6 @@ void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entv CFuncTank::Fire( barrelEnd, forward, pev ); } - - //============================================================================ // FUNC TANK CONTROLS //============================================================================ @@ -981,30 +957,30 @@ public: CFuncTank *m_pTank; }; -LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); + +LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ) TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = { DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), }; -IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); +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 +{ + // 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; diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 76b35155..5dc5cb3e 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -43,7 +43,7 @@ enum GR_PLR_DROP_AMMO_ALL, GR_PLR_DROP_AMMO_ACTIVE, - GR_PLR_DROP_AMMO_NO, + GR_PLR_DROP_AMMO_NO }; // Player relationship return codes @@ -53,7 +53,7 @@ enum GR_TEAMMATE, GR_ENEMY, GR_ALLY, - GR_NEUTRAL, + GR_NEUTRAL }; class CGameRules @@ -67,25 +67,25 @@ public: 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 + // 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 + // 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 + // 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 + // 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? @@ -96,50 +96,51 @@ public: 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 + // 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 + + // 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 + // 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 + // 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 + // 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 + // 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 + // 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 + // by default, everything spawns -// Healthcharger respawn control + // 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 + // 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 + // 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 + // 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; } @@ -148,11 +149,11 @@ public: virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } -// Sounds + // Sounds virtual BOOL PlayTextureSounds( void ) { return TRUE; } virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } -// Monsters + // Monsters virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed // Immediately end a multiplayer game @@ -171,7 +172,7 @@ class CHalfLifeRules : public CGameRules public: CHalfLifeRules ( void ); -// GR_Think + // GR_Think virtual void Think( void ); virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); virtual BOOL FAllowFlashlight( void ) { return TRUE; }; @@ -179,20 +180,20 @@ public: virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); -// Functions to verify the single/multiplayer status of a game + // 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 + // 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 + // Client damage rules virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); -// Client spawn/respawn control + // Client spawn/respawn control virtual void PlayerSpawn( CBasePlayer *pPlayer ); virtual void PlayerThink( CBasePlayer *pPlayer ); virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); @@ -200,50 +201,50 @@ public: virtual BOOL AllowAutoTargetCrosshair( void ); -// Client kills/scoring + // 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 + // Weapon retrieval virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); -// Weapon spawn/respawn control + // 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 + // Item retrieval virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); -// Item spawn/respawn control + // Item spawn/respawn control virtual int ItemShouldRespawn( CItem *pItem ); virtual float FlItemRespawnTime( CItem *pItem ); virtual Vector VecItemRespawnSpot( CItem *pItem ); -// Ammo retrieval + // Ammo retrieval virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); -// Ammo spawn/respawn control + // Ammo spawn/respawn control virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); -// Healthcharger respawn control + // Healthcharger respawn control virtual float FlHealthChargerRechargeTime( void ); -// What happens to a dead player's weapons + // What happens to a dead player's weapons virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); -// What happens to a dead player's ammo + // What happens to a dead player's ammo virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); -// Monsters + // Monsters virtual BOOL FAllowMonsters( void ); -// Teamplay stuff + // Teamplay stuff virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); }; @@ -257,7 +258,7 @@ class CHalfLifeMultiplay : public CGameRules public: CHalfLifeMultiplay(); -// GR_Think + // GR_Think virtual void Think( void ); virtual void RefreshSkillData( void ); virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); @@ -266,12 +267,12 @@ public: virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); -// Functions to verify the single/multiplayer status of a game + // 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 + // 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. @@ -280,11 +281,11 @@ public: 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 + // Client damage rules virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); -// Client spawn/respawn control + // Client spawn/respawn control virtual void PlayerSpawn( CBasePlayer *pPlayer ); virtual void PlayerThink( CBasePlayer *pPlayer ); virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); @@ -294,56 +295,56 @@ public: virtual BOOL AllowAutoTargetCrosshair( void ); virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); -// Client kills/scoring + // 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 + // 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 + // 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 + // Item retrieval virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); -// Item spawn/respawn control + // Item spawn/respawn control virtual int ItemShouldRespawn( CItem *pItem ); virtual float FlItemRespawnTime( CItem *pItem ); virtual Vector VecItemRespawnSpot( CItem *pItem ); -// Ammo retrieval + // Ammo retrieval virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); -// Ammo spawn/respawn control + // Ammo spawn/respawn control virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); -// Healthcharger respawn control + // Healthcharger respawn control virtual float FlHealthChargerRechargeTime( void ); virtual float FlHEVChargerRechargeTime( void ); -// What happens to a dead player's weapons + // What happens to a dead player's weapons virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); -// What happens to a dead player's ammo + // What happens to a dead player's ammo virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); -// Teamplay stuff + // 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 + // Monsters virtual BOOL FAllowMonsters( void ); // Immediately end a multiplayer game diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index c54779c8..6c48a666 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -73,8 +73,8 @@ public: 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 ); +LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ) class CStomp : public CBaseEntity { @@ -88,7 +88,8 @@ private: // CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; }; -LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ); +LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ) + CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) { CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); @@ -116,7 +117,6 @@ void CStomp::Spawn( void ) 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 ) @@ -166,6 +166,7 @@ void CStomp::Think( void ) } } pev->dmgtime += STOMP_INTERVAL; + // Scale has the "life" of this effect pev->scale -= STOMP_INTERVAL * pev->speed; if ( pev->scale <= 0 ) @@ -174,7 +175,6 @@ void CStomp::Think( void ) UTIL_Remove(this); STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); } - } } @@ -196,7 +196,6 @@ void StreakSplash( const Vector &origin, const Vector &direction, int color, int MESSAGE_END(); } - class CGargantua : public CBaseMonster { public: @@ -272,7 +271,7 @@ private: float m_flameY; }; -LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ); +LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ) TYPEDESCRIPTION CGargantua::m_SaveData[] = { @@ -287,7 +286,7 @@ TYPEDESCRIPTION CGargantua::m_SaveData[] = DEFINE_FIELD( CGargantua, m_flameY, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ) const char *CGargantua::pAttackHitSounds[] = { @@ -303,7 +302,6 @@ const char *CGargantua::pBeamAttackSounds[] = "garg/gar_flamerun1.wav", }; - const char *CGargantua::pAttackMissSounds[] = { "zombie/claw_miss1.wav", @@ -332,7 +330,6 @@ const char *CGargantua::pFootSounds[] = "garg/gar_step2.wav", }; - const char *CGargantua::pIdleSounds[] = { "garg/gar_idle1.wav", @@ -342,7 +339,6 @@ const char *CGargantua::pIdleSounds[] = "garg/gar_idle5.wav", }; - const char *CGargantua::pAttackSounds[] = { "garg/gar_attack1.wav", @@ -381,14 +377,14 @@ const char *CGargantua::pBreatheSounds[] = #if 0 enum { - SCHED_ = LAST_COMMON_SCHEDULE + 1, + SCHED_ = LAST_COMMON_SCHEDULE + 1 }; #endif enum { TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1, - TASK_FLAME_SWEEP, + TASK_FLAME_SWEEP }; Task_t tlGargFlame[] = @@ -413,7 +409,6 @@ Schedule_t slGargFlame[] = }, }; - // primary melee attack Task_t tlGargSwipe[] = { @@ -433,28 +428,24 @@ Schedule_t slGargSwipe[] = }, }; - DEFINE_CUSTOM_SCHEDULES( CGargantua ) { slGargFlame, slGargSwipe, }; -IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ); - +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 ) @@ -468,7 +459,6 @@ void CGargantua::EyeUpdate( void ) } } - void CGargantua::StompAttack( void ) { TraceResult trace; @@ -488,7 +478,6 @@ void CGargantua::StompAttack( void ) UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); } - void CGargantua :: FlameCreate( void ) { int i; @@ -529,7 +518,6 @@ void CGargantua :: FlameCreate( void ) 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 ) @@ -548,7 +536,6 @@ void CGargantua :: FlameControls( float angleX, float angleY ) SetBoneController( 1, m_flameX ); } - void CGargantua :: FlameUpdate( void ) { int i; @@ -581,6 +568,7 @@ void CGargantua :: FlameUpdate( void ) 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 ); @@ -603,8 +591,6 @@ void CGargantua :: FlameUpdate( void ) 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; @@ -642,7 +628,8 @@ void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevIn 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! + { + // 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(); @@ -673,7 +660,6 @@ void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevIn } } - void CGargantua :: FlameDestroy( void ) { int i; @@ -689,7 +675,6 @@ void CGargantua :: FlameDestroy( void ) } } - void CGargantua :: PrescheduleThink( void ) { if ( !HasConditions( bits_COND_SEE_ENEMY ) ) @@ -703,7 +688,6 @@ void CGargantua :: PrescheduleThink( void ) EyeUpdate(); } - //========================================================= // Classify - indicates this monster's place in the // relationship table. @@ -734,7 +718,6 @@ void CGargantua :: SetYawSpeed ( void ) case ACT_RUN: ys = 60; break; - default: ys = 60; break; @@ -743,7 +726,6 @@ void CGargantua :: SetYawSpeed ( void ) pev->yaw_speed = ys; } - //========================================================= // Spawn //========================================================= @@ -772,7 +754,6 @@ void CGargantua :: Spawn() m_flameTime = gpGlobals->time + 2; } - //========================================================= // Precache - precaches all resources this monster needs //========================================================= @@ -822,7 +803,6 @@ void CGargantua :: Precache() 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"); @@ -858,11 +838,8 @@ void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec } 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"); @@ -878,7 +855,6 @@ int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } - void CGargantua::DeathEffect( void ) { int i; @@ -903,7 +879,6 @@ void CGargantua::DeathEffect( void ) pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds } - void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) { EyeOff(); @@ -929,7 +904,6 @@ BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) return FALSE; } - // Flame thrower madness! BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) { @@ -946,7 +920,6 @@ BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) return FALSE; } - //========================================================= // CheckRangeAttack1 // flDot is the cos of the angle of the cone within which @@ -968,9 +941,6 @@ BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) return FALSE; } - - - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -1024,7 +994,6 @@ void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) } } - //========================================================= // CheckTraceHullAttack - expects a length to trace, amount // of damage to do, and damage type. Returns a pointer to @@ -1062,7 +1031,6 @@ CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage return NULL; } - Schedule_t *CGargantua::GetScheduleOfType( int Type ) { // HACKHACK - turn off the flames if they are on and garg goes scripted / dead @@ -1081,7 +1049,6 @@ Schedule_t *CGargantua::GetScheduleOfType( int Type ) return CBaseMonster::GetScheduleOfType( Type ); } - void CGargantua::StartTask( Task_t *pTask ) { switch ( pTask->iTask ) @@ -1187,7 +1154,6 @@ void CGargantua::RunTask( Task_t *pTask ) else CBaseMonster::RunTask(pTask); break; - case TASK_FLAME_SWEEP: if ( gpGlobals->time > m_flWaitFinished ) { @@ -1228,14 +1194,12 @@ void CGargantua::RunTask( Task_t *pTask ) FlameControls( angles.x, angles.y ); } break; - default: CBaseMonster::RunTask( pTask ); break; } } - class CSmoker : public CBaseEntity { public: @@ -1243,7 +1207,7 @@ public: void Think( void ); }; -LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ); +LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ) void CSmoker::Spawn( void ) { @@ -1255,7 +1219,6 @@ void CSmoker::Spawn( void ) pev->angles = g_vecZero; } - void CSmoker::Think( void ) { // lots of smoke @@ -1276,7 +1239,6 @@ void CSmoker::Think( void ) UTIL_Remove( this ); } - void CSpiral::Spawn( void ) { pev->movetype = MOVETYPE_NONE; @@ -1287,7 +1249,6 @@ void CSpiral::Spawn( void ) pev->angles = g_vecZero; } - CSpiral *CSpiral::Create( const Vector &origin, float height, float radius, float duration ) { if ( duration <= 0 ) @@ -1341,7 +1302,6 @@ void CSpiral::Think( void ) UTIL_Remove( this ); } - // HACKHACK Cut and pasted from explode.cpp void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) { @@ -1362,7 +1322,4 @@ void SpawnExplosion( Vector center, float randomRange, float time, int magnitude pExplosion->SetThink( &CBaseEntity::SUB_CallUseToggle ); pExplosion->pev->nextthink = gpGlobals->time + time; } - - - #endif diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 2830c9a9..0e4370b4 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -25,7 +25,6 @@ #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 @@ -41,7 +40,7 @@ enum gauss_e { GAUSS_DRAW }; -LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); +LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ) float CGauss::GetFullChargeTime( void ) { @@ -72,7 +71,6 @@ void CGauss::Spawn( ) FallInit();// get ready to fall down. } - void CGauss::Precache( void ) { PRECACHE_MODEL("models/w_gauss.mdl"); @@ -140,7 +138,6 @@ void CGauss::Holster( int skiplocal /* = 0 */ ) m_fInAttack = 0; } - void CGauss::PrimaryAttack() { // don't fire underwater @@ -335,7 +332,6 @@ void CGauss::StartFire( void ) 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; @@ -345,7 +341,6 @@ void CGauss::StartFire( void ) } if ( !g_pGameRules->IsMultiplayer() ) - { // in deathmatch, gauss can pop you up into the air. Not in single play. m_pPlayer->pev->velocity.z = flZVel; @@ -380,8 +375,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) #ifdef CLIENT_DLL if ( m_fPrimaryFire == false ) g_irunninggausspred = true; -#endif - +#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 ); @@ -395,9 +389,8 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) /*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 ); + //ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); #ifndef CLIENT_DLL while (flDamage > 10 && nMaxHits > 0) @@ -535,9 +528,6 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // ALERT( at_console, "%d bytes\n", nTotal ); } - - - void CGauss::WeaponIdle( void ) { ResetEmptySound( ); @@ -588,11 +578,6 @@ void CGauss::WeaponIdle( void ) } } - - - - - class CGaussAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -616,6 +601,6 @@ class CGaussAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); +LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ) #endif diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 88bef689..482533a5 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -38,7 +38,8 @@ public: void HandleAnimEvent( MonsterEvent_t *pEvent ); int ISoundMask ( void ); }; -LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ); + +LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ) //========================================================= // Classify - indicates this monster's place in the diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 09c2f617..476658c6 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -31,7 +31,7 @@ //===================grenade -LINK_ENTITY_TO_CLASS( grenade, CGrenade ); +LINK_ENTITY_TO_CLASS( grenade, CGrenade ) // Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges #define SF_DETONATE 0x0001 @@ -125,7 +125,6 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) } } - void CGrenade::Smoke( void ) { if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) @@ -152,7 +151,6 @@ 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 ) { @@ -168,7 +166,6 @@ void CGrenade::PreDetonate( void ) pev->nextthink = gpGlobals->time + 1; } - void CGrenade::Detonate( void ) { TraceResult tr; @@ -197,7 +194,6 @@ void CGrenade::ExplodeTouch( CBaseEntity *pOther ) Explode( &tr, DMG_BLAST ); } - void CGrenade::DangerSoundThink( void ) { if (!IsInWorld()) @@ -215,7 +211,6 @@ void CGrenade::DangerSoundThink( void ) } } - void CGrenade::BounceTouch( CBaseEntity *pOther ) { // don't hit the guy that launched this grenade @@ -277,8 +272,6 @@ void CGrenade::BounceTouch( CBaseEntity *pOther ) } - - void CGrenade::SlideTouch( CBaseEntity *pOther ) { // don't hit the guy that launched this grenade @@ -340,7 +333,6 @@ void CGrenade :: TumbleThink( void ) } } - void CGrenade:: Spawn( void ) { pev->movetype = MOVETYPE_BOUNCE; @@ -355,7 +347,6 @@ void CGrenade:: Spawn( void ) m_fRegisteredSound = FALSE; } - CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) { CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); @@ -382,7 +373,6 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v return pGrenade; } - CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) { CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); @@ -422,7 +412,6 @@ CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector v return pGrenade; } - CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) { CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); @@ -452,8 +441,6 @@ CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, return pGrenade; } - - void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) { edict_t *pentFind; @@ -485,4 +472,3 @@ void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) } //======================end grenade - diff --git a/dlls/glock.cpp b/dlls/glock.cpp index ee3fa5da..fb390d13 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -34,9 +34,8 @@ enum glock_e { GLOCK_ADD_SILENCER }; -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - +LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ) +LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ) void CGlock::Spawn( ) { @@ -50,7 +49,6 @@ void CGlock::Spawn( ) FallInit();// get ready to fall down. } - void CGlock::Precache( void ) { PRECACHE_MODEL("models/v_9mmhandgun.mdl"); @@ -121,13 +119,11 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) 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 ); @@ -170,7 +166,6 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } - void CGlock::Reload( void ) { if ( m_pPlayer->ammo_9mm <= 0 ) @@ -189,8 +184,6 @@ void CGlock::Reload( void ) } } - - void CGlock::WeaponIdle( void ) { ResetEmptySound( ); @@ -225,13 +218,6 @@ void CGlock::WeaponIdle( void ) } } - - - - - - - class CGlockAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -255,20 +241,6 @@ class CGlockAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - +LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ) +LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ) diff --git a/dlls/gman.cpp b/dlls/gman.cpp index be6e2745..771b86a3 100644 --- a/dlls/gman.cpp +++ b/dlls/gman.cpp @@ -51,16 +51,16 @@ public: EHANDLE m_hTalkTarget; float m_flTalkTime; }; -LINK_ENTITY_TO_CLASS( monster_gman, CGMan ); +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 ); +IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ) //========================================================= // Classify - indicates this monster's place in the @@ -140,12 +140,10 @@ void CGMan :: Precache() PRECACHE_MODEL( "models/gman.mdl" ); } - //========================================================= // AI Schedules Specific to this monster //========================================================= - void CGMan :: StartTask( Task_t *pTask ) { switch( pTask->iTask ) @@ -200,7 +198,6 @@ void CGMan :: RunTask( Task_t *pTask ) } } - //========================================================= // Override all damage //========================================================= @@ -220,14 +217,12 @@ int CGMan :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float 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 ); diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 11b8c064..5fe36c17 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -58,10 +58,9 @@ TYPEDESCRIPTION CRecharge::m_SaveData[] = DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_recharge, CRecharge); +IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity ) +LINK_ENTITY_TO_CLASS( func_recharge, CRecharge ) void CRecharge::KeyValue( KeyValueData *pkvd ) { @@ -103,7 +102,6 @@ void CRecharge::Precache() PRECACHE_SOUND("items/suitchargeok1.wav"); } - void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // if it's not a player, ignore @@ -160,7 +158,6 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); } - // charge the player if (m_hActivator->pev->armorvalue < 100) { diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp index 9bb7b2c2..fc503171 100644 --- a/dlls/h_cine.cpp +++ b/dlls/h_cine.cpp @@ -28,7 +28,6 @@ #include "monsters.h" #include "decals.h" - class CLegacyCineMonster : public CBaseMonster { public: @@ -44,11 +43,13 @@ 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: @@ -89,14 +90,14 @@ public: // ********** 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 ); +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 ********** @@ -129,7 +130,6 @@ void CLegacyCineMonster :: CineSpawn( char *szModel ) } } - // // CineStart // @@ -190,8 +190,7 @@ public: void EXPORT BloodGush ( void ); }; -LINK_ENTITY_TO_CLASS( cine_blood, CCineBlood ); - +LINK_ENTITY_TO_CLASS( cine_blood, CCineBlood ) void CCineBlood :: BloodGush ( void ) { @@ -202,19 +201,20 @@ void CCineBlood :: BloodGush ( void ) UTIL_MakeVectors(pev->angles); if ( pev->health-- < 0 ) REMOVE_ENTITY(ENT(pev)); -// CHANGE_METHOD ( ENT(pev), em_think, SUB_Remove ); + // 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 + 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. + { + // 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); @@ -238,4 +238,3 @@ void CCineBlood :: Spawn ( void ) SetUse( &CCineBlood::BloodStart ); pev->health = 20;//hacked health to count iterations } - diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index df2e30b9..9a79e994 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -28,7 +28,6 @@ #include "weapons.h" #include "player.h" - #define TEMP_FOR_SCREEN_SHOTS #ifdef TEMP_FOR_SCREEN_SHOTS //=================================================== @@ -58,8 +57,7 @@ TYPEDESCRIPTION CCycler::m_SaveData[] = DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ) // // we should get rid of all the other cyclers and replace them with this. @@ -69,9 +67,8 @@ 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 ); - +LINK_ENTITY_TO_CLASS( cycler, CGenericCycler ) // Probe droid imported for tech demo compatibility // @@ -82,15 +79,15 @@ class CCyclerProbe : public CCycler public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe ); + +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(char *szModel, Vector vecMin, Vector vecMax) @@ -111,7 +108,6 @@ void CCycler :: GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax) UTIL_SetSize(pev, vecMin, vecMax); } - void CCycler :: Spawn( ) { InitBoneControllers(); @@ -142,9 +138,6 @@ void CCycler :: Spawn( ) } } - - - // // cycler think // @@ -211,10 +204,8 @@ int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return 0; } - #endif - class CCyclerSprite : public CBaseEntity { public: @@ -235,7 +226,7 @@ public: float m_maxFrame; }; -LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite ); +LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite ) TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = { @@ -244,8 +235,7 @@ TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ); - +IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ) void CCyclerSprite::Spawn( void ) { @@ -265,7 +255,6 @@ void CCyclerSprite::Spawn( void ) m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; } - void CCyclerSprite::Think( void ) { if ( ShouldAnimate() ) @@ -275,14 +264,12 @@ void CCyclerSprite::Think( void ) 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 ) @@ -299,12 +286,6 @@ void CCyclerSprite::Animate( float frames ) pev->frame = fmod( pev->frame, m_maxFrame ); } - - - - - - class CWeaponCycler : public CBasePlayerWeapon { public: @@ -319,8 +300,8 @@ public: int m_iszModel; int m_iModel; }; -LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ); +LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ) void CWeaponCycler::Spawn( ) { @@ -337,8 +318,6 @@ void CWeaponCycler::Spawn( ) SetTouch( &CBasePlayerItem::DefaultTouch ); } - - BOOL CWeaponCycler::Deploy( ) { m_pPlayer->pev->viewmodel = m_iszModel; @@ -348,13 +327,11 @@ BOOL CWeaponCycler::Deploy( ) return TRUE; } - void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; } - void CWeaponCycler::PrimaryAttack() { @@ -363,7 +340,6 @@ void CWeaponCycler::PrimaryAttack() m_flNextPrimaryAttack = gpGlobals->time + 0.3; } - void CWeaponCycler::SecondaryAttack( void ) { float flFrameRate, flGroundSpeed; @@ -385,8 +361,6 @@ void CWeaponCycler::SecondaryAttack( void ) m_flNextSecondaryAttack = gpGlobals->time + 0.3; } - - // Flaming Wreakage class CWreckage : public CBaseMonster { @@ -400,14 +374,15 @@ class CWreckage : public CBaseMonster int m_flStartTime; }; + TYPEDESCRIPTION CWreckage::m_SaveData[] = { DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster ) -LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage ); +LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage ) void CWreckage::Spawn( void ) { diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 61285526..21e366b9 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -20,7 +21,6 @@ #include "nodes.h" #include "player.h" - #define HANDGRENADE_PRIMARY_VOLUME 450 enum handgrenade_e { @@ -34,9 +34,7 @@ enum handgrenade_e { HANDGRENADE_DRAW }; - -LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ); - +LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ) void CHandGrenade::Spawn( ) { @@ -47,13 +45,11 @@ void CHandGrenade::Spawn( ) #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"); @@ -78,7 +74,6 @@ int CHandGrenade::GetItemInfo(ItemInfo *p) return 1; } - BOOL CHandGrenade::Deploy( ) { m_flReleaseThrow = -1; @@ -122,7 +117,6 @@ void CHandGrenade::PrimaryAttack() } } - void CHandGrenade::WeaponIdle( void ) { if ( m_flReleaseThrow == 0 && m_flStartThrow ) @@ -227,7 +221,3 @@ void CHandGrenade::WeaponIdle( void ) SendWeaponAnim( iAnim ); } } - - - - diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index 56ceec3c..d7a2e427 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -38,7 +38,7 @@ 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 + SCHED_ASSASSIN_JUMP_LAND // hit and run away }; //========================================================= @@ -47,10 +47,9 @@ enum enum { - TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1, // falling and waiting to hit ground + TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1 // falling and waiting to hit ground }; - //========================================================= // Monster's Anim Events Go Here //========================================================= @@ -58,7 +57,6 @@ enum #define ASSASSIN_AE_TOSS1 2 #define ASSASSIN_AE_JUMP 3 - #define bits_MEMORY_BADJUMP (bits_MEMORY_CUSTOM1) class CHAssassin : public CBaseMonster @@ -104,8 +102,8 @@ public: int m_iShell; }; -LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ); +LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ) TYPEDESCRIPTION CHAssassin::m_SaveData[] = { @@ -123,8 +121,7 @@ TYPEDESCRIPTION CHAssassin::m_SaveData[] = DEFINE_FIELD( CHAssassin, m_iFrustration, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ) //========================================================= // DieSound @@ -152,12 +149,11 @@ int CHAssassin :: ISoundMask ( void) bits_SOUND_PLAYER; } - //========================================================= // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CHAssassin :: Classify ( void ) +int CHAssassin :: Classify ( void ) { return CLASS_HUMAN_MILITARY; } @@ -184,7 +180,6 @@ void CHAssassin :: SetYawSpeed ( void ) pev->yaw_speed = ys; } - //========================================================= // Shoot //========================================================= @@ -234,7 +229,6 @@ void CHAssassin :: Shoot ( void ) m_cAmmoLoaded--; } - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -317,8 +311,6 @@ void CHAssassin :: Precache() m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell } - - //========================================================= // AI Schedules Specific to this monster @@ -355,7 +347,6 @@ Schedule_t slAssassinFail[] = }, }; - //========================================================= // Enemy exposed Agrunt's cover //========================================================= @@ -378,7 +369,6 @@ Schedule_t slAssassinExposed[] = }, }; - //========================================================= // Take cover from enemy! Tries lateral cover before node // cover! @@ -409,7 +399,6 @@ Schedule_t slAssassinTakeCoverFromEnemy[] = }, }; - //========================================================= // Take cover from enemy! Tries lateral cover before node // cover! @@ -442,7 +431,6 @@ Schedule_t slAssassinTakeCoverFromEnemy2[] = }, }; - //========================================================= // hide from the loudest sound source //========================================================= @@ -468,10 +456,6 @@ Schedule_t slAssassinTakeCoverFromBestSound[] = }, }; - - - - //========================================================= // AlertIdle Schedules //========================================================= @@ -501,8 +485,6 @@ Schedule_t slAssassinHide[] = }, }; - - //========================================================= // HUNT Schedules //========================================================= @@ -528,7 +510,6 @@ Schedule_t slAssassinHunt[] = }, }; - //========================================================= // Jumping Schedules //========================================================= @@ -550,7 +531,6 @@ Schedule_t slAssassinJump[] = }, }; - //========================================================= // repel //========================================================= @@ -561,7 +541,6 @@ Task_t tlAssassinJumpAttack[] = { TASK_ASSASSIN_FALL_TO_GROUND, (float)0 }, }; - Schedule_t slAssassinJumpAttack[] = { { @@ -573,7 +552,6 @@ Schedule_t slAssassinJumpAttack[] = }, }; - //========================================================= // repel //========================================================= @@ -617,8 +595,7 @@ DEFINE_CUSTOM_SCHEDULES( CHAssassin ) slAssassinJumpLand, }; -IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ); - +IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ) //========================================================= // CheckMeleeAttack1 - jump like crazy if the enemy gets too close. @@ -706,7 +683,6 @@ BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) return FALSE; } - //========================================================= // RunAI //========================================================= @@ -755,7 +731,6 @@ void CHAssassin :: RunAI( void ) } } - //========================================================= // StartTask //========================================================= @@ -781,7 +756,6 @@ void CHAssassin :: StartTask ( Task_t *pTask ) } } - //========================================================= // RunTask //========================================================= @@ -1013,5 +987,4 @@ Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) return CBaseMonster :: GetScheduleOfType( Type ); } - #endif diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 243faf8f..a94232de 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -97,7 +97,7 @@ public: virtual float GetSoundVolue( void ) { return 1.0; } Schedule_t* GetScheduleOfType ( int Type ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES static const char *pIdleSounds[]; static const char *pAlertSounds[]; @@ -106,7 +106,8 @@ public: static const char *pDeathSounds[]; static const char *pBiteSounds[]; }; -LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ); + +LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ) DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) { @@ -114,24 +115,27 @@ DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) slHCRangeAttack1Fast, }; -IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ) -const char *CHeadCrab::pIdleSounds[] = +const char *CHeadCrab::pIdleSounds[] = { "headcrab/hc_idle1.wav", "headcrab/hc_idle2.wav", "headcrab/hc_idle3.wav", }; -const char *CHeadCrab::pAlertSounds[] = + +const char *CHeadCrab::pAlertSounds[] = { "headcrab/hc_alert1.wav", }; -const char *CHeadCrab::pPainSounds[] = + +const char *CHeadCrab::pPainSounds[] = { "headcrab/hc_pain1.wav", "headcrab/hc_pain2.wav", "headcrab/hc_pain3.wav", }; + const char *CHeadCrab::pAttackSounds[] = { "headcrab/hc_attack1.wav", @@ -169,7 +173,6 @@ Vector CHeadCrab :: Center ( void ) return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); } - Vector CHeadCrab :: BodyTarget( const Vector &posSrc ) { return Center( ); @@ -310,7 +313,6 @@ void CHeadCrab :: Precache() PRECACHE_MODEL("models/headcrab.mdl"); } - //========================================================= // RunTask //========================================================= @@ -395,7 +397,6 @@ void CHeadCrab :: StartTask ( Task_t *pTask ) } } - //========================================================= // CheckRangeAttack1 //========================================================= @@ -480,7 +481,6 @@ Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) return CBaseMonster::GetScheduleOfType( Type ); } - class CBabyCrab : public CHeadCrab { public: @@ -493,7 +493,8 @@ public: 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 ); + +LINK_ENTITY_TO_CLASS( monster_babycrab, CBabyCrab ) void CBabyCrab :: Spawn( void ) { @@ -512,13 +513,11 @@ void CBabyCrab :: Precache( void ) CHeadCrab::Precache(); } - void CBabyCrab :: SetYawSpeed ( void ) { pev->yaw_speed = 120; } - BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) { if ( pev->flags & FL_ONGROUND ) @@ -534,7 +533,6 @@ BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) return FALSE; } - Schedule_t* CBabyCrab :: GetScheduleOfType ( int Type ) { switch( Type ) diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index bee988a0..940a8cc9 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -29,27 +30,24 @@ 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 ); +LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ) /* -TYPEDESCRIPTION CHealthKit::m_SaveData[] = +TYPEDESCRIPTION CHealthKit::m_SaveData[] = { }; -IMPLEMENT_SAVERESTORE( CHealthKit, CItem); +IMPLEMENT_SAVERESTORE( CHealthKit, CItem) */ void CHealthKit :: Spawn( void ) @@ -96,8 +94,6 @@ BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) return FALSE; } - - //------------------------------------------------------------- // Wall mounted health kit //------------------------------------------------------------- @@ -132,10 +128,9 @@ TYPEDESCRIPTION CWallHealth::m_SaveData[] = DEFINE_FIELD( CWallHealth, m_flSoundTime, FIELD_TIME), }; -IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth); +IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity ) +LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth) void CWallHealth::KeyValue( KeyValueData *pkvd ) { @@ -167,8 +162,7 @@ void CWallHealth::Spawn() UTIL_SetSize(pev, pev->mins, pev->maxs); SET_MODEL(ENT(pev), STRING(pev->model) ); m_iJuice = gSkillData.healthchargerCapacity; - pev->frame = 0; - + pev->frame = 0; } void CWallHealth::Precache() @@ -178,7 +172,6 @@ void CWallHealth::Precache() PRECACHE_SOUND("items/medcharge4.wav"); } - void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // Make sure that we have a caller @@ -210,7 +203,6 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u SetThink( &CWallHealth::Off ); // Time to recharge yet? - if (m_flNextCharge >= gpGlobals->time) return; @@ -227,7 +219,6 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); } - // charge the player if ( pActivator->TakeHealth( 1, DMG_GENERIC ) ) { diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index b31248db..94072d57 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -27,7 +27,6 @@ */ - #include "extdll.h" #include "plane.h" #include "util.h" @@ -102,7 +101,7 @@ enum 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, + SCHED_GRUNT_ELOF_FAIL }; //========================================================= @@ -112,7 +111,7 @@ enum { TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1, TASK_GRUNT_SPEAK_SENTENCE, - TASK_GRUNT_CHECK_FIRE, + TASK_GRUNT_CHECK_FIRE }; //========================================================= @@ -147,7 +146,7 @@ public: void GibMonster( void ); void SpeakSentence( void ); - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); CBaseEntity *Kick( void ); @@ -161,7 +160,7 @@ public: BOOL FOkToSpeak( void ); void JustSpoke( void ); - CUSTOM_SCHEDULES; + 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, @@ -187,9 +186,9 @@ public: static const char *pGruntSentences[]; }; -LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ); +LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ) -TYPEDESCRIPTION CHGrunt::m_SaveData[] = +TYPEDESCRIPTION CHGrunt::m_SaveData[] = { DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ), DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ), @@ -205,9 +204,9 @@ TYPEDESCRIPTION CHGrunt::m_SaveData[] = DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ); +IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ) -const char *CHGrunt::pGruntSentences[] = +const char *CHGrunt::pGruntSentences[] = { "HG_GREN", // grenade scared grunt "HG_ALERT", // sees player @@ -227,7 +226,7 @@ enum HGRUNT_SENT_COVER, HGRUNT_SENT_THROW, HGRUNT_SENT_CHARGE, - HGRUNT_SENT_TAUNT, + HGRUNT_SENT_TAUNT } HGRUNT_SENTENCE_TYPES; //========================================================= @@ -280,7 +279,8 @@ void CHGrunt :: GibMonster ( void ) Vector vecGunAngles; if ( GetBodygroup( 2 ) != 2 ) - {// throw a gun if the grunt has one + { + // throw a gun if the grunt has one GetAttachment( 0, vecGunPos, vecGunAngles ); CBaseEntity *pGun; @@ -330,7 +330,7 @@ int CHGrunt :: ISoundMask ( void ) //========================================================= BOOL CHGrunt :: FOkToSpeak( void ) { -// if someone else is talking, don't speak + // if someone else is talking, don't speak if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) return FALSE; @@ -344,8 +344,8 @@ BOOL CHGrunt :: FOkToSpeak( void ) } // if player is not in pvs, don't speak -// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) -// return FALSE; + //if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) + // return FALSE; return TRUE; } @@ -406,7 +406,6 @@ BOOL CHGrunt :: FCanCheckAttacks ( void ) } } - //========================================================= // CheckMeleeAttack1 //========================================================= @@ -499,7 +498,7 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) m_fThrowGrenade = FALSE; return m_fThrowGrenade; } - + Vector vecTarget; if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) @@ -539,7 +538,7 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) m_fThrowGrenade = FALSE; } } - + if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) { // crap, I don't want to blow myself up @@ -548,7 +547,7 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) return m_fThrowGrenade; } - + if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) { Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); @@ -592,12 +591,9 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) } } - - return m_fThrowGrenade; } - //========================================================= // TraceAttack - make sure we're not taking it in the helmet //========================================================= @@ -755,7 +751,7 @@ CBaseEntity *CHGrunt :: Kick( void ) 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 ); @@ -847,7 +843,7 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) switch( pEvent->event ) { case HGRUNT_AE_DROP_GUN: - { + { Vector vecGunPos; Vector vecGunAngles; @@ -869,16 +865,13 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) { 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 ); @@ -889,7 +882,7 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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; + break; case HGRUNT_AE_GREN_LAUNCH: { @@ -901,15 +894,13 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) else m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. } - break; - + 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; - + break; case HGRUNT_AE_BURST1: { if ( FBitSet( pev->weapons, HGRUNT_9MMAR )) @@ -935,13 +926,11 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); } - break; - + break; case HGRUNT_AE_BURST2: case HGRUNT_AE_BURST3: Shoot(); break; - case HGRUNT_AE_KICK: { CBaseEntity *pHurt = Kick(); @@ -955,8 +944,7 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB ); } } - break; - + break; case HGRUNT_AE_CAUGHT_ENEMY: { if ( FOkToSpeak() ) @@ -966,7 +954,6 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } - default: CSquadMonster::HandleAnimEvent( pEvent ); break; @@ -1094,26 +1081,21 @@ void CHGrunt :: StartTask ( Task_t *pTask ) } 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 ); @@ -1122,7 +1104,6 @@ void CHGrunt :: StartTask ( Task_t *pTask ) m_IdealActivity = ACT_GLIDE; } break; - default: CSquadMonster :: StartTask( pTask ); break; @@ -1174,7 +1155,7 @@ void CHGrunt :: PainSound ( void ) return; } } -#endif +#endif switch ( RANDOM_LONG(0,6) ) { case 0: @@ -1457,7 +1438,6 @@ Schedule_t slGruntSuppress[] = }, }; - //========================================================= // grunt wait in cover - we don't allow danger or the ability // to attack to break a grunt's run to cover schedule, but @@ -1541,7 +1521,6 @@ Schedule_t slGruntGrenadeCover[] = }, }; - //========================================================= // drop grenade then run to cover. //========================================================= @@ -1687,7 +1666,6 @@ Schedule_t slGruntRangeAttack1A[] = }, }; - //========================================================= // primary range attack. Overriden because base class stops attacking when the enemy is occluded. // grunt's grenade toss requires the enemy be occluded. @@ -1750,7 +1728,6 @@ Schedule_t slGruntRangeAttack2[] = }, }; - //========================================================= // repel //========================================================= @@ -1779,7 +1756,6 @@ Schedule_t slGruntRepel[] = }, }; - //========================================================= // repel //========================================================= @@ -1858,7 +1834,7 @@ DEFINE_CUSTOM_SCHEDULES( CHGrunt ) slGruntRepelLand, }; -IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ) //========================================================= // SetActivity @@ -2216,7 +2192,7 @@ Schedule_t *CHGrunt :: GetSchedule( void ) default: break; } - + // no special cases here, call the base class return CSquadMonster :: GetSchedule(); } @@ -2374,7 +2350,6 @@ Schedule_t* CHGrunt :: GetScheduleOfType ( int Type ) } } - //========================================================= // CHGruntRepel - when triggered, spawns a monster_human_grunt // repelling down a line. @@ -2389,7 +2364,7 @@ public: int m_iSpriteTexture; // Don't save, precache }; -LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ); +LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ) void CHGruntRepel::Spawn( void ) { @@ -2432,8 +2407,6 @@ void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE UTIL_Remove( this ); } - - //========================================================= // DEAD HGRUNT PROP //========================================================= @@ -2462,7 +2435,7 @@ void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } -LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ); +LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ) //========================================================= // ********** DeadHGrunt SPAWN ********** diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index b61fbd87..368a4e07 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -25,23 +25,22 @@ #include "hornet.h" #include "gamerules.h" - int iHornetTrail; int iHornetPuff; -LINK_ENTITY_TO_CLASS( hornet, CHornet ); +LINK_ENTITY_TO_CLASS( hornet, CHornet ) //========================================================= // Save/Restore //========================================================= -TYPEDESCRIPTION CHornet::m_SaveData[] = +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 ); +IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ) //========================================================= // don't let hornets gib, ever. @@ -114,7 +113,6 @@ void CHornet :: Spawn( void ) ResetSequenceInfo( ); } - void CHornet :: Precache() { PRECACHE_MODEL("models/hornet.mdl"); @@ -215,7 +213,6 @@ old colors break; */ - // trail MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_BEAMFOLLOW ); @@ -264,7 +261,8 @@ void CHornet :: TrackTarget ( void ) // UNDONE: The player pointer should come back after returning from another level if ( m_hEnemy == NULL ) - {// enemy is dead. + { + // enemy is dead. Look( 512 ); m_hEnemy = BestVisibleEnemy( ); } @@ -289,7 +287,8 @@ void CHornet :: TrackTarget ( void ) flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); if ( flDelta < 0.5 ) - {// hafta turn wide again. play sound + { + // 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; @@ -299,7 +298,8 @@ void CHornet :: TrackTarget ( void ) } 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. + { + // 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; } @@ -308,7 +308,6 @@ void CHornet :: TrackTarget ( void ) 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 ); @@ -367,7 +366,8 @@ void CHornet :: TrackTarget ( void ) void CHornet :: TrackTouch ( CBaseEntity *pOther ) { if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) - {// bumped into the guy that shot it. + { + // bumped into the guy that shot it. pev->solid = SOLID_NOT; return; } @@ -398,10 +398,11 @@ void CHornet::DartTouch( CBaseEntity *pOther ) void CHornet::DieTouch ( CBaseEntity *pOther ) { if ( pOther && pOther->pev->takedamage ) - {// do the damage - + { + // do the damage switch (RANDOM_LONG(0,2)) - {// buzz when you plug someone + { + // 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; @@ -416,4 +417,3 @@ void CHornet::DieTouch ( CBaseEntity *pOther ) SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! } - diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index f6cc2e44..6daca286 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -24,7 +24,6 @@ #include "hornet.h" #include "gamerules.h" - enum hgun_e { HGUN_IDLE1 = 0, HGUN_FIDGETSWAY, @@ -40,8 +39,7 @@ enum firemode_e FIREMODE_FAST }; - -LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ); +LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ) BOOL CHgun::IsUseable( void ) { @@ -60,7 +58,6 @@ void CHgun::Spawn( ) FallInit();// get ready to fall down. } - void CHgun::Precache( void ) { PRECACHE_MODEL("models/v_hgun.mdl"); @@ -76,7 +73,6 @@ int CHgun::AddToPlayer( CBasePlayer *pPlayer ) { if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { - #ifndef CLIENT_DLL if ( g_pGameRules->IsMultiplayer() ) { @@ -84,7 +80,6 @@ int CHgun::AddToPlayer( CBasePlayer *pPlayer ) pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; } #endif - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); MESSAGE_END(); @@ -110,7 +105,6 @@ int CHgun::GetItemInfo(ItemInfo *p) return 1; } - BOOL CHgun::Deploy( ) { return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); @@ -128,7 +122,6 @@ void CHgun::Holster( int skiplocal /* = 0 */ ) } } - void CHgun::PrimaryAttack() { Reload( ); @@ -137,7 +130,6 @@ void CHgun::PrimaryAttack() { return; } - #ifndef CLIENT_DLL UTIL_MakeVectors( m_pPlayer->pev->v_angle ); @@ -146,10 +138,8 @@ void CHgun::PrimaryAttack() 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; @@ -162,8 +152,6 @@ void CHgun::PrimaryAttack() 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 ); @@ -177,8 +165,6 @@ void CHgun::PrimaryAttack() m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } - - void CHgun::SecondaryAttack( void ) { Reload(); @@ -239,17 +225,14 @@ void CHgun::SecondaryAttack( void ) 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; @@ -261,7 +244,6 @@ void CHgun::SecondaryAttack( void ) 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) @@ -274,7 +256,6 @@ void CHgun::Reload( void ) } } - void CHgun::WeaponIdle( void ) { Reload( ); @@ -301,5 +282,4 @@ void CHgun::WeaponIdle( void ) } SendWeaponAnim( iAnim ); } - -#endif \ No newline at end of file +#endif diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index 182d3df1..6d62369b 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -59,7 +59,7 @@ enum { SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1, SCHED_HOUND_HOP_RETREAT, - SCHED_HOUND_FAIL, + SCHED_HOUND_FAIL }; //========================================================= @@ -99,10 +99,10 @@ public: Schedule_t *GetScheduleOfType ( int Type ); Schedule_t *GetSchedule( void ); - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES static TYPEDESCRIPTION m_SaveData[]; int m_iSpriteTexture; @@ -110,7 +110,8 @@ public: 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 ); + +LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ) TYPEDESCRIPTION CHoundeye::m_SaveData[] = { @@ -120,7 +121,7 @@ TYPEDESCRIPTION CHoundeye::m_SaveData[] = DEFINE_FIELD( CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR ), }; -IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ); +IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ) //========================================================= // Classify - indicates this monster's place in the @@ -548,7 +549,6 @@ void CHoundeye :: WriteBeamColor ( void ) WRITE_BYTE( bGreen ); WRITE_BYTE( bBlue ); } - //========================================================= // SonicAttack @@ -608,7 +608,6 @@ void CHoundeye :: SonicAttack ( void ) 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) @@ -616,8 +615,8 @@ void CHoundeye :: SonicAttack ( void ) if ( pEntity->pev->takedamage != DAMAGE_NO ) { if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) - {// houndeyes don't hurt other houndeyes with their attack - + { + // 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 @@ -663,7 +662,7 @@ void CHoundeye :: SonicAttack ( void ) } } } - + //========================================================= // start task //========================================================= @@ -745,7 +744,6 @@ void CHoundeye :: StartTask ( Task_t *pTask ) } } */ - break; } case TASK_SPECIAL_ATTACK1: @@ -782,7 +780,6 @@ void CHoundeye :: RunTask ( Task_t *pTask ) { TaskComplete(); } - break; } case TASK_HOUND_CLOSE_EYE: @@ -827,7 +824,6 @@ void CHoundeye :: RunTask ( Task_t *pTask ) SonicAttack(); TaskComplete(); } - break; } default: @@ -853,11 +849,13 @@ void CHoundeye::PrescheduleThink ( void ) if ( !m_fDontBlink ) { if ( ( pev->skin == 0 ) && RANDOM_LONG(0,0x7F) == 0 ) - {// start blinking! + { + // start blinking! pev->skin = HOUNDEYE_EYE_FRAMES - 1; } else if ( pev->skin != 0 ) - {// already blinking + { + // already blinking pev->skin--; } } @@ -964,7 +962,7 @@ Task_t tlHoundSleep[] = Schedule_t slHoundSleep[] = { - { + { tlHoundSleep, ARRAYSIZE ( tlHoundSleep ), bits_COND_HEAR_SOUND | @@ -1020,7 +1018,6 @@ Schedule_t slHoundWakeUrgent[] = }, }; - Task_t tlHoundSpecialAttack1[] = { { TASK_STOP_MOVING, 0 }, @@ -1140,7 +1137,7 @@ DEFINE_CUSTOM_SCHEDULES( CHoundeye ) slHoundCombatFailNoPVS, }; -IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ) //========================================================= // GetScheduleOfType @@ -1259,7 +1256,7 @@ Schedule_t *CHoundeye :: GetSchedule( void ) { case MONSTERSTATE_COMBAT: { -// dead enemy + // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index b10227da..da37bc5d 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -23,7 +23,7 @@ #include "cbase.h" #include "monsters.h" #include "schedule.h" -#include "flyingmonster.h" +#include "flyingmonster.h" #include "nodes.h" #include "soundent.h" #include "animation.h" @@ -42,8 +42,6 @@ extern CGraph WorldGraph; #define EYE_BACK 3 #define EYE_LOOK 4 - - //========================================================= // Monster's Anim Events Go Here //========================================================= @@ -57,7 +55,7 @@ public: void SetYawSpeed( void ); int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES int Save( CSave &save ); int Restore( CRestore &restore ); @@ -123,9 +121,9 @@ public: void PainSound( void ); }; -LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ); +LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ) -TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = +TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = { DEFINE_FIELD( CIchthyosaur, m_SaveVelocity, FIELD_VECTOR ), DEFINE_FIELD( CIchthyosaur, m_idealDist, FIELD_FLOAT ), @@ -138,10 +136,9 @@ TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = DEFINE_FIELD( CIchthyosaur, m_flNextAlert, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ); +IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ) - -const char *CIchthyosaur::pIdleSounds[] = +const char *CIchthyosaur::pIdleSounds[] = { "ichy/ichy_idle1.wav", "ichy/ichy_idle2.wav", @@ -149,32 +146,32 @@ const char *CIchthyosaur::pIdleSounds[] = "ichy/ichy_idle4.wav", }; -const char *CIchthyosaur::pAlertSounds[] = +const char *CIchthyosaur::pAlertSounds[] = { "ichy/ichy_alert2.wav", "ichy/ichy_alert3.wav", }; -const char *CIchthyosaur::pAttackSounds[] = +const char *CIchthyosaur::pAttackSounds[] = { "ichy/ichy_attack1.wav", "ichy/ichy_attack2.wav", }; -const char *CIchthyosaur::pBiteSounds[] = +const char *CIchthyosaur::pBiteSounds[] = { "ichy/ichy_bite1.wav", "ichy/ichy_bite2.wav", }; -const char *CIchthyosaur::pPainSounds[] = +const char *CIchthyosaur::pPainSounds[] = { "ichy/ichy_pain2.wav", "ichy/ichy_pain3.wav", "ichy/ichy_pain5.wav", }; -const char *CIchthyosaur::pDieSounds[] = +const char *CIchthyosaur::pDieSounds[] = { "ichy/ichy_die2.wav", "ichy/ichy_die4.wav", @@ -183,7 +180,6 @@ const char *CIchthyosaur::pDieSounds[] = #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 ); @@ -221,7 +217,7 @@ enum { TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, TASK_ICHTHYOSAUR_SWIM, - TASK_ICHTHYOSAUR_FLOAT, + TASK_ICHTHYOSAUR_FLOAT }; //========================================================= @@ -268,7 +264,6 @@ static Schedule_t slSwimAgitated[] = }, }; - static Task_t tlCircleEnemy[] = { { TASK_SET_ACTIVITY, (float)ACT_WALK }, @@ -290,7 +285,6 @@ static Schedule_t slCircleEnemy[] = }, }; - Task_t tlTwitchDie[] = { { TASK_STOP_MOVING, 0 }, @@ -310,15 +304,15 @@ Schedule_t slTwitchDie[] = }, }; - -DEFINE_CUSTOM_SCHEDULES(CIchthyosaur) +DEFINE_CUSTOM_SCHEDULES( CIchthyosaur ) { slSwimAround, slSwimAgitated, slCircleEnemy, slTwitchDie, }; -IMPLEMENT_CUSTOM_SCHEDULES(CIchthyosaur, CFlyingMonster); + +IMPLEMENT_CUSTOM_SCHEDULES( CIchthyosaur, CFlyingMonster ) //========================================================= // Classify - indicates this monster's place in the @@ -329,7 +323,6 @@ int CIchthyosaur :: Classify ( void ) return CLASS_ALIEN_MONSTER; } - //========================================================= // CheckMeleeAttack1 //========================================================= @@ -390,8 +383,6 @@ void CIchthyosaur :: SetYawSpeed ( void ) pev->yaw_speed = 100; } - - //========================================================= // Killed - overrides CFlyingMonster. // @@ -413,7 +404,6 @@ void CIchthyosaur::BecomeDead( void ) #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. @@ -569,7 +559,6 @@ Schedule_t* CIchthyosaur::GetSchedule() return CFlyingMonster :: GetSchedule(); } - //========================================================= //========================================================= Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) @@ -592,8 +581,6 @@ Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) return CBaseMonster :: GetScheduleOfType( Type ); } - - //========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the @@ -619,12 +606,10 @@ void CIchthyosaur::StartTask(Task_t *pTask) } CFlyingMonster::StartTask(pTask); break; - case TASK_ICHTHYOSAUR_FLOAT: pev->skin = EYE_BASE; SetSequenceByName( "bellyup" ); break; - default: CFlyingMonster::StartTask(pTask); break; @@ -646,7 +631,7 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) 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; @@ -655,7 +640,7 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) // 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) @@ -728,7 +713,6 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) TaskComplete( ); } break; - case TASK_ICHTHYOSAUR_FLOAT: pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); pev->velocity = pev->velocity * 0.8; @@ -742,15 +726,12 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) } // ALERT( at_console, "%f\n", pev->velocity.z ); break; - default: CFlyingMonster :: RunTask ( pTask ); break; } } - - float CIchthyosaur::VectorToPitch( const Vector &vec ) { float pitch; @@ -835,7 +816,6 @@ float CIchthyosaur::ChangeYaw( int speed ) return CFlyingMonster::ChangeYaw( speed ); } - Activity CIchthyosaur:: GetStoppedActivity( void ) { if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else @@ -848,7 +828,6 @@ void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f m_SaveVelocity = vecDir * m_flightSpeed; } - void CIchthyosaur::MonsterThink ( void ) { CFlyingMonster::MonsterThink( ); @@ -925,7 +904,6 @@ void CIchthyosaur::Swim( ) pev->framerate = m_flightSpeed / 150.0; // ALERT( at_console, "run %.2f\n", pev->framerate ); } - /* if (!m_pBeam) { @@ -965,16 +943,13 @@ void CIchthyosaur::Swim( ) // 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 @@ -1068,7 +1043,6 @@ void CIchthyosaur::Swim( ) // 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. @@ -1107,5 +1081,4 @@ Vector CIchthyosaur::DoProbe(const Vector &Probe) } return Vector(0, 0, 0); } - #endif diff --git a/dlls/islave.cpp b/dlls/islave.cpp index d4ad75b4..c3bff559 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -62,12 +62,12 @@ public: void Killed( entvars_t *pevAttacker, int iGib ); - void StartTask ( Task_t *pTask ); + void StartTask ( Task_t *pTask ); Schedule_t *GetSchedule( void ); Schedule_t *GetScheduleOfType ( int Type ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; @@ -93,9 +93,9 @@ public: static const char *pPainSounds[]; static const char *pDeathSounds[]; }; -LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ); -LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ); +LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ) +LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ) TYPEDESCRIPTION CISlave::m_SaveData[] = { @@ -111,31 +111,28 @@ TYPEDESCRIPTION CISlave::m_SaveData[] = }; -IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ); +IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ) - - - -const char *CISlave::pAttackHitSounds[] = +const char *CISlave::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CISlave::pAttackMissSounds[] = +const char *CISlave::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", }; -const char *CISlave::pPainSounds[] = +const char *CISlave::pPainSounds[] = { "aslave/slv_pain1.wav", "aslave/slv_pain2.wav", }; -const char *CISlave::pDeathSounds[] = +const char *CISlave::pDeathSounds[] = { "aslave/slv_die1.wav", "aslave/slv_die2.wav", @@ -145,12 +142,11 @@ const char *CISlave::pDeathSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CISlave :: Classify ( void ) +int CISlave :: Classify ( void ) { return CLASS_ALIEN_MILITARY; } - int CISlave::IRelationship( CBaseEntity *pTarget ) { if ( (pTarget->IsPlayer()) ) @@ -159,7 +155,6 @@ int CISlave::IRelationship( CBaseEntity *pTarget ) return CBaseMonster::IRelationship( pTarget ); } - void CISlave :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) { // ALERT( at_aiconsole, "help " ); @@ -185,7 +180,6 @@ void CISlave :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Ve } } - //========================================================= // ALertSound - scream //========================================================= @@ -208,7 +202,6 @@ void CISlave :: IdleSound( void ) { SENTENCEG_PlayRndSz(ENT(pev), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch); } - #if 0 int side = RANDOM_LONG( 0, 1 ) * 2 - 1; @@ -254,7 +247,6 @@ 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. @@ -267,7 +259,6 @@ int CISlave :: ISoundMask ( void) bits_SOUND_PLAYER; } - void CISlave::Killed( entvars_t *pevAttacker, int iGib ) { ClearBeams( ); @@ -332,8 +323,7 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } } - break; - + break; case ISLAVE_AE_CLAWRAKE: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); @@ -351,8 +341,7 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } } - break; - + break; case ISLAVE_AE_ZAP_POWERUP: { // speed up attack when on hard @@ -393,8 +382,7 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); pev->skin = m_iBeams / 2; } - break; - + break; case ISLAVE_AE_ZAP_SHOOT: { ClearBeams( ); @@ -414,7 +402,6 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ); @@ -435,14 +422,12 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); } - break; - + break; case ISLAVE_AE_ZAP_DONE: { ClearBeams( ); } - break; - + break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; @@ -507,7 +492,6 @@ BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) return FALSE; } - //========================================================= // StartTask //========================================================= @@ -518,7 +502,6 @@ void CISlave :: StartTask ( Task_t *pTask ) CSquadMonster :: StartTask ( pTask ); } - //========================================================= // Spawn //========================================================= @@ -576,7 +559,6 @@ void CISlave :: Precache() UTIL_PrecacheOther( "test_effect" ); } - //========================================================= // TakeDamage - get provoked when injured //========================================================= @@ -591,7 +573,6 @@ int CISlave :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa 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) @@ -600,13 +581,10 @@ void CISlave::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); } - //========================================================= // AI Schedules Specific to this monster //========================================================= - - // primary range attack Task_t tlSlaveAttack1[] = { @@ -629,21 +607,18 @@ Schedule_t slSlaveAttack1[] = }, }; - DEFINE_CUSTOM_SCHEDULES( CISlave ) { slSlaveAttack1, }; -IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ); - +IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ) //========================================================= //========================================================= Schedule_t *CISlave :: GetSchedule( void ) { ClearBeams( ); - /* if (pev->spawnflags) { @@ -651,7 +626,6 @@ Schedule_t *CISlave :: GetSchedule( void ) return GetScheduleOfType( SCHED_RELOAD ); } */ - if ( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; @@ -698,10 +672,9 @@ Schedule_t *CISlave :: GetSchedule( void ) return CSquadMonster::GetSchedule( ); } - Schedule_t *CISlave :: GetScheduleOfType ( int Type ) { - switch ( Type ) + switch( Type ) { case SCHED_FAIL: if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) @@ -717,7 +690,6 @@ Schedule_t *CISlave :: GetScheduleOfType ( int Type ) return CSquadMonster :: GetScheduleOfType( Type ); } - //========================================================= // ArmBeam - small beam from arm to nearby geometry //========================================================= @@ -764,7 +736,6 @@ void CISlave :: ArmBeam( int side ) m_iBeams++; } - //========================================================= // BeamGlow - brighten all beams //========================================================= @@ -783,7 +754,6 @@ void CISlave :: BeamGlow( ) } } - //========================================================= // WackBeam - regenerate dead colleagues //========================================================= @@ -791,7 +761,7 @@ void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) { Vector vecDest; float flDist = 1.0; - + if (m_iBeams >= ISLAVE_MAX_BEAMS) return; @@ -847,7 +817,6 @@ void CISlave :: ZapBeam( int side ) UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); } - //========================================================= // ClearBeams - remove all beams //========================================================= diff --git a/dlls/items.cpp b/dlls/items.cpp index 693d2022..06d657f2 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -39,7 +39,7 @@ public: int m_iType; }; -LINK_ENTITY_TO_CLASS(world_items, CWorldItem); +LINK_ENTITY_TO_CLASS(world_items, CWorldItem) void CWorldItem::KeyValue(KeyValueData *pkvd) { @@ -86,7 +86,6 @@ void CWorldItem::Spawn( void ) REMOVE_ENTITY(edict()); } - void CItem::Spawn( void ) { pev->movetype = MOVETYPE_TOSS; @@ -198,9 +197,7 @@ class CItemSuit : public CItem } }; -LINK_ENTITY_TO_CLASS(item_suit, CItemSuit); - - +LINK_ENTITY_TO_CLASS(item_suit, CItemSuit) class CItemBattery : public CItem { @@ -236,17 +233,16 @@ class CItemBattery : public CItem 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; @@ -255,8 +251,7 @@ class CItemBattery : public CItem } }; -LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); - +LINK_ENTITY_TO_CLASS( item_battery, CItemBattery ) class CItemAntidote : public CItem { @@ -279,8 +274,7 @@ class CItemAntidote : public CItem } }; -LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote); - +LINK_ENTITY_TO_CLASS( item_antidote, CItemAntidote ) class CItemSecurity : public CItem { @@ -301,7 +295,7 @@ class CItemSecurity : public CItem } }; -LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); +LINK_ENTITY_TO_CLASS( item_security, CItemSecurity ) class CItemLongJump : public CItem { @@ -339,4 +333,4 @@ class CItemLongJump : public CItem } }; -LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); +LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ) diff --git a/dlls/items.h b/dlls/items.h index e9852966..53395a55 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -15,7 +15,6 @@ #ifndef ITEMS_H #define ITEMS_H - class CItem : public CBaseEntity { public: diff --git a/dlls/leech.cpp b/dlls/leech.cpp index 3ced19ca..8bb9b0c5 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -34,21 +34,16 @@ // 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 @@ -60,15 +55,12 @@ #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: @@ -141,11 +133,9 @@ private: #endif }; +LINK_ENTITY_TO_CLASS( monster_leech, CLeech ) - -LINK_ENTITY_TO_CLASS( monster_leech, CLeech ); - -TYPEDESCRIPTION CLeech::m_SaveData[] = +TYPEDESCRIPTION CLeech::m_SaveData[] = { DEFINE_FIELD( CLeech, m_flTurning, FIELD_FLOAT ), DEFINE_FIELD( CLeech, m_fPathBlocked, FIELD_BOOLEAN ), @@ -161,8 +151,7 @@ TYPEDESCRIPTION CLeech::m_SaveData[] = DEFINE_FIELD( CLeech, m_attackSoundTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ) const char *CLeech::pAttackSounds[] = { @@ -177,7 +166,6 @@ const char *CLeech::pAlertSounds[] = "leech/leech_alert2.wav", }; - void CLeech::Spawn( void ) { Precache(); @@ -185,7 +173,7 @@ void CLeech::Spawn( void ) // Just for fun // SET_MODEL(ENT(pev), "models/icky.mdl"); -// UTIL_SetSize( pev, g_vecZero, g_vecZero ); + //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; @@ -208,14 +196,11 @@ void CLeech::Spawn( void ) m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); } - void CLeech::Activate( void ) { RecalculateWaterlevel(); } - - void CLeech::RecalculateWaterlevel( void ) { // Calculate boundaries @@ -239,7 +224,6 @@ void CLeech::RecalculateWaterlevel( void ) m_waterTime = gpGlobals->time + RANDOM_FLOAT( 5, 7 ); } - void CLeech::SwitchLeechState( void ) { m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); @@ -264,7 +248,6 @@ void CLeech::SwitchLeechState( void ) } } - int CLeech::IRelationship( CBaseEntity *pTarget ) { if ( pTarget->IsPlayer() ) @@ -272,8 +255,6 @@ int CLeech::IRelationship( CBaseEntity *pTarget ) return CBaseMonster::IRelationship( pTarget ); } - - void CLeech::AttackSound( void ) { if ( gpGlobals->time > m_attackSoundTime ) @@ -283,13 +264,11 @@ void CLeech::AttackSound( void ) } } - 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 ) { int i; @@ -303,7 +282,6 @@ void CLeech::Precache( void ) PRECACHE_SOUND((char *)pAlertSounds[i]); } - int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { pev->velocity = g_vecZero; @@ -317,7 +295,6 @@ int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float f return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } - void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) @@ -338,24 +315,20 @@ void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) 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; @@ -363,7 +336,6 @@ void CLeech::MakeVectors( void ) UTIL_MakeVectors ( tmp ); } - // // ObstacleDistance - returns normalized distance to obstacle // @@ -419,7 +391,6 @@ float CLeech::ObstacleDistance( CBaseEntity *pTarget ) return 1.0; } - void CLeech::DeadThink( void ) { if ( m_fSequenceFinished ) @@ -454,8 +425,6 @@ void CLeech::DeadThink( void ) } } - - void CLeech::UpdateMotion( void ) { float flapspeed = (pev->speed - m_flAccelerate) / LEECH_ACCELERATE; @@ -530,7 +499,6 @@ void CLeech::UpdateMotion( void ) } float flInterval = StudioFrameAdvance(); DispatchAnimEvents ( flInterval ); - #if DEBUG_BEAMS if ( !m_pb ) m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); @@ -553,7 +521,6 @@ void CLeech::UpdateMotion( void ) #endif } - void CLeech::SwimThink( void ) { TraceResult tr; @@ -612,9 +579,7 @@ void CLeech::SwimThink( void ) else targetSpeed *= 2; } - break; - default: if ( m_zTime < gpGlobals->time ) { @@ -625,13 +590,13 @@ void CLeech::SwimThink( void ) 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; } @@ -686,7 +651,6 @@ void CLeech::SwimThink( void ) UpdateMotion(); } - void CLeech::Killed(entvars_t *pevAttacker, int iGib) { Vector vecSplatDir; @@ -719,5 +683,3 @@ void CLeech::Killed(entvars_t *pevAttacker, int iGib) pev->takedamage = DAMAGE_NO; SetThink( &CLeech::DeadThink ); } - - diff --git a/dlls/lights.cpp b/dlls/lights.cpp index 312aa30a..18602dc2 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -24,8 +24,6 @@ #include "util.h" #include "cbase.h" - - class CLight : public CPointEntity { public: @@ -42,7 +40,8 @@ private: int m_iStyle; int m_iszPattern; }; -LINK_ENTITY_TO_CLASS( light, CLight ); + +LINK_ENTITY_TO_CLASS( light, CLight ) TYPEDESCRIPTION CLight::m_SaveData[] = { @@ -50,8 +49,7 @@ TYPEDESCRIPTION CLight::m_SaveData[] = DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CLight, CPointEntity ); - +IMPLEMENT_SAVERESTORE( CLight, CPointEntity ) // // Cache user-entity-field values until spawn is called. @@ -96,7 +94,7 @@ void CLight :: Spawn( void ) if (m_iStyle >= 32) { -// CHANGE_METHOD(ENT(pev), em_use, light_use); + //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) @@ -106,7 +104,6 @@ void CLight :: Spawn( void ) } } - void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if (m_iStyle >= 32) @@ -133,8 +130,7 @@ void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT // // shut up spawn functions for new spotlights // -LINK_ENTITY_TO_CLASS( light_spot, CLight ); - +LINK_ENTITY_TO_CLASS( light_spot, CLight ) class CEnvLight : public CLight { @@ -143,7 +139,7 @@ public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ); +LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ) void CEnvLight::KeyValue( KeyValueData* pkvd ) { @@ -182,7 +178,6 @@ void CEnvLight::KeyValue( KeyValueData* pkvd ) } } - void CEnvLight :: Spawn( void ) { char szVector[64]; diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index f6d13343..de14cf39 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -53,8 +53,7 @@ TYPEDESCRIPTION CRuleEntity::m_SaveData[] = DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), }; -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); - +IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ) void CRuleEntity::Spawn( void ) { @@ -63,7 +62,6 @@ void CRuleEntity::Spawn( void ) pev->effects = EF_NODRAW; } - void CRuleEntity::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "master")) @@ -122,7 +120,6 @@ void CRuleBrushEntity::Spawn( void ) CRuleEntity::Spawn(); } - // CGameScore / game_score -- award points to player / team // Points +/- total // Flag: Allow negative scores SF_SCORE_NEGATIVE @@ -147,15 +144,13 @@ public: private: }; -LINK_ENTITY_TO_CLASS( game_score, CGameScore ); - +LINK_ENTITY_TO_CLASS( game_score, CGameScore ) void CGameScore::Spawn( void ) { CRulePointEntity::Spawn(); } - void CGameScore::KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "points")) @@ -167,8 +162,6 @@ void CGameScore::KeyValue( KeyValueData *pkvd ) CRulePointEntity::KeyValue( pkvd ); } - - void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !CanFireForActivator( pActivator ) ) @@ -188,7 +181,6 @@ void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us } } - // CGameEnd / game_end -- Ends the game in MP class CGameEnd : public CRulePointEntity @@ -198,8 +190,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); - +LINK_ENTITY_TO_CLASS( game_end, CGameEnd ) void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -209,16 +200,13 @@ void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT 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: @@ -238,7 +226,7 @@ private: hudtextparms_t m_textParms; }; -LINK_ENTITY_TO_CLASS( game_text, CGameText ); +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. @@ -247,8 +235,7 @@ TYPEDESCRIPTION CGameText::m_SaveData[] = DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), }; -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); - +IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ) void CGameText::KeyValue( KeyValueData *pkvd ) { @@ -316,7 +303,6 @@ void CGameText::KeyValue( KeyValueData *pkvd ) CRulePointEntity::KeyValue( pkvd ); } - void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !CanFireForActivator( pActivator ) ) @@ -335,7 +321,6 @@ void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } } - // // 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 @@ -367,7 +352,7 @@ private: USE_TYPE triggerType; }; -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); +LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ) void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) { @@ -397,7 +382,6 @@ void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) CRulePointEntity::KeyValue( pkvd ); } - void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !CanFireForActivator( pActivator ) ) @@ -424,13 +408,11 @@ void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) { return TeamMatch( pActivator ); } - const char *CGameTeamMaster::TeamID( void ) { if ( m_teamIndex < 0 ) // Currently set to "no team" @@ -439,7 +421,6 @@ const char *CGameTeamMaster::TeamID( void ) 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() ) @@ -451,7 +432,6 @@ BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) 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 @@ -470,8 +450,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); - +LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ) void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -493,7 +472,6 @@ void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } - // // CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired // @@ -515,8 +493,8 @@ private: string_t m_iszOutCount; }; -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = +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 ), @@ -524,7 +502,7 @@ TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); +IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ) void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) { @@ -608,13 +586,12 @@ void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - - // // CGamePlayerHurt / game_player_hurt -- Damages the player who fires it // Flag: Fire once #define SF_PKILL_FIREONCE 0x0001 + class CGamePlayerHurt : public CRulePointEntity { public: @@ -624,8 +601,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); - +LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ) void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -639,7 +615,7 @@ void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY else pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); } - + SUB_UseTargets( pActivator, useType, value ); if ( RemoveOnFire() ) @@ -648,8 +624,6 @@ void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - - // // CGameCounter / game_counter -- Counts events and fires target // Flag: Fire once @@ -671,7 +645,7 @@ public: inline void ResetCount( void ) { pev->frags = pev->dmg; } inline int CountValue( void ) { return pev->frags; } inline int LimitValue( void ) { return pev->health; } - + inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } private: @@ -680,7 +654,7 @@ private: inline void SetInitialValue( int value ) { pev->dmg = value; } }; -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); +LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ) void CGameCounter::Spawn( void ) { @@ -689,7 +663,6 @@ void CGameCounter::Spawn( void ) CRulePointEntity::Spawn(); } - void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !CanFireForActivator( pActivator ) ) @@ -701,11 +674,9 @@ void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE case USE_TOGGLE: CountUp(); break; - case USE_OFF: CountDown(); break; - case USE_SET: SetCountValue( (int)value ); break; @@ -726,8 +697,6 @@ void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } - - // // CGameCounterSet / game_counter_set -- Sets the counter's value // Flag: Fire once @@ -743,8 +712,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); - +LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ) void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -759,7 +727,6 @@ void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - // // CGamePlayerEquip / game_playerequip -- Sets the default player equipment // Flag: USE Only @@ -777,15 +744,13 @@ public: 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 ); - +LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ) void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) { @@ -811,7 +776,6 @@ void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) } } - void CGamePlayerEquip::Touch( CBaseEntity *pOther ) { if ( !CanFireForActivator( pOther ) ) @@ -846,13 +810,11 @@ void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) } } - 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 @@ -869,7 +831,6 @@ 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; } @@ -877,8 +838,7 @@ private: const char *TargetTeamName( const char *pszTargetName ); }; -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); - +LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ) const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) { @@ -893,7 +853,6 @@ const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) return NULL; } - void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !CanFireForActivator( pActivator ) ) @@ -914,5 +873,3 @@ void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY UTIL_Remove( this ); } } - - diff --git a/dlls/maprules.h b/dlls/maprules.h index 57f9939b..70a88fb5 100644 --- a/dlls/maprules.h +++ b/dlls/maprules.h @@ -15,8 +15,5 @@ #ifndef MAPRULES_H #define MAPRULES_H - - - -#endif // MAPRULES_H +#endif //MAPRULES_H diff --git a/dlls/monsterevent.h b/dlls/monsterevent.h index 46c5624a..5d144750 100644 --- a/dlls/monsterevent.h +++ b/dlls/monsterevent.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #ifndef MONSTEREVENT_H #define MONSTEREVENT_H @@ -31,4 +32,4 @@ typedef struct #define MONSTER_EVENT_SWISHSOUND 2010 -#endif // MONSTEREVENT_H +#endif //MONSTEREVENT_H diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index dcfe42db..ca893969 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -51,7 +51,6 @@ public: 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. @@ -62,9 +61,9 @@ public: BOOL m_fFadeChildren;// should we make the children fadeout? }; -LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ); +LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ) -TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = +TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = { DEFINE_FIELD( CMonsterMaker, m_iszMonsterClassname, FIELD_STRING ), DEFINE_FIELD( CMonsterMaker, m_cNumMonsters, FIELD_INTEGER ), @@ -75,12 +74,10 @@ TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ), }; - -IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ) void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) { - if ( FStrEq(pkvd->szKeyName, "monstercount") ) { m_cNumMonsters = atoi(pkvd->szValue); @@ -100,7 +97,6 @@ void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } - void CMonsterMaker :: Spawn( ) { pev->solid = SOLID_NOT; @@ -119,21 +115,24 @@ void CMonsterMaker :: Spawn( ) } if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) - {// start making monsters as soon as monstermaker spawns + { + // start making monsters as soon as monstermaker spawns m_fActive = TRUE; SetThink( &CMonsterMaker::MakerThink ); } else - {// wait to be activated. + { + // wait to be activated. m_fActive = FALSE; SetThink( &CBaseEntity::SUB_DoNothing ); } } else - {// no targetname, just start. - pev->nextthink = gpGlobals->time + m_flDelay; - m_fActive = TRUE; - SetThink( &CMonsterMaker::MakerThink ); + { + // no targetname, just start. + pev->nextthink = gpGlobals->time + m_flDelay; + m_fActive = TRUE; + SetThink( &CMonsterMaker::MakerThink ); } if ( m_cNumMonsters == 1 ) @@ -164,7 +163,8 @@ void CMonsterMaker::MakeMonster( void ) 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. + { + // not allowed to make a new one yet. Too many live ones out right now. return; } @@ -275,7 +275,6 @@ void CMonsterMaker :: MakerThink ( void ) MakeMonster(); } - //========================================================= //========================================================= void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) @@ -288,5 +287,3 @@ void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) pevChild->owner = NULL; } } - - diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index 21901b0c..da565e6c 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -36,7 +36,6 @@ #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; @@ -45,8 +44,6 @@ extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser b 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) @@ -74,15 +71,15 @@ TYPEDESCRIPTION CBaseMonster::m_SaveData[] = 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_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 ), + //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 ), @@ -110,7 +107,8 @@ TYPEDESCRIPTION CBaseMonster::m_SaveData[] = DEFINE_FIELD( CBaseMonster, m_pCine, FIELD_CLASSPTR ), }; -//IMPLEMENT_SAVERESTORE( CBaseMonster, CBaseToggle ); +//IMPLEMENT_SAVERESTORE( CBaseMonster, CBaseToggle ) + int CBaseMonster::Save( CSave &save ) { if ( !CBaseToggle::Save(save) ) @@ -141,7 +139,6 @@ int CBaseMonster::Restore( CRestore &restore ) return status; } - //========================================================= // Eat - makes a monster full for a little while. //========================================================= @@ -244,7 +241,7 @@ void CBaseMonster :: Listen ( void ) 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 ( 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. @@ -258,14 +255,13 @@ void CBaseMonster :: Listen ( void ) SetConditions( bits_COND_SMELL ); } } - -// m_afSoundTypes |= g_pSoundEnt->m_SoundPool[ iSound ].m_iType; + //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 = g_pSoundEnt->m_SoundPool[ iSound ].m_iNext; iSound = pCurrentSound->m_iNext; } } @@ -341,6 +337,7 @@ void CBaseMonster :: Look ( int iDistance ) 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 ) ) { @@ -393,7 +390,7 @@ void CBaseMonster :: Look ( int iDistance ) } } } - + SetConditions( iSighted ); } @@ -512,8 +509,6 @@ CSound* CBaseMonster :: PBestScent ( void ) return NULL; } - - //========================================================= // Monster Think - calls out to core AI functions and handles this // monster's specific animation events @@ -522,13 +517,13 @@ 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. + + // 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; @@ -671,22 +666,18 @@ BOOL CBaseMonster :: FRefreshRoute ( void ) } 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 != NULL) { returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); } break; - case MOVEGOAL_NODE: returnCode = FGetNodeRoute( m_vecMoveGoal ); // if ( returnCode ) @@ -707,28 +698,25 @@ BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) 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; @@ -739,7 +727,6 @@ BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vecto return FRefreshRoute(); } - #ifdef _DEBUG void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ) { @@ -780,7 +767,6 @@ void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, 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 ); @@ -807,7 +793,6 @@ void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, i } #endif - int ShouldSimplify( int routeType ) { routeType &= ~bits_MF_IS_GOAL; @@ -845,7 +830,7 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) // Can't simplify a direct route! if ( count < 2 ) { -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); + //DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); return; } @@ -900,12 +885,12 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) 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 + // Copy the simplified route, disable for testing m_iRouteIndex = 0; for ( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) { @@ -1009,7 +994,7 @@ void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) // 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 ); @@ -1061,7 +1046,7 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) iUpdatedLKP = FALSE; ClearConditions ( bits_COND_ENEMY_FACING_ME ); - + if ( !FVisible( pEnemy ) ) { ASSERT(!HasConditions(bits_COND_SEE_ENEMY)); @@ -1078,9 +1063,11 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) } 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) @@ -1247,11 +1234,9 @@ void CBaseMonster :: SetActivity ( Activity NewActivity ) } 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; - - } //========================================================= @@ -1306,8 +1291,7 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn 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. @@ -1322,7 +1306,7 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn //pev->origin.z = vecStartPos.z;//!!!HACKHACK -// pev->origin = vecStart; + //pev->origin = vecStart; /* if ( flDist > 1024 ) @@ -1343,12 +1327,12 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn if ( (flStep + LOCAL_STEP_SIZE) >= (flDist-1) ) stepSize = (flDist - flStep) - 1; - -// UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); + + //UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) - {// can't take the next step, fail! - + { + // can't take the next step, fail! if ( pflDist != NULL ) { *pflDist = flStep; @@ -1362,9 +1346,9 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn 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 + //if ( pTarget && fabs( flDist - iStep ) < LOCAL_STEP_SIZE ) + // fReturn = TRUE; + //else iReturn = LOCALMOVE_INVALID; break; } @@ -1399,7 +1383,6 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn return iReturn; } - float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { float flTravelTime = 0; @@ -1442,7 +1425,6 @@ float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) return gpGlobals->time + flTravelTime; } - //========================================================= // AdvanceRoute - poorly named function that advances the // m_iRouteIndex. If it goes beyond ROUTE_SIZE, the route @@ -1490,7 +1472,7 @@ void CBaseMonster :: AdvanceRoute ( float distance ) if (pevDoor) { m_flMoveWaitFinished = OpenDoorAndWait( pevDoor ); -// ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); + //ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); } } } @@ -1508,7 +1490,6 @@ void CBaseMonster :: AdvanceRoute ( float distance ) } } - int CBaseMonster :: RouteClassify( int iMoveFlag ) { int movementGoal; @@ -1541,11 +1522,11 @@ BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEnt RouteNew(); m_movementGoal = RouteClassify( iMoveFlag ); -// so we don't end up with no moveflags + // 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 + // check simple local move iLocalMove = CheckLocalMove( pev->origin, vecGoal, pTarget, &flDist ); if ( iLocalMove == LOCALMOVE_VALID ) @@ -1553,7 +1534,8 @@ BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEnt // monster can walk straight there! return TRUE; } -// try to triangulate around any obstacles. + + // 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 @@ -1562,7 +1544,6 @@ BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEnt 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); @@ -1573,15 +1554,14 @@ BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEnt WRITE_COORD(MSG_BROADCAST, vecApex.y ); WRITE_COORD(MSG_BROADCAST, vecApex.z + 128 ); */ - RouteSimplify( pTarget ); return TRUE; } -// last ditch, try nodes + // last ditch, try nodes if ( FGetNodeRoute( vecGoal ) ) { -// ALERT ( at_console, "Can get there on nodes\n" ); + //ALERT ( at_console, "Can get there on nodes\n" ); m_vecMoveGoal = vecGoal; RouteSimplify( pTarget ); return TRUE; @@ -1602,7 +1582,6 @@ 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 @@ -1666,7 +1645,7 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn } vecFarSide = m_Route[ m_iRouteIndex ].vecLocation; - + vecDir = vecDir * sizeX * 2; if (pev->movetype == MOVETYPE_FLY) vecDirUp = vecDirUp * sizeZ * 2; @@ -1695,7 +1674,6 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn WRITE_COORD( vecLeft.z ); MESSAGE_END(); #endif - #if 0 if (pev->movetype == MOVETYPE_FLY) { @@ -1720,7 +1698,6 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn MESSAGE_END(); } #endif - if ( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { if ( CheckLocalMove ( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) @@ -1816,7 +1793,7 @@ void CBaseMonster :: Move ( float flInterval ) return; } } - + if ( m_flMoveWaitFinished > gpGlobals->time ) return; @@ -1835,7 +1812,6 @@ void CBaseMonster :: Move ( float flInterval ) // 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; @@ -1843,7 +1819,7 @@ void CBaseMonster :: Move ( float flInterval ) // 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 ); @@ -1856,7 +1832,7 @@ void CBaseMonster :: Move ( float flInterval ) { 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 ) @@ -1877,6 +1853,7 @@ void CBaseMonster :: Move ( float flInterval ) // Can't move, stop Stop(); + // Blocking entity is in global trace_ent pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); if (pBlocker) @@ -1905,8 +1882,9 @@ void CBaseMonster :: Move ( float flInterval ) } else { -// ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); + //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) ) { @@ -1964,7 +1942,6 @@ void CBaseMonster :: Move ( float flInterval ) } } - BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { if ( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) @@ -1976,11 +1953,10 @@ BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) 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 ); + //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; @@ -1996,7 +1972,6 @@ void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f // 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, @@ -2010,7 +1985,7 @@ 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)); + //REMOVE_ENTITY(ENT(pev)); return; } @@ -2087,6 +2062,7 @@ void CBaseMonster :: StartMonster ( void ) { 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 ) ) { @@ -2121,12 +2097,11 @@ void CBaseMonster :: StartMonster ( void ) 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 @@ -2140,7 +2115,7 @@ void CBaseMonster :: StartMonster ( void ) ChangeSchedule( GetScheduleOfType( SCHED_IDLE_WALK ) ); } } - + //SetState ( m_IdealMonsterState ); //SetActivity ( m_IdealActivity ); @@ -2148,7 +2123,7 @@ void CBaseMonster :: StartMonster ( void ) // 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 ); @@ -2158,7 +2133,6 @@ void CBaseMonster :: StartMonster ( void ) } } - void CBaseMonster :: MovementComplete( void ) { switch( m_iTaskStatus ) @@ -2167,22 +2141,18 @@ void CBaseMonster :: MovementComplete( void ) 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 && @@ -2328,7 +2298,6 @@ BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float f 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. @@ -2414,8 +2383,6 @@ BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, return FALSE; } - - //========================================================= // BestVisibleEnemy - this functions searches the link // list whose head is the caller's m_pLink field, and returns @@ -2473,7 +2440,6 @@ CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) return pReturn; } - //========================================================= // MakeIdealYaw - gets a yaw value for the caller that would // face the supplied vector. Value is stuffed into the monster's @@ -2482,7 +2448,7 @@ CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { Vector vecProjection; - + // strafing monster needs to face 90 degrees away from its goal if ( m_movementActivity == ACT_STRAFE_LEFT ) { @@ -2521,11 +2487,9 @@ float CBaseMonster::FlYawDiff ( void ) return 0; } - return UTIL_AngleDiff( pev->ideal_yaw, flCurrentYaw ); } - //========================================================= // Changeyaw - turns a monster towards its ideal_yaw //========================================================= @@ -2552,16 +2516,18 @@ float CBaseMonster::ChangeYaw ( int yawSpeed ) } if (move > 0) - {// turning to the monster's left + { + // turning to the monster's left if (move > speed) move = speed; } else - {// turning to the monster's right + { + // 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 @@ -2592,7 +2558,6 @@ float CBaseMonster::VecToYaw ( Vector vecDir ) return UTIL_VecToYaw( vecDir ); } - //========================================================= // SetEyePosition // @@ -2638,19 +2603,17 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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; @@ -2658,27 +2621,22 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ) { @@ -2692,7 +2650,6 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } break; - case MONSTER_EVENT_BODYDROP_LIGHT: if ( pev->flags & FL_ONGROUND ) { @@ -2706,24 +2663,19 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } 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); @@ -2739,18 +2691,10 @@ Vector CBaseMonster :: GetGunPosition( ) return vecSrc; } - - - - //========================================================= // NODE GRAPH //========================================================= - - - - //========================================================= // FGetNodeRoute - tries to build an entire node path from // the callers origin to the passed vector. If this is @@ -2773,13 +2717,13 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) if ( iSrcNode == -1 ) { // no node nearest self -// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); + //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" ); + //ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near target!\n" ); return FALSE; } @@ -2823,13 +2767,13 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { 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; @@ -2885,8 +2829,7 @@ int CBaseMonster :: FindHintNode ( void ) WorldGraph.m_iLastActiveIdleSearch = 0;// start at the top of the list for the next search. return NO_NODE; -} - +} void CBaseMonster::ReportAIState( void ) { @@ -3122,7 +3065,6 @@ int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptL return FALSE; } - //========================================================= // FindLateralCover - attempts to locate a spot in the world // directly to the left or right of the caller that will @@ -3144,7 +3086,7 @@ BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &v UTIL_MakeVectors ( pev->angles ); vecStepRight = gpGlobals->v_right * COVER_DELTA; vecStepRight.z = 0; - + vecLeftTest = vecRightTest = pev->origin; for ( i = 0 ; i < COVER_CHECKS ; i++ ) @@ -3184,7 +3126,6 @@ BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &v return FALSE; } - Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { CBaseEntity *pEnemy = m_hEnemy; @@ -3197,8 +3138,6 @@ Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) return gpGlobals->v_forward; } - - //========================================================= // FacingIdeal - tells us if a monster is facing its ideal // yaw. Created this function because many spots in the @@ -3230,7 +3169,6 @@ BOOL CBaseMonster :: FCanActiveIdle ( void ) return FALSE; } - void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { if ( pszSentence && IsAlive() ) @@ -3242,19 +3180,16 @@ void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float } } - 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 ) @@ -3279,11 +3214,11 @@ void CBaseMonster :: MonsterInitDead( void ) 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 ); @@ -3408,7 +3343,6 @@ BOOL CBaseMonster :: GetEnemy ( void ) return FALSE;// monster has no enemy } - //========================================================= // DropItem - dead monster drops named item //========================================================= @@ -3437,7 +3371,6 @@ CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, } - BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { // if flagged to fade out or I have an owner (I came from a monster spawner) diff --git a/dlls/monsters.h b/dlls/monsters.h index f7f1a03f..bf30ffcc 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -39,7 +39,6 @@ #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 @@ -58,13 +57,10 @@ #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 @@ -92,7 +88,6 @@ BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTarget #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. @@ -123,7 +118,7 @@ enum AITRIGGER_HEARPLAYER, AITRIGGER_HEARCOMBAT, AITRIGGER_SEEPLAYER_UNCONDITIONAL, - AITRIGGER_SEEPLAYER_NOT_IN_COMBAT, + AITRIGGER_SEEPLAYER_NOT_IN_COMBAT }; /* 0 : "No Trigger" @@ -161,7 +156,6 @@ public: float m_lifeTime; }; - #define CUSTOM_SCHEDULES\ virtual Schedule_t *ScheduleFromName( const char *pName );\ static Schedule_t *m_scheduleList[]; @@ -178,6 +172,4 @@ public: return pSchedule;\ } - - #endif //MONSTERS_H diff --git a/dlls/monsterstate.cpp b/dlls/monsterstate.cpp index 3c1620aa..b40af733 100644 --- a/dlls/monsterstate.cpp +++ b/dlls/monsterstate.cpp @@ -37,13 +37,11 @@ void CBaseMonster :: SetState ( MONSTERSTATE State ) ALERT ( at_aiconsole, "State Changed to %d\n", State ); } */ - switch( State ) { - + // Drop enemy pointers when going to idle case MONSTERSTATE_IDLE: - if ( m_hEnemy != NULL ) { m_hEnemy = NULL;// not allowed to have an enemy anymore. @@ -128,7 +126,6 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) switch ( m_MonsterState ) { case MONSTERSTATE_IDLE: - /* IDLE goes to ALERT upon hearing a sound -IDLE goes to ALERT upon being injured @@ -225,7 +222,6 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) ExitScriptedSequence(); // This will set the ideal state } break; - case MONSTERSTATE_DEAD: m_IdealMonsterState = MONSTERSTATE_DEAD; break; @@ -235,4 +231,3 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) return m_IdealMonsterState; } - diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index 43d68d42..54c05f25 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -53,9 +53,9 @@ public: int m_fControl; }; -LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField ); +LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField ) -TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = +TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = { DEFINE_FIELD( CFuncMortarField, m_iszXController, FIELD_STRING ), DEFINE_FIELD( CFuncMortarField, m_iszYController, FIELD_STRING ), @@ -65,8 +65,7 @@ TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = DEFINE_FIELD( CFuncMortarField, m_fControl, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ); - +IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ) void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) { @@ -97,7 +96,6 @@ void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) } } - // Drop bombs from above void CFuncMortarField :: Spawn( void ) { @@ -109,7 +107,6 @@ void CFuncMortarField :: Spawn( void ) Precache(); } - void CFuncMortarField :: Precache( void ) { PRECACHE_SOUND ("weapons/mortar.wav"); @@ -117,7 +114,6 @@ void CFuncMortarField :: Precache( void ) 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 ) { @@ -188,7 +184,6 @@ void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller } } - class CMortar : public CGrenade { public: @@ -200,7 +195,7 @@ public: int m_spriteTexture; }; -LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ); +LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ) void CMortar::Spawn( ) { @@ -213,11 +208,8 @@ void CMortar::Spawn( ) pev->nextthink = 0; Precache( ); - - } - void CMortar::Precache( ) { m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" ); @@ -278,7 +270,6 @@ void CMortar::MortarExplode( void ) 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); @@ -303,10 +294,8 @@ void CMortar::MortarExplode( void ) SetThink( &SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; #endif - } - #if 0 void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) { diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 789c264e..850bf549 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -32,14 +32,11 @@ enum mp5_e MP5_DEPLOY, MP5_FIRE1, MP5_FIRE2, - MP5_FIRE3, + MP5_FIRE3 }; - - -LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); -LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); - +LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ) +LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ) //========================================================= //========================================================= @@ -60,7 +57,6 @@ void CMP5::Spawn( ) FallInit();// get ready to fall down. } - void CMP5::Precache( void ) { PRECACHE_MODEL("models/v_9mmAR.mdl"); @@ -124,7 +120,6 @@ BOOL CMP5::Deploy( ) return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); } - void CMP5::PrimaryAttack() { // don't fire underwater @@ -147,7 +142,6 @@ void CMP5::PrimaryAttack() m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; // player "shoot" animation @@ -156,7 +150,6 @@ void CMP5::PrimaryAttack() Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; - #ifdef CLIENT_DLL if ( !bIsMultiplayer() ) #else @@ -172,13 +165,12 @@ void CMP5::PrimaryAttack() 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; + 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) @@ -193,8 +185,6 @@ void CMP5::PrimaryAttack() m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } - - void CMP5::SecondaryAttack( void ) { // don't fire underwater @@ -235,7 +225,6 @@ void CMP5::SecondaryAttack( void ) #else flags = 0; #endif - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; @@ -255,7 +244,6 @@ void CMP5::Reload( void ) DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); } - void CMP5::WeaponIdle( void ) { ResetEmptySound( ); @@ -283,8 +271,6 @@ void CMP5::WeaponIdle( void ) m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. } - - class CMP5AmmoClip : public CBasePlayerAmmo { void Spawn( void ) @@ -308,10 +294,9 @@ class CMP5AmmoClip : public CBasePlayerAmmo return bResult; } }; -LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ); -LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ); - +LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ) +LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ) class CMP5Chainammo : public CBasePlayerAmmo { @@ -336,8 +321,8 @@ class CMP5Chainammo : public CBasePlayerAmmo return bResult; } }; -LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ); +LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ) class CMP5AmmoGrenade : public CBasePlayerAmmo { @@ -363,23 +348,6 @@ class CMP5AmmoGrenade : public CBasePlayerAmmo return bResult; } }; -LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ); -LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ); - - - - - - - - - - - - - - - - - +LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ) +LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ) diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index 29d2ef30..edfaee5d 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -13,7 +13,6 @@ * ****/ - #include "extdll.h" #include "util.h" #include "cbase.h" @@ -22,12 +21,10 @@ #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; } @@ -37,15 +34,12 @@ 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 ) @@ -58,6 +52,7 @@ void CBaseMonster::CorpseFallThink( void ) else pev->nextthink = gpGlobals->time + 0.1; } + // Call after animation/pose is set up void CBaseMonster :: MonsterInitDead( void ) { @@ -83,7 +78,6 @@ void CBaseMonster :: MonsterInitDead( void ) pev->nextthink = gpGlobals->time + 0.5; } - BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; @@ -122,7 +116,6 @@ int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) return iEnemy[ Classify() ][ pTarget->Classify() ]; } - //========================================================= // Look - Base class monster function to find enemies or // food by sight. iDistance is distance ( in units ) that the @@ -205,7 +198,6 @@ void CBaseMonster :: Look ( int iDistance ) SetConditions( iSighted ); } - //========================================================= // BestVisibleEnemy - this functions searches the link // list whose head is the caller's m_pLink field, and returns diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 9b505549..fead70cf 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -15,6 +15,7 @@ // // teamplay_gamerules.cpp // + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -63,8 +64,8 @@ public: return true; } }; -static CMultiplayGameMgrHelper g_GameMgrHelper; +static CMultiplayGameMgrHelper g_GameMgrHelper; //********************************************************* // Rules for the half-life multiplayer game. @@ -125,7 +126,6 @@ BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) return TRUE; #endif - return CGameRules::ClientCommand(pPlayer, pcmd); } @@ -133,10 +133,10 @@ BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) //========================================================= void CHalfLifeMultiplay::RefreshSkillData( void ) { -// load all default values + // load all default values CGameRules::RefreshSkillData(); -// override some values for multiplay. + // override some values for multiplay. // suitcharger gSkillData.suitchargerCapacity = 30; @@ -283,7 +283,6 @@ void CHalfLifeMultiplay :: Think ( void ) last_time = time_remaining; } - //========================================================= //========================================================= BOOL CHalfLifeMultiplay::IsMultiplayer( void ) @@ -616,7 +615,6 @@ int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *p return 1; } - //========================================================= // PlayerKilled - someone/something killed this player //========================================================= @@ -626,7 +624,6 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille pVictim->m_iDeaths += 1; - FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); CBasePlayer *peKiller = NULL; CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); @@ -634,7 +631,8 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille peKiller = (CBasePlayer*)ktmp; if ( pVictim->pev == pKiller ) - { // killed self + { + // killed self pKiller->frags -= 1; } else if ( ktmp && ktmp->IsPlayer() ) @@ -645,7 +643,8 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE, 0 ); } else - { // killed by the world + { + // killed by the world pKiller->frags -= 1; } @@ -1014,7 +1013,6 @@ int CHalfLifeMultiplay::ItemShouldRespawn( CItem *pItem ) return GR_ITEM_RESPAWN_YES; } - //========================================================= // At what time in the future may this Item respawn? //========================================================= @@ -1081,7 +1079,6 @@ float CHalfLifeMultiplay::FlHealthChargerRechargeTime( void ) return 60; } - float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) { return 30; @@ -1112,7 +1109,6 @@ edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) return pentSpawnSpot; } - //========================================================= //========================================================= int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) @@ -1228,13 +1224,13 @@ 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) <= ' ') @@ -1243,17 +1239,16 @@ skipwhite: return NULL; // end of file; data++; } - -// skip // comments + + // skip // comments if (c=='/' && data[1] == '/') { while (*data && *data != '\n') data++; goto skipwhite; } - -// handle quoted strings specially + // handle quoted strings specially if (c == '\"') { data++; @@ -1270,7 +1265,7 @@ skipwhite: } } -// parse single characters + // parse single characters if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) { com_token[len] = c; @@ -1279,7 +1274,7 @@ skipwhite: return data+1; } -// parse a regular word + // parse a regular word do { com_token[len] = c; @@ -1289,7 +1284,7 @@ skipwhite: if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) break; } while (c>32); - + com_token[len] = 0; return data; } @@ -1317,8 +1312,6 @@ int COM_TokenWaiting( char *buffer ) return 0; } - - /* ============== ReloadMapCycleFile @@ -1440,7 +1433,7 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) item = item->next; } item->next = cycle->items; - + cycle->next_item = item->next; return 1; @@ -1483,7 +1476,7 @@ 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 + // work without stomping on each other char *o; if ( *s == '\\' ) @@ -1680,7 +1673,7 @@ void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) { char chunk[MAX_MOTD_CHUNK+1]; - + if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) { strcpy( chunk, pFileList ); @@ -1705,5 +1698,3 @@ void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) FREE_FILE( aFileList ); } - - diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index cacb61a2..7b6e6331 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -80,7 +80,7 @@ public: 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; @@ -131,9 +131,9 @@ public: EHANDLE m_hFriend[3]; }; -LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ); +LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ) -TYPEDESCRIPTION CNihilanth::m_SaveData[] = +TYPEDESCRIPTION CNihilanth::m_SaveData[] = { DEFINE_FIELD( CNihilanth, m_flForce, FIELD_FLOAT ), DEFINE_FIELD( CNihilanth, m_flNextPainSound, FIELD_TIME ), @@ -167,7 +167,7 @@ TYPEDESCRIPTION CNihilanth::m_SaveData[] = DEFINE_ARRAY( CNihilanth, m_hFriend, FIELD_EHANDLE, 3 ), }; -IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ) class CNihilanthHVR : public CBaseMonster { @@ -214,10 +214,9 @@ public: int m_nFrames; }; -LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ); +LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ) - -TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = +TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = { DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ), DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ), @@ -226,9 +225,7 @@ TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = DEFINE_FIELD( CNihilanthHVR, m_nFrames, FIELD_INTEGER ), }; - -IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ) //========================================================= // Nihilanth, final Boss monster @@ -275,7 +272,6 @@ const char *CNihilanth::pDeathSounds[] = "X/x_die1.wav", }; - void CNihilanth :: Spawn( void ) { Precache( ); @@ -325,7 +321,6 @@ void CNihilanth :: Spawn( void ) */ } - void CNihilanth::Precache( void ) { PRECACHE_MODEL("models/nihilanth.mdl"); @@ -344,8 +339,6 @@ void CNihilanth::Precache( void ) PRECACHE_SOUND("debris/beamstart7.wav"); } - - void CNihilanth :: PainSound( void ) { if (m_flNextPainSound > gpGlobals->time) @@ -368,14 +361,12 @@ 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 ); @@ -383,7 +374,6 @@ void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ SetUse( &CNihilanth::CommandUse ); } - void CNihilanth::StartupThink( void ) { m_irritation = 0; @@ -415,7 +405,6 @@ void CNihilanth::StartupThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - void CNihilanth :: Killed( entvars_t *pevAttacker, int iGib ) { CBaseMonster::Killed( pevAttacker, iGib ); @@ -537,8 +526,6 @@ void CNihilanth :: DyingThink( void ) return; } - - void CNihilanth::CrashTouch( CBaseEntity *pOther ) { // only crash if we hit something solid @@ -549,15 +536,11 @@ void CNihilanth::CrashTouch( CBaseEntity *pOther ) } } - - 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) @@ -586,13 +569,12 @@ void CNihilanth :: FloatSequence( void ) } } - void CNihilanth :: ShootBalls( void ) { if (m_flShootEnd > gpGlobals->time) { Vector vecHand, vecAngle; - + while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) { if (m_hEnemy != NULL) @@ -623,7 +605,6 @@ void CNihilanth :: ShootBalls( void ) } } - void CNihilanth :: MakeFriend( Vector vecStart ) { int i; @@ -673,7 +654,6 @@ void CNihilanth :: MakeFriend( Vector vecStart ) } } - void CNihilanth :: NextActivity( ) { UTIL_MakeAimVectors( pev->angles ); @@ -730,7 +710,7 @@ void CNihilanth :: NextActivity( ) pRecharger = pEnt; } } - + if (pRecharger) { m_hRecharger = pRecharger; @@ -899,8 +879,6 @@ void CNihilanth :: HuntThink( void ) Flight( ); } - - void CNihilanth :: Flight( void ) { // estimate where I'll be facing in one seconds @@ -935,7 +913,6 @@ void CNihilanth :: Flight( void ) 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) @@ -950,7 +927,7 @@ void CNihilanth :: Flight( void ) // general drag m_velocity = m_velocity * 0.995; - + // apply power to stay correct height if (m_flForce < 100 && vecEst.z < m_posDesired.z) { @@ -968,7 +945,6 @@ void CNihilanth :: Flight( void ) // 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++) @@ -985,7 +961,6 @@ BOOL CNihilanth :: AbsorbSphere( void ) return FALSE; } - BOOL CNihilanth :: EmitSphere( void ) { m_iActiveSpheres = 0; @@ -1015,8 +990,7 @@ BOOL CNihilanth :: EmitSphere( void ) return TRUE; } - -void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) +void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) { int i; CBaseMonster *pSphere; @@ -1041,8 +1015,6 @@ void CNihilanth :: TargetSphere( USE_TYPE useType, float 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 ) @@ -1084,7 +1056,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) WRITE_BYTE( 10 ); // life * 10 WRITE_COORD( 128 ); // decay MESSAGE_END(); - + m_flShootTime = gpGlobals->time; m_flShootEnd = gpGlobals->time + 1.0; } @@ -1189,8 +1161,6 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } - - void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { switch (useType) @@ -1215,7 +1185,6 @@ void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ } } - int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { if (pevInflictor->owner == edict()) @@ -1227,15 +1196,13 @@ int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f 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) @@ -1255,8 +1222,6 @@ void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } - - CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) { int total = 0; @@ -1272,20 +1237,10 @@ CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) return pEntity; } - - - - - - - - //========================================================= // Controller bouncy ball attack //========================================================= - - void CNihilanthHVR :: Spawn( void ) { Precache( ); @@ -1295,7 +1250,6 @@ void CNihilanthHVR :: Spawn( void ) pev->scale = 3.0; } - void CNihilanthHVR :: Precache( void ) { PRECACHE_MODEL("sprites/flare6.spr"); @@ -1310,8 +1264,6 @@ void CNihilanthHVR :: Precache( void ) PRECACHE_SOUND("x/x_teleattack1.wav"); } - - void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) { pev->movetype = MOVETYPE_NOCLIP; @@ -1338,7 +1290,6 @@ void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) m_hTargetEnt = pTarget; } - CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) { int total = 0; @@ -1416,9 +1367,6 @@ void CNihilanthHVR :: HoverThink( void ) pev->frame = ((int)pev->frame + 1) % m_nFrames; } - - - void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) { pev->movetype = MOVETYPE_FLY; @@ -1458,7 +1406,6 @@ void CNihilanthHVR :: ZapThink( void ) pev->velocity = pev->velocity * 1.2; } - // MovetoTarget( m_hEnemy->Center( ) ); if ((m_hEnemy->Center() - pev->origin).Length() < 256) @@ -1521,7 +1468,6 @@ void CNihilanthHVR :: ZapThink( void ) // Crawl( ); } - void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) { UTIL_EmitAmbientSound( edict(), pev->origin, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, RANDOM_LONG( 90, 95 ) ); @@ -1541,8 +1487,6 @@ void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) pev->nextthink = gpGlobals->time + 0.2; } - - void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) { pev->movetype = MOVETYPE_FLY; @@ -1567,7 +1511,6 @@ void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBa EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); } - void CNihilanthHVR :: GreenBallInit( ) { pev->movetype = MOVETYPE_FLY; @@ -1583,7 +1526,6 @@ void CNihilanthHVR :: GreenBallInit( ) SetTouch( &CNihilanthHVR::RemoveTouch ); } - void CNihilanthHVR :: TeleportThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -1629,7 +1571,6 @@ void CNihilanthHVR :: TeleportThink( void ) pev->frame = (int)(pev->frame + 1) % 20; } - void CNihilanthHVR :: AbsorbInit( void ) { SetThink( &CNihilanthHVR::DissipateThink ); @@ -1675,7 +1616,6 @@ void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) UTIL_Remove( this ); } - void CNihilanthHVR :: DissipateThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -1710,7 +1650,6 @@ void CNihilanthHVR :: DissipateThink( void ) MESSAGE_END(); } - BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) { BOOL fClose = FALSE; @@ -1765,7 +1704,6 @@ BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) return fClose; } - void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) { if (m_vecIdeal == Vector( 0, 0, 0 )) @@ -1783,12 +1721,8 @@ void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) 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; @@ -1812,7 +1746,6 @@ void CNihilanthHVR :: Crawl( void ) MESSAGE_END(); } - void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) { STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); @@ -1831,7 +1764,4 @@ void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) m_vecIdeal = vecDir * m_vecIdeal.Length(); } - - - #endif diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index d512e54c..368ba7b3 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -38,8 +38,8 @@ Vector VecBModelOrigin( entvars_t* pevBModel ); CGraph WorldGraph; -LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); -LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); +LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ) +LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ) #if defined _LINUX && !defined _WIN32 #include #include @@ -52,7 +52,6 @@ LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); //========================================================= void CGraph :: InitGraph( void) { - // Make the graph unavailable // m_fGraphPresent = FALSE; @@ -112,10 +111,10 @@ void CGraph :: InitGraph( void) //========================================================= int CGraph :: AllocNodes ( void ) { -// malloc all of the nodes + // malloc all of the nodes WorldGraph.m_pNodes = (CNode *)calloc ( sizeof ( CNode ), MAX_NODES ); -// could not malloc space for all the 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 ); @@ -145,21 +144,21 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) 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 + { + // door is use only, so the door is all the monster has to worry about return pevLinkEnt; } @@ -168,7 +167,8 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) pentTrigger = FIND_ENTITY_BY_TARGET ( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger if ( FNullEnt( pentTrigger ) ) - {// no trigger found + { + // 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 @@ -180,7 +180,8 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) pevTrigger = VARS( pentTrigger ); if ( FClassnameIs(pevTrigger, "func_button") || FClassnameIs(pevTrigger, "func_rot_button" ) ) - {// only buttons are handled right now. + { + // 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! @@ -188,7 +189,8 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) if ( VARS(tr.pHit) == pevTrigger ) - {// good to go! + { + // good to go! return VARS( tr.pHit ); } } @@ -214,7 +216,8 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N TraceResult tr; if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available + { + // protect us in the case that the node graph isn't available ALERT ( at_aiconsole, "Graph not ready!\n" ); return FALSE; } @@ -226,17 +229,18 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N } pentWorld = NULL; -// func_door + // func_door if ( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) - {// ent is a door. - + { + // ent is a door. pDoor = ( CBaseEntity::Instance( pevLinkEnt ) ); if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) - {// door is use only. - + { + // door is use only. if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - {// let monster right through if he can open doors + { + // let monster right through if he can open doors return TRUE; } else @@ -251,7 +255,8 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N } } else - {// door must be opened with a button or trigger field. + { + // 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 ) ) @@ -267,7 +272,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N return FALSE; } } -// func_breakable + // func_breakable else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) { return TRUE; @@ -313,8 +318,8 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, 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 + // 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++ ) @@ -322,7 +327,8 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, vecSpot1 = m_pNodes[ i ].m_vecOrigin; if ( m_pNodes[ i ].m_cNumLinks <= 0 ) - {// this shouldn't happen! + { + // this shouldn't happen! ALERT ( at_aiconsole, "**Node %d has no links\n", i ); continue; } @@ -358,48 +364,51 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, // 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 + { + // point outside of line flDistToLine = ( vec2TestPoint - vec2Spot1 ).Length(); fCurrentAlongLine = FALSE; } else if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) - {// point outside of line + { + // point outside of line flDistToLine = ( vec2TestPoint - vec2Spot2 ).Length(); fCurrentAlongLine = FALSE; } else - {// point inside line + { + // point inside line flDistToLine = fabs( DotProduct ( vec2TestPoint - vec2Spot2, vec2Normal ) ); fCurrentAlongLine = TRUE; } if ( flDistToLine < flMinDist ) - {// just found a line nearer than any other so far - + { + // 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 - + { + // 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! + { + // can't use this link, cause can't see either node! continue; } - } fSuccess = TRUE;// we know there will be something to return. @@ -410,7 +419,6 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, } } } - /* if ( fSuccess ) { @@ -426,11 +434,9 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, 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 ) @@ -445,12 +451,11 @@ int CGraph::HullIndex( const CBaseEntity *pEntity ) else if ( pEntity->pev->mins == Vector ( -32, -32, 0 ) ) return NODE_LARGE_HULL; -// ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); + //ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); return NODE_HUMAN_HULL; } - -int CGraph::NodeType( const CBaseEntity *pEntity ) +int CGraph::NodeType( const CBaseEntity *pEntity ) { if ( pEntity->pev->movetype == MOVETYPE_FLY) { @@ -466,7 +471,6 @@ int CGraph::NodeType( const CBaseEntity *pEntity ) 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 ) { @@ -509,7 +513,6 @@ float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) 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 ) { @@ -566,7 +569,6 @@ int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) return iNext; } - //========================================================= // CGraph - FindShortestPath // @@ -582,13 +584,15 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int iHullMask; if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built + { + // 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? + { + // The start node is bad? ALERT ( at_aiconsole, "Can't build a path, iStart is %d!\n", iStart ); return FALSE; } @@ -678,22 +682,24 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, 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 - + { + // 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 + { + // 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 - + { + // 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. + { + // monster should not try to go this way. continue; } } @@ -709,16 +715,16 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, } } if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) - {// Destination is unreachable, no path found. + { + // Destination is unreachable, no path found. return 0; } - // the queue is not empty - + // 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++; @@ -732,13 +738,10 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, 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 ); @@ -754,7 +757,6 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, MESSAGE_END(); } } - #endif #if 0 // MAZE map MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -769,73 +771,73 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.z + NODE_HEIGHT ); MESSAGE_END(); #endif - return iNumPathNodes; } -inline ULONG Hash(void *p, int len) +inline ULONG Hash( void *p, int len ) { CRC32_t ulCrc; - CRC32_INIT(&ulCrc); - CRC32_PROCESS_BUFFER(&ulCrc, p, len); - return CRC32_FINAL(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) +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; - } + 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) +inline int CALC_RANGE( int x, int lower, int upper ) { - return NUM_RANGES*(x-lower)/((upper-lower+1)); + 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; + 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) +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; + // Have we already seen this point before?. + // + if( m_di[iNode].m_CheckedEvent == m_CheckedCounter ) + return; - float flDist = ( vecOrigin - m_pNodes[ iNode ].m_vecOriginPeek ).Length(); + m_di[iNode].m_CheckedEvent = m_CheckedCounter; - if ( flDist < m_flShortest ) + 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 ); + UTIL_TraceLine ( vecOrigin, m_pNodes[iNode].m_vecOriginPeek, ignore_monsters, 0, &tr ); - if ( tr.flFraction == 1.0 ) + 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]); + 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. @@ -855,18 +857,19 @@ void CGraph :: CheckNode(Vector vecOrigin, int iNode) // the given vector -1 is failure (couldn't find a valid // near node ) //========================================================= -int CGraph :: FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) +int CGraph::FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) { return FindNearestNode( vecOrigin, NodeType( pEntity ) ); } -int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) +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 + 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; } @@ -874,20 +877,20 @@ int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) // Check with the cache // ULONG iHash = (CACHE_SIZE-1) & Hash((void *)(const float *)vecOrigin, sizeof(vecOrigin)); - if (m_Cache[iHash].v == vecOrigin) + if(m_Cache[iHash].v == vecOrigin) { //ALERT(at_aiconsole, "Cache Hit.\n"); return m_Cache[iHash].n; } - else +/* else { //ALERT(at_aiconsole, "Cache Miss.\n"); } - +*/ // Mark all points as unchecked. // m_CheckedCounter++; - if (m_CheckedCounter == 0) + if( m_CheckedCounter == 0 ) { for ( i = 0; i < m_cNodes; i++ ) { @@ -916,65 +919,90 @@ int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) 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]); + 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 halfX = (m_minX+m_maxX)/2; - int halfY = (m_minY+m_maxY)/2; - int halfZ = (m_minZ+m_maxZ)/2; + int j; - 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; + 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; + 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]); - } - } + if( rgZ < m_minBoxZ ) + continue; - 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; + 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]); - } - } + if( rgZ > m_maxBoxZ ) + break; - 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; + 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; + 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( 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++) { @@ -1430,7 +1458,6 @@ int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) //========================================================= class CTestHull : public CBaseMonster { - public: void Spawn( entvars_t *pevMasterNode ); virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } @@ -1443,7 +1470,7 @@ public: Vector vecBadNodeOrigin; }; -LINK_ENTITY_TO_CLASS( testhull, CTestHull ); +LINK_ENTITY_TO_CLASS( testhull, CTestHull ) //========================================================= // CTestHull::Spawn @@ -1576,6 +1603,7 @@ void CTestHull :: ShowBadNode( void ) } extern BOOL gTouchDisabled; + void CTestHull::CallBuildNodeGraph( void ) { // TOUCH HACK -- Don't allow this entity to call anyone's "touch" function @@ -1637,7 +1665,7 @@ void CTestHull :: BuildNodeGraph( void ) SetThink( &CBaseEntity::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. + //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 ) { @@ -1763,8 +1791,8 @@ void CTestHull :: BuildNodeGraph( void ) 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. + // 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"); @@ -1931,7 +1959,7 @@ void CTestHull :: BuildNodeGraph( void ) cPoolLinks -= WorldGraph.RejectInlineLinks ( pTempPool, file ); -// now malloc a pool just large enough to hold the links that are actually used + // 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 ) @@ -1950,7 +1978,7 @@ void CTestHull :: BuildNodeGraph( void ) } WorldGraph.m_cLinks = cPoolLinks; -//copy only the used portions of the TempPool into the graph's link pool + //copy only the used portions of the TempPool into the graph's link pool int iFinalPoolIndex = 0; int iOldFirstLink; @@ -1980,9 +2008,9 @@ void CTestHull :: BuildNodeGraph( void ) 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. + // 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++ ) @@ -2050,12 +2078,11 @@ void CTestHull :: BuildNodeGraph( void ) // WorldGraph.ComputeStaticRoutingTables(); -// save the node graph for this level + // save the node graph for this level WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); ALERT( at_console, "Done.\n"); } - //========================================================= // returns a hardcoded path. //========================================================= @@ -2106,7 +2133,6 @@ void CTestHull :: PathFind ( void ) } - //========================================================= // CStack Constructor //========================================================= @@ -2265,7 +2291,7 @@ void CQueuePriority::Heap_SiftDown(int iSubRoot) struct tag_HEAP_NODE Ref = m_heap[ parent ]; - while (child < m_cSize) + while (child < m_cSize) { int rightchild = HEAP_RIGHT_CHILD(parent); if (rightchild < m_cSize) @@ -2367,7 +2393,6 @@ int CGraph :: FLoadGraph ( char *szMapName ) m_pRouteInfo = NULL; m_pHashLinks = NULL; - // Malloc for the nodes // m_pNodes = ( CNode * )calloc ( sizeof ( CNode ), m_cNodes ); @@ -2786,6 +2811,7 @@ void CGraph::HashChoosePrimes(int TableSize) // 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. @@ -3327,7 +3353,6 @@ void CGraph :: ComputeStaticRoutingTables( void ) BestNextNodes = 0; pRoute = 0; pMyPath = 0; - #if 0 TestRoutingTables(); #endif @@ -3453,21 +3478,12 @@ void CGraph :: TestRoutingTables( void ) } 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 @@ -3490,12 +3506,12 @@ public: 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 ); + +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( ) { @@ -3571,7 +3587,6 @@ void CNodeViewer::Spawn( ) pev->nextthink = gpGlobals->time; } - void CNodeViewer :: FindNodeConnections ( int iNode ) { AddNode( iNode, WorldGraph.NextNodeInRoute( iNode, m_iBaseNode, m_iHull, 0 )); @@ -3645,5 +3660,3 @@ void CNodeViewer :: DrawThink( void ) m_iDraw++; } } - - diff --git a/dlls/nodes.h b/dlls/nodes.h index 67ac2139..27b890ed 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -88,7 +88,6 @@ public: float m_flWeight;// length of the link line segment }; - typedef struct { int m_SortedBy[3]; @@ -105,6 +104,7 @@ typedef struct // CGraph //========================================================= #define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. + class CGraph { public: @@ -269,7 +269,6 @@ class CNodeEnt : public CBaseEntity short m_sHintActivity; }; - //========================================================= // CStack - last in, first out. //========================================================= @@ -289,7 +288,6 @@ private: int m_level; }; - //========================================================= // CQueue - first in, first out. //========================================================= @@ -368,7 +366,7 @@ enum HINT_TACTICAL_AMBUSH, HINT_STUKA_PERCH = 300, - HINT_STUKA_LANDING, + HINT_STUKA_LANDING }; extern CGraph WorldGraph; diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index 97c3513f..97747f2b 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -30,11 +31,8 @@ typedef struct Vector vecAngles; } t_ospreygrunt; - - #define SF_WAITFORTRIGGER 0x40 - #define MAX_CARRY 24 class COsprey : public CBaseMonster @@ -105,9 +103,9 @@ public: int m_iDoRightSmokePuff; }; -LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ); +LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ) -TYPEDESCRIPTION COsprey::m_SaveData[] = +TYPEDESCRIPTION COsprey::m_SaveData[] = { DEFINE_FIELD( COsprey, m_pGoalEnt, FIELD_CLASSPTR ), DEFINE_FIELD( COsprey, m_vel1, FIELD_VECTOR ), @@ -139,8 +137,8 @@ TYPEDESCRIPTION COsprey::m_SaveData[] = DEFINE_FIELD( COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER ), DEFINE_FIELD( COsprey, m_iDoRightSmokePuff, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ); +IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ) void COsprey :: Spawn( void ) { @@ -180,7 +178,6 @@ void COsprey :: Spawn( void ) m_vel2 = pev->velocity; } - void COsprey::Precache( void ) { UTIL_PrecacheOther( "monster_human_grunt" ); @@ -230,7 +227,6 @@ void COsprey :: FindAllThink( void ) m_startTime = gpGlobals->time; } - void COsprey :: DeployThink( void ) { UTIL_MakeAimVectors( pev->angles ); @@ -261,8 +257,6 @@ void COsprey :: DeployThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - - BOOL COsprey :: HasDead( ) { for (int i = 0; i < m_iUnits; i++) @@ -279,7 +273,6 @@ BOOL COsprey :: HasDead( ) return FALSE; } - CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) { CBaseEntity *pEntity; @@ -321,7 +314,6 @@ CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) return NULL; } - void COsprey :: HoverThink( void ) { int i; @@ -344,7 +336,6 @@ void COsprey :: HoverThink( void ) ShowDamage( ); } - void COsprey::UpdateGoal( ) { if (m_pGoalEnt) @@ -380,7 +371,6 @@ void COsprey::UpdateGoal( ) } } - void COsprey::FlyThink( void ) { StudioFrameAdvance( ); @@ -408,7 +398,6 @@ void COsprey::FlyThink( void ) ShowDamage( ); } - void COsprey::Flight( ) { float t = (gpGlobals->time - m_startTime); @@ -484,13 +473,11 @@ void COsprey::Flight( ) } - void COsprey::HitTouch( CBaseEntity *pOther ) { pev->nextthink = gpGlobals->time + 2.0; } - /* int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { @@ -507,8 +494,6 @@ int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float } */ - - void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) { pev->movetype = MOVETYPE_TOSS; @@ -539,7 +524,6 @@ void COsprey::CrashTouch( CBaseEntity *pOther ) } } - void COsprey :: DyingThink( void ) { StudioFrameAdvance( ); @@ -728,7 +712,6 @@ void COsprey :: DyingThink( void ) } } - void COsprey :: ShowDamage( void ) { if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0,99) > m_flLeftHealth) @@ -763,7 +746,6 @@ void COsprey :: ShowDamage( void ) } } - void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); @@ -798,8 +780,3 @@ void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir UTIL_Sparks( ptr->vecEndPos ); } } - - - - - diff --git a/dlls/pathcorner.cpp b/dlls/pathcorner.cpp index 3516ec08..3717ee8b 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -38,15 +38,15 @@ private: float m_flWait; }; -LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ); +LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ) // Global Savedata for Delay -TYPEDESCRIPTION CPathCorner::m_SaveData[] = +TYPEDESCRIPTION CPathCorner::m_SaveData[] = { DEFINE_FIELD( CPathCorner, m_flWait, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ); +IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ) // // Cache user-entity-field values until spawn is called. @@ -62,7 +62,6 @@ void CPathCorner :: KeyValue( KeyValueData *pkvd ) CPointEntity::KeyValue( pkvd ); } - void CPathCorner :: Spawn( ) { ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname"); @@ -116,9 +115,7 @@ void CPathCorner :: Touch( CBaseEntity *pOther ) } #endif - - -TYPEDESCRIPTION CPathTrack::m_SaveData[] = +TYPEDESCRIPTION CPathTrack::m_SaveData[] = { DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ), DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ), @@ -127,8 +124,8 @@ TYPEDESCRIPTION CPathTrack::m_SaveData[] = DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ); -LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); +IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ) +LINK_ENTITY_TO_CLASS( path_track, CPathTrack ) // // Cache user-entity-field values until spawn is called. @@ -174,7 +171,6 @@ void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } - void CPathTrack :: Link( void ) { edict_t *pentTarget; @@ -211,7 +207,6 @@ void CPathTrack :: Link( void ) } } - void CPathTrack :: Spawn( void ) { pev->solid = SOLID_TRIGGER; @@ -226,7 +221,6 @@ void CPathTrack :: Spawn( void ) #endif } - void CPathTrack::Activate( void ) { if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link @@ -244,7 +238,6 @@ CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag ) return ppath; } - void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) { if ( pstart && pend ) @@ -273,8 +266,6 @@ CPathTrack *CPathTrack::GetPrevious( void ) return m_pprevious; } - - void CPathTrack::SetPrevious( CPathTrack *pprev ) { // Only set previous if this isn't my alternate path @@ -282,7 +273,6 @@ void CPathTrack::SetPrevious( CPathTrack *pprev ) m_pprevious = pprev; } - // Assumes this is ALWAYS enabled CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) { @@ -364,7 +354,6 @@ CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) return pcurrent; } - // Assumes this is ALWAYS enabled CPathTrack *CPathTrack :: Nearest( Vector origin ) @@ -404,7 +393,6 @@ CPathTrack *CPathTrack :: Nearest( Vector origin ) return pnearest; } - CPathTrack *CPathTrack::Instance( edict_t *pent ) { if ( FClassnameIs( pent, "path_track" ) ) @@ -412,8 +400,7 @@ CPathTrack *CPathTrack::Instance( edict_t *pent ) return NULL; } - - // DEBUGGING CODE +// DEBUGGING CODE #if PATH_SPARKLE_DEBUG void CPathTrack :: Sparkle( void ) { @@ -425,4 +412,3 @@ void CPathTrack :: Sparkle( void ) UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10); } #endif - diff --git a/dlls/physcallback.h b/dlls/physcallback.h index 4471e05c..1db276e0 100644 --- a/dlls/physcallback.h +++ b/dlls/physcallback.h @@ -30,4 +30,4 @@ extern server_physics_api_t g_physfuncs; #define GET_SERVER_STATE (*g_physfuncs.pfnServerState) #define HOST_ERROR (*g_physfuncs.pfnHost_Error) -#endif //PHYSCALLBACK_H \ No newline at end of file +#endif //PHYSCALLBACK_H diff --git a/dlls/plane.cpp b/dlls/plane.cpp index 39a91c32..689a0c29 100644 --- a/dlls/plane.cpp +++ b/dlls/plane.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "plane.h" @@ -34,7 +35,6 @@ void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint m_fInitialized = TRUE; } - //========================================================= // PointInFront - determines whether the given vector is // in front of the plane. @@ -57,4 +57,3 @@ BOOL CPlane :: PointInFront ( const Vector &vecPoint ) return FALSE; } - diff --git a/dlls/plats.cpp b/dlls/plats.cpp index d2ca1aa0..e4e30ef1 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -49,14 +49,14 @@ public: float m_volume; // Sound volume }; -TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = +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 ); +IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ) void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) { @@ -104,7 +104,7 @@ void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) void CBasePlatTrain::Precache( void ) { -// set the plat's "in-motion" sound + // set the plat's "in-motion" sound switch (m_bMoveSnd) { case 0: @@ -167,7 +167,7 @@ void CBasePlatTrain::Precache( void ) break; } -// set the plat's 'reached destination' stop sound + // set the plat's 'reached destination' stop sound switch (m_bStopSnd) { case 0: @@ -216,7 +216,6 @@ void CBasePlatTrain::Precache( void ) //====================== PLAT code ==================================================== // - #define noiseMovement noise #define noiseStopMoving noise1 @@ -229,7 +228,6 @@ public: virtual void Blocked( CBaseEntity *pOther ); - void EXPORT PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT CallGoDown( void ) { GoDown(); } @@ -241,8 +239,8 @@ public: virtual void HitTop( void ); virtual void HitBottom( void ); }; -LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ); +LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ) // UNDONE: Need to save this!!! It needs class & linkage class CPlatTrigger : public CBaseEntity @@ -254,8 +252,6 @@ public: CFuncPlat *m_pPlatform; }; - - /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER speed default 150 @@ -305,7 +301,6 @@ void CFuncPlat :: Setup( void ) m_volume = 0.85; } - void CFuncPlat :: Precache( ) { CBasePlatTrain::Precache(); @@ -315,7 +310,6 @@ void CFuncPlat :: Precache( ) PlatSpawnInsideTrigger( pev ); // the "start moving" trigger } - void CFuncPlat :: Spawn( ) { Setup(); @@ -337,14 +331,11 @@ void CFuncPlat :: Spawn( ) } } - - static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) { GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); } - // // Create a trigger entity for a platform. // @@ -373,7 +364,6 @@ void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) UTIL_SetSize ( pev, vecTMin, vecTMax ); } - // // When the platform's trigger field is touched, the platform ??? // @@ -395,7 +385,6 @@ void CPlatTrigger :: Touch( CBaseEntity *pOther ) 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. @@ -424,7 +413,6 @@ void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - // // Platform is at top, now starts moving down. // @@ -439,7 +427,6 @@ void CFuncPlat :: GoDown( void ) LinearMove(m_vecPosition2, pev->speed); } - // // Platform has hit bottom. Stops and waits forever. // @@ -455,7 +442,6 @@ void CFuncPlat :: HitBottom( void ) m_toggle_state = TS_AT_BOTTOM; } - // // Platform is at bottom, now starts moving up // @@ -470,7 +456,6 @@ void CFuncPlat :: GoUp( void ) LinearMove(m_vecPosition1, pev->speed); } - // // Platform has hit top. Pauses, then starts back down again. // @@ -493,7 +478,6 @@ void CFuncPlat :: HitTop( void ) } } - void CFuncPlat :: Blocked( CBaseEntity *pOther ) { ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); @@ -511,7 +495,6 @@ void CFuncPlat :: Blocked( CBaseEntity *pOther ) GoUp (); } - class CFuncPlatRot : public CFuncPlat { public: @@ -530,15 +513,15 @@ public: Vector m_end, m_start; }; -LINK_ENTITY_TO_CLASS( func_platrot, CFuncPlatRot ); -TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = + +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 ); - +IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ) void CFuncPlatRot :: SetupRotation( void ) { @@ -559,7 +542,6 @@ void CFuncPlatRot :: SetupRotation( void ) } } - void CFuncPlatRot :: Spawn( void ) { CFuncPlat :: Spawn(); @@ -572,7 +554,6 @@ void CFuncPlatRot :: GoDown( void ) RotMove( m_start, pev->nextthink - pev->ltime ); } - // // Platform has hit bottom. Stops and waits forever. // @@ -583,7 +564,6 @@ void CFuncPlatRot :: HitBottom( void ) pev->angles = m_start; } - // // Platform is at bottom, now starts moving up // @@ -593,7 +573,6 @@ void CFuncPlatRot :: GoUp( void ) RotMove( m_end, pev->nextthink - pev->ltime ); } - // // Platform has hit top. Pauses, then starts back down again. // @@ -604,7 +583,6 @@ void CFuncPlatRot :: HitTop( void ) pev->angles = m_end; } - void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) { // set destdelta to the vector needed to move @@ -620,7 +598,6 @@ void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) } } - // //====================== TRAIN code ================================================== // @@ -649,16 +626,16 @@ public: BOOL m_activated; }; -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = +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 ); - +IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ) void CFuncTrain :: KeyValue( KeyValueData *pkvd ) { @@ -671,9 +648,7 @@ void CFuncTrain :: KeyValue( KeyValueData *pkvd ) CBasePlatTrain::KeyValue( pkvd ); } - void CFuncTrain :: Blocked( CBaseEntity *pOther ) - { if ( gpGlobals->time < m_flActivateFinished) return; @@ -683,7 +658,6 @@ void CFuncTrain :: Blocked( CBaseEntity *pOther ) 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 ) @@ -705,7 +679,6 @@ void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } - void CFuncTrain :: Wait( void ) { // Fire the pass target if there is one @@ -718,21 +691,23 @@ void CFuncTrain :: Wait( void ) // 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. + + // 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 ); + return; + } + + // ALERT ( at_console, "%f\n", m_flWait ); if (m_flWait != 0) - {// -1 wait will wait forever! + { + // -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; if ( pev->noiseMovement ) STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); @@ -746,7 +721,6 @@ void CFuncTrain :: Wait( void ) } } - // // Train next - path corner needs to change to next target // @@ -758,7 +732,7 @@ void CFuncTrain :: Next( void ) // now find our next target pTarg = GetNextTarget(); - if ( !pTarg ) + if( !pTarg ) { if ( pev->noiseMovement ) STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); @@ -775,13 +749,14 @@ void CFuncTrain :: Next( void ) 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; + { + // 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 + pev->enemy = pTarg->edict();//hack if(FBitSet(m_pevCurrentTarget->spawnflags, SF_CORNER_TELEPORT)) { @@ -807,7 +782,6 @@ void CFuncTrain :: Next( void ) } } - void CFuncTrain :: Activate( void ) { // Not yet active, so teleport to first target @@ -815,10 +789,10 @@ void CFuncTrain :: Activate( void ) { 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) ) @@ -847,15 +821,15 @@ 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 @@ -871,11 +845,9 @@ void CFuncTrain :: Spawn( void ) m_volume = 0.85; } - void CFuncTrain::Precache( void ) { CBasePlatTrain::Precache(); - #if 0 // obsolete // otherwise use preset sound switch (m_sounds) @@ -884,14 +856,12 @@ void CFuncTrain::Precache( void ) 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"); @@ -902,7 +872,6 @@ void CFuncTrain::Precache( void ) #endif } - void CFuncTrain::OverrideReset( void ) { CBaseEntity *pTarg; @@ -926,9 +895,6 @@ void CFuncTrain::OverrideReset( void ) } } - - - // --------------------------------------------------------------------- // // Track Train @@ -951,8 +917,8 @@ TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ); -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); +IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ) +LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ) void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) { @@ -991,7 +957,6 @@ void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } - void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) { if ( alwaysThink ) @@ -1002,7 +967,6 @@ void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) pev->nextthink = thinkTime; } - void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) { entvars_t *pevOther = pOther->pev; @@ -1027,7 +991,6 @@ void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); } - void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( useType != USE_SET ) @@ -1038,7 +1001,7 @@ void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ if ( pev->speed == 0 ) { pev->speed = m_speed * m_dir; - + Next(); } else @@ -1070,7 +1033,6 @@ void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ } } - static float Fix( float angle ) { while ( angle < 0 ) @@ -1081,7 +1043,6 @@ static float Fix( float angle ) return angle; } - static void FixupAngles( Vector &v ) { v.x = Fix( v.x ); @@ -1122,7 +1083,7 @@ void CFuncTrackTrain :: StopSound( void ) void CFuncTrackTrain :: UpdateSound( void ) { float flpitch; - + if (!pev->noise) return; @@ -1158,7 +1119,6 @@ void CFuncTrackTrain :: UpdateSound( void ) } } - void CFuncTrackTrain :: Next( void ) { float time = 0.5; @@ -1228,7 +1188,7 @@ void CFuncTrackTrain :: Next( void ) 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 ) @@ -1250,12 +1210,13 @@ void CFuncTrackTrain :: Next( void ) 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) + { + // 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 ); } @@ -1265,7 +1226,7 @@ void CFuncTrackTrain :: Next( void ) SetThink( &CFuncTrackTrain::Next ); NextThink( pev->ltime + time, TRUE ); } - else // end of path, stop + else // end of path, stop { StopSound(); pev->velocity = (nextPos - pev->origin); @@ -1273,11 +1234,10 @@ void CFuncTrackTrain :: Next( void ) float distance = pev->velocity.Length(); m_oldSpeed = pev->speed; - pev->speed = 0; - + // Move to the dead end - + // Are we there yet? if ( distance > 0 ) { @@ -1294,7 +1254,6 @@ void CFuncTrackTrain :: Next( void ) } } - void CFuncTrackTrain::DeadEnd( void ) { // Fire the dead-end target if there is one @@ -1340,7 +1299,6 @@ void CFuncTrackTrain::DeadEnd( void ) ALERT( at_aiconsole, "\n" ); } - void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) { Vector offset = pevControls->origin - pev->oldorigin; @@ -1349,7 +1307,6 @@ void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) m_controlMaxs = pevControls->maxs + offset; } - BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) { Vector offset = pevTest->origin - pev->origin; @@ -1371,7 +1328,6 @@ BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) return FALSE; } - void CFuncTrackTrain :: Find( void ) { m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); @@ -1400,7 +1356,7 @@ void CFuncTrackTrain :: Find( void ) if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) pev->angles.x = 0; - UTIL_SetOrigin( pev, nextPos ); + UTIL_SetOrigin( pev, nextPos ); NextThink( pev->ltime + 0.1, FALSE ); SetThink( &CFuncTrackTrain::Next ); pev->speed = m_startSpeed; @@ -1408,7 +1364,6 @@ void CFuncTrackTrain :: Find( void ) UpdateSound(); } - void CFuncTrackTrain :: NearestPath( void ) { CBaseEntity *pTrack = NULL; @@ -1456,14 +1411,12 @@ void CFuncTrackTrain :: NearestPath( void ) } } - void CFuncTrackTrain::OverrideReset( void ) { NextThink( pev->ltime + 0.1, FALSE ); SetThink( &CFuncTrackTrain::NearestPath ); } - CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) { if ( FClassnameIs( pent, "func_tracktrain" ) ) @@ -1488,7 +1441,7 @@ void CFuncTrackTrain :: Spawn( void ) m_speed = 100; else m_speed = pev->speed; - + pev->speed = 0; pev->velocity = g_vecZero; pev->avelocity = g_vecZero; @@ -1504,7 +1457,7 @@ void CFuncTrackTrain :: Spawn( void ) else pev->solid = SOLID_BSP; pev->movetype = MOVETYPE_PUSH; - + SET_MODEL( ENT(pev), STRING(pev->model) ); UTIL_SetSize( pev, pev->mins, pev->maxs ); @@ -1516,8 +1469,9 @@ void CFuncTrackTrain :: Spawn( void ) 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 + + // 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(); @@ -1556,8 +1510,8 @@ public: void Spawn( void ); void EXPORT Find( void ); }; -LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); +LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ) void CFuncTrainControls :: Find( void ) { @@ -1579,7 +1533,6 @@ void CFuncTrainControls :: Find( void ) UTIL_Remove( this ); } - void CFuncTrainControls :: Spawn( void ) { pev->solid = SOLID_NOT; @@ -1588,13 +1541,11 @@ void CFuncTrainControls :: Spawn( void ) UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); - + SetThink( &CFuncTrainControls::Find ); pev->nextthink = gpGlobals->time; } - - // ---------------------------------------------------------------------------- // // Track changer / Train elevator @@ -1621,7 +1572,7 @@ public: void Spawn( void ); void Precache( void ); -// virtual void Blocked( void ); + //virtual void Blocked( void ); virtual void EXPORT GoUp( void ); virtual void EXPORT GoDown( void ); @@ -1646,7 +1597,6 @@ public: virtual void OverrideReset( void ); - CPathTrack *m_trackTop; CPathTrack *m_trackBottom; @@ -1659,9 +1609,10 @@ public: int m_targetState; int m_use; }; -LINK_ENTITY_TO_CLASS( func_trackchange, CFuncTrackChange ); -TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = +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 ), @@ -1674,7 +1625,7 @@ TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = DEFINE_FIELD( CFuncTrackChange, m_use, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ); +IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ) void CFuncTrackChange :: Spawn( void ) { @@ -1709,11 +1660,10 @@ 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 ) { @@ -1723,8 +1673,6 @@ void CFuncTrackChange :: Touch( CBaseEntity *pOther ) #endif } - - void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) { if ( FStrEq(pkvd->szKeyName, "train") ) @@ -1748,7 +1696,6 @@ void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) } } - void CFuncTrackChange::OverrideReset( void ) { pev->nextthink = pev->ltime + 1.0; @@ -1797,8 +1744,6 @@ void CFuncTrackChange :: Find( void ) 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 @@ -1820,11 +1765,10 @@ TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) return TRAIN_BLOCKING; } - + return TRAIN_SAFE; } - void CFuncTrackChange :: UpdateTrain( Vector &dest ) { float time = (pev->nextthink - pev->ltime); @@ -1882,7 +1826,6 @@ void CFuncTrackChange :: GoDown( void ) } } - // // Platform is at bottom, now starts moving up // @@ -1908,7 +1851,7 @@ void CFuncTrackChange :: GoUp( void ) SetMoveDone( &CFuncPlat::CallHitTop ); RotMove( m_end, pev->nextthink - pev->ltime ); } - + // Otherwise, move first, rotate second // If the train is moving with the platform, update it @@ -1919,7 +1862,6 @@ void CFuncTrackChange :: GoUp( void ) } } - // Normal track change void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) { @@ -1937,7 +1879,6 @@ void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) 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 ) @@ -1968,7 +1909,6 @@ void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE GoUp(); } - // // Platform has hit bottom. Stops and waits forever. // @@ -1977,7 +1917,7 @@ void CFuncTrackChange :: HitBottom( void ) CFuncPlatRot :: HitBottom(); if ( m_code == TRAIN_FOLLOWING ) { -// UpdateTrain(); + //UpdateTrain(); m_train->SetTrack( m_trackBottom ); } SetThink( NULL ); @@ -1988,7 +1928,6 @@ void CFuncTrackChange :: HitBottom( void ) EnableUse(); } - // // Platform has hit bottom. Stops and waits forever. // @@ -1997,10 +1936,10 @@ void CFuncTrackChange :: HitTop( void ) CFuncPlatRot :: HitTop(); if ( m_code == TRAIN_FOLLOWING ) { -// UpdateTrain(); + //UpdateTrain(); m_train->SetTrack( m_trackTop ); } - + // Don't let the plat go back down SetThink( NULL ); pev->nextthink = -1; @@ -2008,16 +1947,14 @@ void CFuncTrackChange :: HitTop( void ) EnableUse(); } - - class CFuncTrackAuto : public CFuncTrackChange { public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); virtual void UpdateAutoTargets( int toggleState ); }; -LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ); +LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ) // Auto track change void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) @@ -2046,10 +1983,8 @@ void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) if ( pNextTarget ) SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); - } - void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CPathTrack *pTarget; @@ -2067,6 +2002,7 @@ void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) { m_code = EvaluateTrain( pTarget ); + // Safe to fire? if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) { @@ -2093,7 +2029,6 @@ void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T } } - // ---------------------------------------------------------- // // @@ -2129,16 +2064,14 @@ private: BOOL m_on; }; - -LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ); +LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ) TYPEDESCRIPTION CGunTarget::m_SaveData[] = { DEFINE_FIELD( CGunTarget, m_on, FIELD_BOOLEAN ), }; -IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ) void CGunTarget::Spawn( void ) { @@ -2165,7 +2098,6 @@ void CGunTarget::Spawn( void ) } } - void CGunTarget::Activate( void ) { CBaseEntity *pTarg; @@ -2179,20 +2111,18 @@ void CGunTarget::Activate( void ) } } - 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(); @@ -2202,11 +2132,10 @@ void CGunTarget::Next( void ) LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); } - void CGunTarget::Wait( void ) { CBaseEntity *pTarget = m_hTargetEnt; - + if ( !pTarget ) { Stop(); @@ -2220,13 +2149,14 @@ void CGunTarget::Wait( void ) 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! + { + // -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; } else @@ -2235,7 +2165,6 @@ void CGunTarget::Wait( void ) } } - void CGunTarget::Stop( void ) { pev->velocity = g_vecZero; @@ -2244,7 +2173,7 @@ void CGunTarget::Stop( void ) } -int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { if ( pev->health > 0 ) { @@ -2260,7 +2189,6 @@ int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo return 0; } - void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !ShouldToggle( useType, m_on ) ) @@ -2280,6 +2208,3 @@ void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us Next(); } } - - - diff --git a/dlls/player.cpp b/dlls/player.cpp index 54d4e8c5..866898c8 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1,4 +1,4 @@ - /*** +/*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. * @@ -44,7 +44,6 @@ extern DLL_GLOBAL BOOL g_fDrawLines; int gEvilImpulse101; extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; - BOOL gInitHUD = TRUE; extern void CopyToBodyQue(entvars_t* pev); @@ -68,7 +67,7 @@ extern CGraph WorldGraph; #define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) // Global Savedata for player -TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = +TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = { DEFINE_FIELD( CBasePlayer, m_flFlashLightTime, FIELD_TIME ), DEFINE_FIELD( CBasePlayer, m_iFlashBattery, FIELD_INTEGER ), @@ -96,7 +95,7 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = 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 ), @@ -116,7 +115,7 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = 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 ), @@ -143,10 +142,8 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = //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; @@ -187,8 +184,6 @@ int gmsgTeamNames = 0; int gmsgStatusText = 0; int gmsgStatusValue = 0; - - void LinkUserMessages( void ) { // Already taken care of? @@ -232,20 +227,17 @@ void LinkUserMessages( void ) gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 ); gmsgStatusText = REG_USER_MSG("StatusText", -1); - gmsgStatusValue = REG_USER_MSG("StatusValue", 3); - + gmsgStatusValue = REG_USER_MSG("StatusValue", 3); } -LINK_ENTITY_TO_CLASS( player, CBasePlayer ); - - +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 ) @@ -267,7 +259,7 @@ Vector VecVelocityForDamage(float flDamage) vec = vec * 2; else vec = vec * 10; - + return vec; } @@ -293,8 +285,7 @@ static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) pevNew->frame = 0; pevNew->flags = 0; } - - + static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) { SET_MODEL(ENT(pev), szGibModel); @@ -310,9 +301,7 @@ static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) pev->origin.z -= 24; ClearBits(pev->flags, FL_ONGROUND); } - - -*/ +*/ #endif int TrainSpeed(int iSpeed, int iMax) @@ -374,15 +363,14 @@ void CBasePlayer :: DeathSound( void ) 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; + //UTIL_MakeVectors(pev->v_angle); + //m_HackedGunPos = pev->view_ofs; Vector origin; - + origin = pev->origin + pev->view_ofs; return origin; @@ -465,7 +453,7 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, return 0; // go take the damage first - + CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) @@ -521,9 +509,7 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, 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); @@ -560,18 +546,18 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, 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; } @@ -586,7 +572,7 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, bitsDamage &= ~DMG_SLASH; ffound = TRUE; } - + if (bitsDamage & DMG_SONIC) { if (fmajor) @@ -640,16 +626,15 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // 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 @@ -701,7 +686,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) return; } -// go through all of the weapons and make a list of the ones to pack + // 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 ] ) @@ -720,11 +705,9 @@ void CBasePlayer::PackDeadPlayerItems( void ) rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; } break; - case GR_PLR_DROP_GUN_ALL: rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; break; - default: break; } @@ -734,7 +717,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) } } -// now go through ammo and make a list of which types to pack. + // 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++ ) @@ -747,7 +730,6 @@ void CBasePlayer::PackDeadPlayerItems( void ) case GR_PLR_DROP_AMMO_ALL: iPackAmmo[ iPA++ ] = i; break; - case GR_PLR_DROP_AMMO_ACTIVE: if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) { @@ -760,15 +742,13 @@ void CBasePlayer::PackDeadPlayerItems( void ) iPackAmmo[ iPA++ ] = i; } break; - default: break; } } } } - -// create a box to pack the stuff into. + // 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. @@ -777,18 +757,18 @@ void CBasePlayer::PackDeadPlayerItems( void ) pWeaponBox->SetThink( &CWeaponBox::Kill ); pWeaponBox->pev->nextthink = gpGlobals->time + 120; -// back these two lists up to their first elements + // back these two lists up to their first elements iPA = 0; iPW = 0; -// pack the ammo + // 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 + // now pack all of the items in the lists while ( rgpPackWeapons[ iPW ] ) { // weapon unhooked from the player. Pack it into der box. @@ -830,7 +810,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) pev->viewmodel = 0; pev->weaponmodel = 0; - + if ( removeSuit ) pev->weapons = 0; else @@ -840,6 +820,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) m_rgAmmo[i] = 0; UpdateClientData(); + // send Selected Weapon Message to our client MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); WRITE_BYTE(0); @@ -854,7 +835,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) * 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. + // Better solution: Add as parameter to all Killed() functions. void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) { @@ -882,7 +863,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) } SetAnimation( PLAYER_DIE ); - + m_iRespawnFrames = 0; pev->modelindex = g_ulModelIndexPlayer; // don't use eyes @@ -916,7 +897,6 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) 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 ); @@ -929,15 +909,14 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) } DeathSound(); - + pev->angles.x = 0; pev->angles.z = 0; - SetThink( &CBasePlayer::PlayerDeathThink); + 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 ) { @@ -958,16 +937,13 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM 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 ) { @@ -1016,6 +992,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) m_Activity = m_IdealActivity; animDesired = LookupActivity( m_Activity ); + // Already using the desired animation? if (pev->sequence == animDesired) return; @@ -1025,7 +1002,6 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) pev->frame = 0; ResetSequenceInfo( ); return; - case ACT_RANGE_ATTACK1: if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching strcpy( szAnim, "crouch_shoot_" ); @@ -1051,7 +1027,6 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) pev->sequence = animDesired; ResetSequenceInfo( ); break; - case ACT_WALK: if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished) { @@ -1097,7 +1072,6 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) pev->gaitsequence = LookupSequence( "deep_idle" ); } - // Already using the desired animation? if (pev->sequence == animDesired) return; @@ -1154,7 +1128,7 @@ void CBasePlayer::WaterMove() 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); @@ -1170,7 +1144,7 @@ void CBasePlayer::WaterMove() // 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. @@ -1178,7 +1152,6 @@ void CBasePlayer::WaterMove() m_bitsDamageType &= ~DMG_DROWN; m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; } - } else { // fully under water @@ -1196,7 +1169,7 @@ void CBasePlayer::WaterMove() 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 @@ -1217,9 +1190,8 @@ void CBasePlayer::WaterMove() } return; } - - // make bubbles + // make bubbles air = (int)(pev->air_finished - gpGlobals->time); if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) { @@ -1242,7 +1214,7 @@ void CBasePlayer::WaterMove() 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); @@ -1250,7 +1222,6 @@ void CBasePlayer::WaterMove() } } - // TRUE if the player is attached to a ladder BOOL CBasePlayer::IsOnLadder( void ) { @@ -1279,7 +1250,6 @@ void CBasePlayer::PlayerDeathThink(void) PackDeadPlayerItems(); } - if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) { StudioFrameAdvance( ); @@ -1296,14 +1266,14 @@ void CBasePlayer::PlayerDeathThink(void) 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) { @@ -1315,20 +1285,20 @@ void CBasePlayer::PlayerDeathThink(void) 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 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(); } - -// wait for any button down, or mp_forcerespawn is set and the respawn time is up + + // 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; @@ -1367,7 +1337,7 @@ void CBasePlayer::StartDeathCam( void ) while ( iRand > 0 ) { pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); - + if ( pNewSpot ) { pSpot = pNewSpot; @@ -1404,7 +1374,7 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) UTIL_SetOrigin( pev, vecPosition ); } -// +// // PlayerUse - handles USE keypress // #define PLAYER_SEARCH_RADIUS (float)64 @@ -1457,7 +1427,7 @@ void CBasePlayer::PlayerUse ( void ) 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) { @@ -1467,19 +1437,20 @@ void CBasePlayer::PlayerUse ( void ) // 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 + { + // 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 ); } -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); + //ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); } } pObject = pClosest; @@ -1514,18 +1485,16 @@ void CBasePlayer::PlayerUse ( void ) } } - - 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; @@ -1542,11 +1511,11 @@ void CBasePlayer::Jump() return; } -// many features in this function use v_forward, so makevectors now. + // 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 && @@ -1565,8 +1534,6 @@ void CBasePlayer::Jump() } } - - // 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 :( @@ -1604,7 +1571,6 @@ int CBasePlayer::Classify ( void ) return CLASS_PLAYER; } - void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { // Positive score always adds @@ -1614,7 +1580,7 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { if ( pev->frags < 0 ) // Can't go more negative return; - + if ( -score > pev->frags ) // Will this go negative? { score = -pev->frags; // Sum will be 0 @@ -1633,7 +1599,6 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) MESSAGE_END(); } - void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { int index = entindex(); @@ -1749,14 +1714,6 @@ void CBasePlayer::UpdateStatusBar() } } - - - - - - - - #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 @@ -1766,7 +1723,7 @@ void CBasePlayer::UpdateStatusBar() 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" @@ -1778,7 +1735,7 @@ void CBasePlayer::PreThink(void) return; // intermission or finale UTIL_MakeVectors(pev->v_angle); // is this still used? - + ItemPreFrame( ); WaterMove(); @@ -1787,10 +1744,9 @@ void CBasePlayer::PreThink(void) 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(); @@ -1813,7 +1769,7 @@ void CBasePlayer::PreThink(void) { CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); float vel; - + if ( !pTrain ) { TraceResult trainTrace; @@ -1824,7 +1780,6 @@ void CBasePlayer::PreThink(void) 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" ); @@ -1859,8 +1814,8 @@ void CBasePlayer::PreThink(void) m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; } - - } else if (m_iTrain & TRAIN_ACTIVE) + } + else if( m_iTrain & TRAIN_ACTIVE ) m_iTrain = TRAIN_NEW; // turn off train if (pev->button & IN_JUMP) @@ -1870,7 +1825,6 @@ void CBasePlayer::PreThink(void) 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(); @@ -1931,8 +1885,6 @@ void CBasePlayer::PreThink(void) 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 - @@ -1967,7 +1919,6 @@ void CBasePlayer::PreThink(void) /* */ - void CBasePlayer::CheckTimeBasedDamage() { int i; @@ -1981,7 +1932,7 @@ void CBasePlayer::CheckTimeBasedDamage() // only check for time based damage approx. every 2 seconds if ( fabs( gpGlobals->time - m_tbdPrev ) < 2.0 ) return; - + m_tbdPrev = gpGlobals->time; for (i = 0; i < CDMG_TIMEBASED; i++) @@ -1996,7 +1947,7 @@ void CBasePlayer::CheckTimeBasedDamage() bDuration = PARALYZE_DURATION; break; case itbd_NerveGas: -// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); + //TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); bDuration = NERVEGAS_DURATION; break; case itbd_Poison: @@ -2004,7 +1955,7 @@ void CBasePlayer::CheckTimeBasedDamage() bDuration = POISON_DURATION; break; case itbd_Radiation: -// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); + //TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); bDuration = RADIATION_DURATION; break; case itbd_DrownRecover: @@ -2020,15 +1971,15 @@ void CBasePlayer::CheckTimeBasedDamage() bDuration = 4; // get up to 5*10 = 50 points back break; case itbd_Acid: -// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); + //TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); bDuration = ACID_DURATION; break; case itbd_SlowBurn: -// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); + //TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); bDuration = SLOWBURN_DURATION; break; case itbd_SlowFreeze: -// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); + //TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); bDuration = SLOWFREEZE_DURATION; break; default: @@ -2049,11 +2000,11 @@ void CBasePlayer::CheckTimeBasedDamage() } } - // 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); } @@ -2129,7 +2080,6 @@ Things powered by the battery 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 @@ -2145,9 +2095,8 @@ void CBasePlayer :: UpdateGeigerCounter( void ) return; m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; - - // send range to radition source to client + // send range to radition source to client range = (BYTE) (m_flgeigerRange / 4); if (range != m_igeigerRangePrev) @@ -2162,7 +2111,6 @@ void CBasePlayer :: UpdateGeigerCounter( void ) // reset counter and semaphore if (!RANDOM_LONG(0,3)) m_flgeigerRange = 1000; - } /* @@ -2181,7 +2129,7 @@ void CBasePlayer::CheckSuitUpdate() int i; int isentence = 0; int isearch = m_iSuitPlayNext; - + // Ignore suit updates if no suit if ( !(pev->weapons & (1< 0) { // play sentence number - - char sentence[CBSENTENCENAME_MAX+1]; + char sentence[CBSENTENCENAME_MAX + 1]; strcpy(sentence, "!"); strcat(sentence, gszallsentencenames[isentence]); EMIT_SOUND_SUIT(ENT(pev), sentence); @@ -2224,14 +2171,14 @@ void CBasePlayer::CheckSuitUpdate() // play sentence group EMIT_GROUPID_SUIT(ENT(pev), -isentence); } - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; + 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 @@ -2243,8 +2190,7 @@ void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) int i; int isentence; int iempty = -1; - - + // Ignore suit updates if no suit if ( !(pev->weapons & (1<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) @@ -2315,7 +2259,7 @@ void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) } // find empty spot in queue, or overwrite last spot - + m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; if (m_iSuitPlayNext == CSUITPLAYLIST) m_iSuitPlayNext = 0; @@ -2328,7 +2272,6 @@ void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) else m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; } - } /* @@ -2340,8 +2283,7 @@ Check for turning off powerups GLOBALS ASSUMED SET: g_ulModelIndexPlayer ================ */ - static void -CheckPowerups(entvars_t *pev) +static void CheckPowerups(entvars_t *pev) { if (pev->health <= 0) return; @@ -2349,7 +2291,6 @@ CheckPowerups(entvars_t *pev) pev->modelindex = g_ulModelIndexPlayer; // don't use eyes } - //========================================================= // UpdatePlayerSound - updates the position of the player's // reserved sound slot in the sound list. @@ -2372,7 +2313,6 @@ void CBasePlayer :: UpdatePlayerSound ( void ) // 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 = pev->velocity.Length(); @@ -2394,7 +2334,7 @@ void CBasePlayer :: UpdatePlayerSound ( void ) iBodyVolume += 100; } -// convert player move speed and actions into sound audible by monsters. + // convert player move speed and actions into sound audible by monsters. if ( m_iWeaponVolume > iBodyVolume ) { m_iTargetVolume = m_iWeaponVolume; @@ -2414,7 +2354,6 @@ void CBasePlayer :: UpdatePlayerSound ( void ) 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 @@ -2469,7 +2408,6 @@ void CBasePlayer :: UpdatePlayerSound ( void ) //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); } - void CBasePlayer::PostThink() { if ( g_fGameOver ) @@ -2480,19 +2418,21 @@ void CBasePlayer::PostThink() // Handle Tank controlling if ( m_pTank != NULL ) - { // if they've moved too far from the gun, or selected a weapon, unuse the gun + { + // 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 + { + // they've moved off the platform m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; } } -// do weapon stuff + // do weapon stuff ItemPostFrame( ); // check to see if player landed hard enough to make a sound @@ -2514,12 +2454,13 @@ void CBasePlayer::PostThink() // 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 - + { + // after this point, we start doing damage float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); if ( flFallDamage > pev->health ) - {//splat + { + //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); } @@ -2535,7 +2476,7 @@ void CBasePlayer::PostThink() { SetAnimation( PLAYER_WALK ); } - } + } if (FBitSet(pev->flags, FL_ONGROUND)) { @@ -2568,7 +2509,7 @@ void CBasePlayer::PostThink() pt_end: #if defined( CLIENT_WEAPONS ) - // Decay timers on 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++ ) { @@ -2581,7 +2522,7 @@ pt_end: CBasePlayerWeapon *gun; gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - + if ( gun && gun->UseDecrement() ) { gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); @@ -2598,11 +2539,10 @@ pt_end: } // Only decrement if not flagged as NO_DECREMENT -// if ( gun->m_flPumpTime != 1000 ) - // { - // gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); - // } - + /*if ( gun->m_flPumpTime != 1000 ) + { + gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); + }*/ } pPlayerItem = pPlayerItem->m_pNext; @@ -2629,14 +2569,11 @@ pt_end: if ( m_flAmmoStartCharge < -0.001 ) m_flAmmoStartCharge = -0.001; } - - #else return; #endif } - // checks if the spot is clear of players BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) { @@ -2657,7 +2594,6 @@ BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) return TRUE; } - DLL_GLOBAL CBaseEntity *g_pLastSpawn; inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); } @@ -2677,7 +2613,7 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) player = pPlayer->edict(); -// choose a info_player_deathmatch point + // choose a info_player_deathmatch point if (g_pGameRules->IsCoOp()) { pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop"); @@ -2791,8 +2727,8 @@ void CBasePlayer::Spawn( void ) 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 - + // 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. @@ -2804,14 +2740,14 @@ void CBasePlayer::Spawn( void ) m_iFlashBattery = 99; m_flFlashLightTime = 1; // force first message -// dont let uninitialized value here hurt the player + // 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; + SET_MODEL(ENT(pev), "models/player.mdl"); + g_ulModelIndexPlayer = pev->modelindex; pev->sequence = LookupActivity( ACT_IDLE ); if ( FBitSet(pev->flags, FL_DUCKING) ) @@ -2819,7 +2755,7 @@ void CBasePlayer::Spawn( void ) else UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - pev->view_ofs = VEC_VIEW; + pev->view_ofs = VEC_VIEW; Precache(); m_HackedGunPos = Vector( 0, 32, 0 ); @@ -2851,7 +2787,6 @@ void CBasePlayer::Spawn( void ) g_pGameRules->PlayerSpawn( this ); } - void CBasePlayer :: Precache( void ) { // in the event that the player JUST spawned, and the level node graph @@ -2897,7 +2832,6 @@ void CBasePlayer :: Precache( void ) m_fInitHUD = TRUE; } - int CBasePlayer::Save( CSave &save ) { if ( !CBaseMonster::Save(save) ) @@ -2906,7 +2840,6 @@ int CBasePlayer::Save( CSave &save ) return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); } - // // Marks everything as new so the player will resend this to the hud. // @@ -2915,7 +2848,6 @@ void CBasePlayer::RenewItems(void) } - int CBasePlayer::Restore( CRestore &restore ) { if ( !CBaseMonster::Restore(restore) ) @@ -2939,10 +2871,10 @@ int CBasePlayer::Restore( CRestore &restore ) pev->fixangle = TRUE; // turn this way immediately -// Copied from spawn() for now + // Copied from spawn() for now m_bloodColor = BLOOD_COLOR_RED; - g_ulModelIndexPlayer = pev->modelindex; + g_ulModelIndexPlayer = pev->modelindex; if ( FBitSet(pev->flags, FL_DUCKING) ) { @@ -2975,12 +2907,9 @@ int CBasePlayer::Restore( CRestore &restore ) // 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; @@ -3055,7 +2984,6 @@ void CBasePlayer::SelectItem(const char *pstr) if (!pItem) return; - if (pItem == m_pActiveItem) return; @@ -3075,7 +3003,6 @@ void CBasePlayer::SelectItem(const char *pstr) } } - void CBasePlayer::SelectLastItem(void) { if (!m_pLastItem) @@ -3123,7 +3050,6 @@ void CBasePlayer::SelectPrevItem( int iItem ) { } - const char *CBasePlayer::TeamID( void ) { if ( pev == NULL ) // Not fully connected yet @@ -3133,7 +3059,6 @@ const char *CBasePlayer::TeamID( void ) return m_szTeamName; } - //============================================== // !!!UNDONE:ultra temporary SprayCan entity to apply // decal frame at a time. For PreAlpha CD @@ -3216,7 +3141,7 @@ void CBloodSplat::Spawn ( entvars_t *pevOwner ) void CBloodSplat::Spray ( void ) { TraceResult tr; - + if ( g_Language != LANGUAGE_GERMAN ) { UTIL_MakeVectors(pev->angles); @@ -3230,8 +3155,6 @@ void CBloodSplat::Spray ( void ) //============================================== - - void CBasePlayer::GiveNamedItem( const char *pszName ) { edict_t *pent; @@ -3251,8 +3174,6 @@ void CBasePlayer::GiveNamedItem( const char *pszName ) DispatchTouch( pent, ENT( pev ) ); } - - CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { TraceResult tr; @@ -3267,13 +3188,11 @@ CBaseEntity *FindEntityForward( CBaseEntity *pMe ) return NULL; } - BOOL CBasePlayer :: FlashlightIsOn( void ) { return FBitSet(pev->effects, EF_DIMLIGHT); } - void CBasePlayer :: FlashlightTurnOn( void ) { if ( !g_pGameRules->FAllowFlashlight() ) @@ -3291,22 +3210,19 @@ void CBasePlayer :: FlashlightTurnOn( void ) 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); + 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; - } /* @@ -3345,13 +3261,12 @@ void CBasePlayer::ImpulseCommands( ) // Handle use events PlayerUse(); - + int iImpulse = (int)pev->impulse; switch (iImpulse) { case 99: { - int iOn; if (!gmsgLogo) @@ -3363,8 +3278,9 @@ void CBasePlayer::ImpulseCommands( ) { iOn = 0; } - + ASSERT( gmsgLogo > 0 ); + // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgLogo, NULL, pev ); WRITE_BYTE(iOn); @@ -3385,9 +3301,8 @@ void CBasePlayer::ImpulseCommands( ) FlashlightTurnOn(); } break; - - case 201:// paint decal - + case 201: + // paint decal if ( gpGlobals->time < m_flNextDecalTime ) { // too early! @@ -3398,20 +3313,19 @@ void CBasePlayer::ImpulseCommands( ) 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 + { + // 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; } @@ -3444,8 +3358,6 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) } break; } - - case 101: gEvilImpulse101 = TRUE; GiveNamedItem( "item_suit" ); @@ -3476,12 +3388,10 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) #endif gEvilImpulse101 = FALSE; break; - case 102: // Gibbage!!! CGib::SpawnRandomGibs( pev, 1, 1 ); break; - case 103: // What the hell are you doing? pEntity = FindEntityForward( this ); @@ -3492,13 +3402,11 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) 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. + case 105:// player makes no sound for monsters to hear. { if ( m_fNoPlayerSound ) { @@ -3512,7 +3420,6 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) } break; } - case 106: // Give me the classname and targetname of this entity. pEntity = FindEntityForward( this ); @@ -3534,7 +3441,6 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) ALERT ( at_console, "Globalname: %s\n", STRING( pEntity->pev->globalname ) ); } break; - case 107: { //TraceResult tr; @@ -3551,38 +3457,39 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) ALERT( at_console, "Texture: %s\n", pTextureName ); } break; - case 195:// show shortest paths for entire level to nearest node + 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 + 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 + 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 + 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 + 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 + { + // line hit something, so paint a decal CBloodSplat *pBlood = GetClassPtr((CBloodSplat *)NULL); pBlood->Spawn( pev ); } break; - case 203:// remove creature. + case 203:// remove creature. pEntity = FindEntityForward( this ); if ( pEntity ) { @@ -3600,7 +3507,7 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { CBasePlayerItem *pInsert; - + pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; while (pInsert) @@ -3629,7 +3536,6 @@ int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) pInsert = pInsert->m_pNext; } - if (pItem->AddToPlayer( this )) { g_pGameRules->PlayerGotWeapon ( this, pItem ); @@ -3654,8 +3560,6 @@ int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) return FALSE; } - - int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { if (m_pActiveItem == pItem) @@ -3693,7 +3597,6 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) return FALSE; } - // // Returns the unique ID for the ammo, or -1 if error // @@ -3724,7 +3627,6 @@ int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) m_rgAmmo[ i ] += iAdd; - if ( gmsgAmmoPickup ) // make sure the ammo messages have been linked first { // Send the message that ammo has been picked up @@ -3739,7 +3641,6 @@ int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) return i; } - /* ============ ItemPreFrame @@ -3750,9 +3651,9 @@ Called every frame by the player PreThink void CBasePlayer::ItemPreFrame() { #if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) + if ( m_flNextAttack > 0 ) #else - if ( gpGlobals->time < m_flNextAttack ) + if ( gpGlobals->time < m_flNextAttack ) #endif { return; @@ -3764,7 +3665,6 @@ void CBasePlayer::ItemPreFrame() m_pActiveItem->ItemPreFrame( ); } - /* ============ ItemPostFrame @@ -3781,9 +3681,9 @@ void CBasePlayer::ItemPostFrame() return; #if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) + if ( m_flNextAttack > 0 ) #else - if ( gpGlobals->time < m_flNextAttack ) + if ( gpGlobals->time < m_flNextAttack ) #endif { return; @@ -3927,12 +3827,12 @@ void CBasePlayer :: UpdateClientData( void ) m_iClientHealth = pev->health; } - if (pev->armorvalue != m_iClientBattery) { m_iClientBattery = pev->armorvalue; ASSERT( gmsgBattery > 0 ); + // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); WRITE_SHORT( (int)pev->armorvalue); @@ -3982,7 +3882,7 @@ void CBasePlayer :: UpdateClientData( void ) { m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; m_iFlashBattery--; - + if (!m_iFlashBattery) FlashlightTurnOff(); } @@ -4003,10 +3903,10 @@ void CBasePlayer :: UpdateClientData( void ) 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); @@ -4034,7 +3934,7 @@ void CBasePlayer :: UpdateClientData( void ) // byte bucket pos // byte flags // ???? Icons - + // Send ALL the weapon info now int i; @@ -4065,7 +3965,6 @@ void CBasePlayer :: UpdateClientData( void ) } } - SendAmmoUpdate(); // Update all the items @@ -4087,7 +3986,6 @@ void CBasePlayer :: UpdateClientData( void ) } } - //========================================================= // FBecomeProne - Overridden for the player to set the proper // physics flags when a barnacle grabs player. @@ -4117,7 +4015,6 @@ void CBasePlayer :: BarnacleVictimReleased ( void ) m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; } - //========================================================= // Illumination // return player light level plus virtual muzzle flash @@ -4132,7 +4029,6 @@ int CBasePlayer :: Illumination( void ) return iIllum; } - void CBasePlayer :: EnableControl(BOOL fControl) { if (!fControl) @@ -4142,7 +4038,6 @@ void CBasePlayer :: EnableControl(BOOL fControl) } - #define DOT_1DEGREE 0.9998476951564 #define DOT_2DEGREE 0.9993908270191 #define DOT_3DEGREE 0.9986295347546 @@ -4209,7 +4104,6 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) if (angles.y < -12) angles.y = -12; - // always use non-sticky autoaim // UNDONE: use sever variable to chose! if (0 || g_iSkillLevel == SKILL_EASY) @@ -4242,7 +4136,6 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) return gpGlobals->v_forward; } - Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); @@ -4269,7 +4162,6 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD 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 @@ -4291,13 +4183,13 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD 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 (pev->team > 0 && pEdict->v.team == pev->team) + // continue; // don't aim at teammate if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) continue; @@ -4366,7 +4258,6 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD return Vector( 0, 0, 0 ); } - void CBasePlayer :: ResetAutoaim( ) { if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) @@ -4406,7 +4297,6 @@ int CBasePlayer :: GetCustomDecalFrames( void ) return m_nCustomSprayFrames; } - //========================================================= // DropPlayerItem - drop the named item, or if no name, // the active item. @@ -4458,7 +4348,6 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) 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 ) @@ -4488,7 +4377,6 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) // 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 { @@ -4496,7 +4384,6 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) 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. @@ -4530,7 +4417,7 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) { CBasePlayerItem *pItem; int i; - + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) { pItem = m_rgpPlayerItems[ i ]; @@ -4599,7 +4486,7 @@ void CDeadHEV::KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } -LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); +LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ) //========================================================= // ********** DeadHEV SPAWN ********** @@ -4630,7 +4517,6 @@ void CDeadHEV :: Spawn( void ) MonsterInitDead(); } - class CStripWeapons : public CPointEntity { public: @@ -4639,7 +4525,7 @@ public: private: }; -LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); +LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ) void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { @@ -4658,7 +4544,6 @@ void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY pPlayer->RemoveAllItems( FALSE ); } - class CRevertSaved : public CPointEntity { public: @@ -4686,15 +4571,15 @@ private: float m_loadTime; }; -LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); +LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ) -TYPEDESCRIPTION CRevertSaved::m_SaveData[] = +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 ); +IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ) void CRevertSaved :: KeyValue( KeyValueData *pkvd ) { @@ -4729,7 +4614,6 @@ void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP SetThink( &CRevertSaved::MessageThink ); } - void CRevertSaved :: MessageThink( void ) { UTIL_ShowMessageAll( STRING(pev->message) ); @@ -4743,7 +4627,6 @@ void CRevertSaved :: MessageThink( void ) LoadThink(); } - void CRevertSaved :: LoadThink( void ) { if ( !gpGlobals->deathmatch ) @@ -4752,7 +4635,6 @@ void CRevertSaved :: LoadThink( void ) } } - //========================================================= // Multiplayer intermission spots. //========================================================= @@ -4770,7 +4652,6 @@ void CInfoIntermission::Spawn( void ) pev->v_angle = g_vecZero; pev->nextthink = gpGlobals->time + 2;// let targets spawn! - } void CInfoIntermission::Think ( void ) @@ -4787,5 +4668,4 @@ void CInfoIntermission::Think ( void ) } } -LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); - +LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ) diff --git a/dlls/player.h b/dlls/player.h index a11d0754..e75787ee 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -15,10 +15,8 @@ #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. @@ -28,13 +26,13 @@ // // 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. +#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 @@ -69,7 +67,7 @@ typedef enum PLAYER_JUMP, PLAYER_SUPERJUMP, PLAYER_DIE, - PLAYER_ATTACK1, + PLAYER_ATTACK1 } PLAYER_ANIM; #define MAX_ID_RANGE 2048 @@ -80,7 +78,7 @@ enum sbar_data SBAR_ID_TARGETNAME = 1, SBAR_ID_TARGETHEALTH, SBAR_ID_TARGETARMOR, - SBAR_END, + SBAR_END }; #define CHAT_INTERVAL 1.0f @@ -96,20 +94,20 @@ public: 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 @@ -117,8 +115,7 @@ public: 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 + // 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 @@ -144,7 +141,7 @@ public: 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 + // 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 @@ -164,11 +161,13 @@ public: 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]; @@ -188,7 +187,7 @@ public: virtual void Spawn( void ); void Pain( void ); -// virtual void Think( void ); + //virtual void Think( void ); virtual void Jump( void ); virtual void Duck( void ); virtual void PreThink( void ); @@ -229,7 +228,7 @@ public: BOOL FlashlightIsOn( void ); void FlashlightTurnOn( void ); void FlashlightTurnOff( void ); - + void UpdatePlayerSound ( void ); void DeathSound ( void ); @@ -298,7 +297,7 @@ public: 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 ); @@ -307,9 +306,8 @@ public: float m_flStatusBarDisappearDelay; char m_SbarString0[ SBAR_STRING_SIZE ]; char m_SbarString1[ SBAR_STRING_SIZE ]; - + float m_flNextChatTime; - }; #define AUTOAIM_2DEGREES 0.0348994967025 @@ -317,7 +315,6 @@ public: #define AUTOAIM_8DEGREES 0.1391731009601 #define AUTOAIM_10DEGREES 0.1736481776669 - extern int gmsgHudText; extern BOOL gInitHUD; diff --git a/dlls/playermonster.cpp b/dlls/playermonster.cpp index 6497ea6e..9a5bf898 100644 --- a/dlls/playermonster.cpp +++ b/dlls/playermonster.cpp @@ -8,6 +8,7 @@ //========================================================= // playermonster - for scripted sequence use. //========================================================= + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -31,13 +32,14 @@ public: void HandleAnimEvent( MonsterEvent_t *pEvent ); int ISoundMask ( void ); }; -LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ); + +LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ) //========================================================= // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CPlayerMonster :: Classify ( void ) +int CPlayerMonster :: Classify ( void ) { return CLASS_PLAYER_ALLY; } @@ -100,7 +102,6 @@ void CPlayerMonster :: Spawn() 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 ) { diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 86b1bf8a..0c3cbc8f 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -142,7 +142,8 @@ public: int m_iaCustomAnglesX[10]; int m_iaCustomAnglesZ[10]; }; -LINK_ENTITY_TO_CLASS(prop, CProp); + +LINK_ENTITY_TO_CLASS(prop, CProp) const char *CProp::pSoundsWood[] = { @@ -175,7 +176,6 @@ const char *CProp::pSoundsConcrete[] = "debris/concrete3.wav", }; - const char *CProp::pSoundsGlass[] = { "debris/glass1.wav", @@ -208,14 +208,11 @@ const char **CProp::MaterialSoundList( Materials precacheMaterial, int &soundCou pSoundList = pSoundsMetal; soundCount = ARRAYSIZE(pSoundsMetal); break; - case matCinderBlock: case matRocks: pSoundList = pSoundsConcrete; soundCount = ARRAYSIZE(pSoundsConcrete); break; - - case matCeilingTile: case matNone: default: @@ -279,7 +276,6 @@ void CProp::Precache( void ) PRECACHE_SOUND("debris/bustmetal1.wav"); PRECACHE_SOUND("debris/bustmetal2.wav"); break; - case matUnbreakableGlass: case matGlass: pGibName = "models/glassgibs.mdl"; @@ -327,8 +323,8 @@ void CProp::DamageSound( void ) int i; int material = m_Material; -// if (RANDOM_LONG(0,1)) -// return; + //if (RANDOM_LONG(0,1)) + // return; if (RANDOM_LONG(0,2)) pitch = PITCH_NORM; @@ -350,21 +346,18 @@ void CProp::DamageSound( void ) 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"; @@ -374,7 +367,6 @@ void CProp::DamageSound( void ) rgpsz[5] = "debris/flesh7.wav"; i = 6; break; - case matRocks: case matCinderBlock: rgpsz[0] = "debris/concrete1.wav"; @@ -382,7 +374,6 @@ void CProp::DamageSound( void ) rgpsz[2] = "debris/concrete3.wav"; i = 3; break; - case matCeilingTile: // UNDONE: no ceiling tile shard sound yet i = 0; @@ -414,7 +405,6 @@ void CProp::Die( void ) if (fvol > 1.0) fvol = 1.0; - switch (m_Material) { case matGlass: @@ -427,7 +417,6 @@ void CProp::Die( void ) } cFlag = BREAK_GLASS; break; - case matWood: switch ( RANDOM_LONG(0,1) ) { @@ -438,7 +427,6 @@ void CProp::Die( void ) } cFlag = BREAK_WOOD; break; - case matComputer: case matMetal: switch ( RANDOM_LONG(0,1) ) @@ -450,7 +438,6 @@ void CProp::Die( void ) } cFlag = BREAK_METAL; break; - case matFlesh: switch ( RANDOM_LONG(0,1) ) { @@ -461,7 +448,6 @@ void CProp::Die( void ) } cFlag = BREAK_FLESH; break; - case matRocks: case matCinderBlock: switch ( RANDOM_LONG(0,1) ) @@ -473,13 +459,11 @@ void CProp::Die( void ) } cFlag = BREAK_CONCRETE; break; - case matCeilingTile: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); break; } - if (m_Explosion == expDirected) vecVelocity = g_vecAttackDir * 200; else @@ -553,6 +537,7 @@ void CProp::Die( void ) pev->targetname = 0; pev->solid = SOLID_NOT; + // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); @@ -599,7 +584,6 @@ void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, { CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); - //m_Holstered->m_pActiveItem->Holster(); // strange bug here. ValveWHY? // HACK: prevent attack @@ -795,7 +779,6 @@ void CProp::BounceTouch(CBaseEntity *pOther) CheckRotate(); if (m_shape == SHAPE_CYL_H) { - pev->velocity.x *= fabs(dp) * 0.8 + 0.2; pev->velocity.y *= fabs(dp) * 0.8 + 0.2; pev->velocity.z -= 20; @@ -831,7 +814,6 @@ void CProp::BounceTouch(CBaseEntity *pOther) pev->velocity.y *= m_flFloorFriction; pev->velocity.z -= 10; } - } else { @@ -874,7 +856,6 @@ void CProp::BounceSound(void) void CProp::Spawn(void) { - Precache(); if( minsH == g_vecZero ) @@ -933,8 +914,6 @@ void CProp::RespawnThink() PropRespawn(); } - - void CProp::AngleThink() { pev->nextthink = gpGlobals->time + m_flRespawnTime; @@ -1059,7 +1038,6 @@ int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flD ALERT(at_console, "Takedmg: %s %s %f %f\n", STRING(pevInflictor->classname), STRING(pevAttacker->classname), flDamage, pev->health ); // now some func_breakable code - if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) return 0; if ( pev->health <= 0 ) @@ -1085,10 +1063,10 @@ int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flD // Make a shard noise each time func breakable is hit. // Don't play shard noise if cbreakable actually died. - DamageSound(); return 1; } + void CProp::KeyValue( KeyValueData* pkvd ) { ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue); diff --git a/dlls/python.cpp b/dlls/python.cpp index 0e2a4c06..a49d0015 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -34,8 +34,8 @@ enum python_e { PYTHON_IDLE3 }; -LINK_ENTITY_TO_CLASS( weapon_python, CPython ); -LINK_ENTITY_TO_CLASS( weapon_357, CPython ); +LINK_ENTITY_TO_CLASS( weapon_python, CPython ) +LINK_ENTITY_TO_CLASS( weapon_357, CPython ) int CPython::GetItemInfo(ItemInfo *p) { @@ -78,7 +78,6 @@ void CPython::Spawn( ) FallInit();// get ready to fall down. } - void CPython::Precache( void ) { PRECACHE_MODEL("models/v_357.mdl"); @@ -115,7 +114,6 @@ BOOL CPython::Deploy( ) 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. @@ -188,7 +186,6 @@ void CPython::PrimaryAttack() // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -197,13 +194,12 @@ void CPython::PrimaryAttack() 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; + 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) @@ -214,7 +210,6 @@ void CPython::PrimaryAttack() m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } - void CPython::Reload( void ) { if ( m_pPlayer->ammo_357 <= 0 ) @@ -239,7 +234,6 @@ void CPython::Reload( void ) } } - void CPython::WeaponIdle( void ) { ResetEmptySound( ); @@ -289,8 +283,6 @@ void CPython::WeaponIdle( void ) SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); } - - class CPythonAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -314,7 +306,6 @@ class CPythonAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ); - -#endif \ No newline at end of file +LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ) +#endif diff --git a/dlls/rat.cpp b/dlls/rat.cpp index 88b1ad2d..3676d9e5 100644 --- a/dlls/rat.cpp +++ b/dlls/rat.cpp @@ -34,13 +34,14 @@ public: void SetYawSpeed( void ); int Classify ( void ); }; -LINK_ENTITY_TO_CLASS( monster_rat, CRat ); + +LINK_ENTITY_TO_CLASS( monster_rat, CRat ) //========================================================= // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CRat :: Classify ( void ) +int CRat :: Classify ( void ) { return CLASS_INSECT; } diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index a6773dcf..6a7b0558 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -36,14 +36,14 @@ enum rpg_e { RPG_HOLSTER2, // unloaded RPG_DRAW_UL, // unloaded RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget + RPG_FIDGET_UL // unloaded fidget }; -LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); +LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ) #ifndef CLIENT_DLL -LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); +LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ) //========================================================= //========================================================= @@ -99,7 +99,7 @@ void CLaserSpot::Precache( void ) PRECACHE_MODEL("sprites/laserdot.spr"); }; -LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); +LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ) //========================================================= //========================================================= @@ -204,7 +204,6 @@ void CRpgRocket :: IgniteThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - void CRpgRocket :: FollowThink( void ) { CBaseEntity *pOther = NULL; @@ -280,8 +279,6 @@ void CRpgRocket :: FollowThink( void ) } #endif - - void CRpg::Reload( void ) { int iResult = 0; @@ -355,7 +352,6 @@ void CRpg::Spawn( ) FallInit();// get ready to fall down. } - void CRpg::Precache( void ) { PRECACHE_MODEL("models/w_rpg.mdl"); @@ -413,7 +409,6 @@ BOOL CRpg::Deploy( ) return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); } - BOOL CRpg::CanHolster( void ) { if ( m_fSpotActive && m_cActiveRockets ) @@ -440,11 +435,8 @@ void CRpg::Holster( int skiplocal /* = 0 */ ) m_pSpot = NULL; } #endif - } - - void CRpg::PrimaryAttack() { if ( m_iClip ) @@ -490,7 +482,6 @@ void CRpg::PrimaryAttack() UpdateSpot( ); } - void CRpg::SecondaryAttack() { m_fSpotActive = ! m_fSpotActive; @@ -502,11 +493,9 @@ void CRpg::SecondaryAttack() m_pSpot = NULL; } #endif - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; } - void CRpg::WeaponIdle( void ) { UpdateSpot( ); @@ -547,11 +536,8 @@ void CRpg::WeaponIdle( void ) } } - - void CRpg::UpdateSpot( void ) { - #ifndef CLIENT_DLL if (m_fSpotActive) { @@ -570,10 +556,8 @@ void CRpg::UpdateSpot( void ) UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); } #endif - } - class CRpgAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -613,6 +597,6 @@ class CRpgAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); +LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ) #endif diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index ee74a3df..ed1f8216 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -38,8 +38,6 @@ enum satchel_radio_e { SATCHEL_RADIO_HOLSTER }; - - class CSatchelCharge : public CGrenade { void Spawn( void ); @@ -52,7 +50,8 @@ class CSatchelCharge : public CGrenade public: void Deactivate( void ); }; -LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ); + +LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ) //========================================================= // Deactivate - do whatever it is we do to an orphaned @@ -64,7 +63,6 @@ void CSatchelCharge::Deactivate( void ) UTIL_Remove( this ); } - void CSatchelCharge :: Spawn( void ) { Precache( ); @@ -90,7 +88,6 @@ void CSatchelCharge :: Spawn( void ) pev->sequence = 1; } - void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) { entvars_t *pevOther = pOther->pev; @@ -120,7 +117,6 @@ void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) StudioFrameAdvance( ); } - void CSatchelCharge :: SatchelThink( void ) { StudioFrameAdvance( ); @@ -167,9 +163,7 @@ void CSatchelCharge :: BounceSound( void ) } } - -LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ); - +LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ) //========================================================= // CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal @@ -223,7 +217,6 @@ void CSatchel::Spawn( ) FallInit();// get ready to fall down. } - void CSatchel::Precache( void ) { PRECACHE_MODEL("models/v_satchel.mdl"); @@ -235,7 +228,6 @@ void CSatchel::Precache( void ) UTIL_PrecacheOther( "monster_satchel" ); } - int CSatchel::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); @@ -304,7 +296,6 @@ BOOL CSatchel::Deploy( ) return TRUE; } - void CSatchel::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; @@ -327,8 +318,6 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) } } - - void CSatchel::PrimaryAttack() { switch (m_chargeReady) @@ -364,7 +353,6 @@ void CSatchel::PrimaryAttack() m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; break; } - case 2: // we're reloading, don't allow fire { @@ -373,7 +361,6 @@ void CSatchel::PrimaryAttack() } } - void CSatchel::SecondaryAttack( void ) { if ( m_chargeReady != 2 ) @@ -382,7 +369,6 @@ void CSatchel::SecondaryAttack( void ) } } - void CSatchel::Throw( void ) { if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) @@ -416,7 +402,6 @@ void CSatchel::Throw( void ) } } - void CSatchel::WeaponIdle( void ) { if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) @@ -448,7 +433,6 @@ void CSatchel::WeaponIdle( void ) #else LoadVModel ( "models/v_satchel.mdl", m_pPlayer ); #endif - SendWeaponAnim( SATCHEL_DRAW ); // use tripmine animations @@ -490,5 +474,4 @@ void DeactivateSatchels( CBasePlayer *pOwner ) pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" ); } } - #endif diff --git a/dlls/saverestore.h b/dlls/saverestore.h index 8623601f..f76613e8 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -43,7 +43,6 @@ protected: unsigned int HashString( const char *pszToken ); }; - class CSave : public CSaveRestoreBuffer { public: @@ -125,7 +124,6 @@ private: 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; @@ -166,4 +164,4 @@ private: extern CGlobalState gGlobalState; -#endif //SAVERESTORE_H +#endif //SAVERESTORE_H diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index 468bb358..c0911c94 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -16,6 +16,7 @@ // schedule.cpp - functions and data pertaining to the // monsters' AI scheduling system. //========================================================= + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -60,7 +61,7 @@ void CBaseMonster :: ClearSchedule( void ) BOOL CBaseMonster :: FScheduleDone ( void ) { ASSERT( m_pSchedule != NULL ); - + if ( m_iScheduleIndex == m_pSchedule->cTasks ) { return TRUE; @@ -106,7 +107,7 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) if ( FClassnameIs( pev, "monster_human_grunt" ) ) { Task_t *pTask = GetTask(); - + if ( pTask ) { const char *pName = NULL; @@ -119,7 +120,7 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) { pName = "No Schedule"; } - + if ( !pName ) { pName = "Unknown"; @@ -129,7 +130,6 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) } } #endif// 0 - } //========================================================= @@ -161,7 +161,7 @@ int CBaseMonster :: IScheduleFlags ( void ) { return 0; } - + // strip off all bits excepts the ones capable of breaking this schedule. return m_afConditions & m_pSchedule->iInterruptMask; } @@ -192,7 +192,6 @@ BOOL CBaseMonster :: FScheduleValid ( void ) UTIL_Sparks( tmp ); } #endif // DEBUG - // some condition has interrupted the schedule, or the schedule is done return FALSE; } @@ -218,7 +217,7 @@ void CBaseMonster :: MaintainSchedule ( void ) NextScheduledTask(); } - // validate existing schedule + // 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. @@ -250,6 +249,7 @@ void CBaseMonster :: MaintainSchedule ( void ) 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 ); @@ -278,7 +278,7 @@ void CBaseMonster :: MaintainSchedule ( void ) { SetActivity ( m_IdealActivity ); } - + if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) break; } @@ -317,7 +317,6 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } break; } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: case TASK_PLAY_SEQUENCE_FACE_TARGET: { @@ -336,7 +335,6 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) TaskComplete(); } break; - case TASK_PLAY_SEQUENCE: case TASK_PLAY_ACTIVE_IDLE: { @@ -346,8 +344,6 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } break; } - - case TASK_FACE_ENEMY: { MakeIdealYaw( m_vecEnemyLKP ); @@ -416,6 +412,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) 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 ) { @@ -436,7 +433,6 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) else if ( distance >= 270 && m_movementActivity != ACT_RUN ) m_movementActivity = ACT_RUN; } - break; } case TASK_WAIT_FOR_MOVEMENT: @@ -453,7 +449,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) if ( m_fSequenceFinished && pev->frame >= 255 ) { pev->deadflag = DEAD_DEAD; - + SetThink( NULL ); StopAnimation(); @@ -461,7 +457,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { // 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; + //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 @@ -554,11 +550,13 @@ void CBaseMonster :: SetTurnActivity ( void ) flYD = FlYawDiff(); if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn + { + // big right turn m_IdealActivity = ACT_TURN_RIGHT; } else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn + { + // big left turn m_IdealActivity = ACT_TURN_LEFT; } } @@ -575,7 +573,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_TURN_RIGHT: { float flCurrentYaw; - + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); SetTurnActivity(); @@ -584,7 +582,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_TURN_LEFT: { float flCurrentYaw; - + flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); SetTurnActivity(); @@ -673,7 +671,6 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { TaskFail(); } - break; } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: @@ -744,8 +741,8 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { // Find cover from self if no enemy available pevCover = pev; -// TaskFail(); -// return; + //TaskFail(); + //return; } else pevCover = m_hEnemy->pev; @@ -819,12 +816,10 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) SetTurnActivity(); break; } - case TASK_FACE_LASTPOSITION: MakeIdealYaw ( m_vecLastPosition ); SetTurnActivity(); break; - case TASK_FACE_TARGET: if ( m_hTargetEnt != NULL ) { @@ -867,12 +862,14 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. + { + // 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. + { + // set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); break; } @@ -901,6 +898,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) newActivity = ACT_WALK; else newActivity = ACT_RUN; + // This monster can't do this! if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) TaskComplete(); @@ -1042,7 +1040,6 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } break; } - case TASK_GET_PATH_TO_TARGET: { RouteClear(); @@ -1106,7 +1103,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } break; } -case TASK_GET_PATH_TO_BESTSCENT: + case TASK_GET_PATH_TO_BESTSCENT: { CSound *pScent; @@ -1120,7 +1117,7 @@ case TASK_GET_PATH_TO_BESTSCENT: { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - + TaskFail(); } break; @@ -1180,8 +1177,6 @@ case TASK_GET_PATH_TO_BESTSCENT: TaskComplete(); break; } - - case TASK_WAIT_FOR_MOVEMENT: { if (FRouteClear()) @@ -1190,7 +1185,6 @@ case TASK_GET_PATH_TO_BESTSCENT: } break; } - case TASK_EAT: { Eat( pTask->flData ); @@ -1205,7 +1199,7 @@ case TASK_GET_PATH_TO_BESTSCENT: case TASK_DIE: { RouteClear(); - + m_IdealActivity = GetDeathActivity(); pev->deadflag = DEAD_DYING; @@ -1260,7 +1254,6 @@ case TASK_GET_PATH_TO_BESTSCENT: } else m_IdealActivity = ACT_IDLE; - break; } case TASK_PLAY_SCRIPT: @@ -1298,24 +1291,20 @@ case TASK_GET_PATH_TO_BESTSCENT: 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 ); @@ -1397,7 +1386,6 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); } } - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); diff --git a/dlls/schedule.h b/dlls/schedule.h index 82cbdeb7..0c4fb1ce 100644 --- a/dlls/schedule.h +++ b/dlls/schedule.h @@ -25,7 +25,6 @@ #define TASKSTATUS_RUNNING_TASK 3 // Just running task #define TASKSTATUS_COMPLETE 4 // Completed, get next task - //========================================================= // These are the schedule types //========================================================= @@ -172,7 +171,7 @@ typedef enum TASK_REMEMBER, TASK_FORGET, TASK_WAIT_FOR_MOVEMENT, // wait until MovementIsComplete() - LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb) + LAST_COMMON_TASK // LEAVE THIS AT THE BOTTOM!! (sjb) } SHARED_TASKS; @@ -180,7 +179,7 @@ typedef enum enum { TARGET_MOVE_NORMAL = 0, - TARGET_MOVE_SCRIPTED = 1, + TARGET_MOVE_SCRIPTED = 1 }; @@ -194,7 +193,7 @@ enum GOAL_MOVE, GOAL_TAKE_COVER, GOAL_MOVE_TARGET, - GOAL_EAT, + GOAL_EAT }; // an array of tasks is a task list @@ -208,11 +207,10 @@ struct Task_t 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; @@ -282,7 +280,6 @@ struct WayPoint_t #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) diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 0b7c6eac..b2f2b784 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -27,7 +27,6 @@ #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 }; @@ -38,7 +37,7 @@ enum SCHED_PANIC, SCHED_STARTLE, SCHED_TARGET_CHASE_SCARED, - SCHED_TARGET_FACE_SCARED, + SCHED_TARGET_FACE_SCARED }; enum @@ -49,7 +48,7 @@ enum TASK_RUN_PATH_SCARED, TASK_SCREAM, TASK_RANDOM_SCREAM, - TASK_MOVE_TO_TARGET_RANGE_SCARED, + TASK_MOVE_TO_TARGET_RANGE_SCARED }; //========================================================= @@ -96,7 +95,7 @@ public: void DeathSound( void ); void PainSound( void ); - + void TalkInit( void ); void Killed( entvars_t *pevAttacker, int iGib ); @@ -105,7 +104,7 @@ public: virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES private: float m_painTime; @@ -113,16 +112,16 @@ private: float m_fearTime; }; -LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ); +LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ) -TYPEDESCRIPTION CScientist::m_SaveData[] = +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 ); +IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ) //========================================================= // AI Schedules Specific to this monster @@ -205,7 +204,6 @@ Schedule_t slStopFollowing[] = }, }; - Task_t tlHeal[] = { { TASK_MOVE_TO_TARGET_RANGE,(float)50 }, // Move within 60 of target ent (client) @@ -228,7 +226,6 @@ Schedule_t slHeal[] = }, }; - Task_t tlFaceTarget[] = { { TASK_STOP_MOVING, (float)0 }, @@ -251,7 +248,6 @@ Schedule_t slFaceTarget[] = }, }; - Task_t tlSciPanic[] = { { TASK_STOP_MOVING, (float)0 }, @@ -272,7 +268,6 @@ Schedule_t slSciPanic[] = }, }; - Task_t tlIdleSciStand[] = { { TASK_STOP_MOVING, 0 }, @@ -306,7 +301,6 @@ Schedule_t slIdleSciStand[] = }, }; - Task_t tlScientistCover[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! @@ -328,8 +322,6 @@ Schedule_t slScientistCover[] = }, }; - - Task_t tlScientistHide[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! @@ -355,7 +347,6 @@ Schedule_t slScientistHide[] = }, }; - Task_t tlScientistStartle[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! @@ -382,8 +373,6 @@ Schedule_t slScientistStartle[] = }, }; - - Task_t tlFear[] = { { TASK_STOP_MOVING, (float)0 }, @@ -403,7 +392,6 @@ Schedule_t slFear[] = }, }; - DEFINE_CUSTOM_SCHEDULES( CScientist ) { slFollow, @@ -420,9 +408,7 @@ DEFINE_CUSTOM_SCHEDULES( CScientist ) slFaceTargetScared, }; - -IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ); - +IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ) void CScientist::DeclineFollowing( void ) { @@ -431,7 +417,6 @@ void CScientist::DeclineFollowing( void ) PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); } - void CScientist :: Scream( void ) { if ( FOkToSpeak() ) @@ -442,7 +427,6 @@ void CScientist :: Scream( void ) } } - Activity CScientist::GetStoppedActivity( void ) { if ( m_hEnemy != NULL ) @@ -450,7 +434,6 @@ Activity CScientist::GetStoppedActivity( void ) return CTalkMonster::GetStoppedActivity(); } - void CScientist :: StartTask( Task_t *pTask ) { switch( pTask->iTask ) @@ -463,18 +446,15 @@ void CScientist :: StartTask( Task_t *pTask ) 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() ) { @@ -487,15 +467,12 @@ void CScientist :: StartTask( Task_t *pTask ) } 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 ) @@ -508,7 +485,6 @@ void CScientist :: StartTask( Task_t *pTask ) } } break; - default: CTalkMonster::StartTask( pTask ); break; @@ -525,7 +501,6 @@ void CScientist :: RunTask( Task_t *pTask ) if ( RANDOM_LONG(0,31) < 8 ) Scream(); break; - case TASK_MOVE_TO_TARGET_RANGE_SCARED: { if ( RANDOM_LONG(0,63)< 8 ) @@ -562,7 +537,6 @@ void CScientist :: RunTask( Task_t *pTask ) } } break; - case TASK_HEAL: if ( m_fSequenceFinished ) { @@ -591,7 +565,6 @@ int CScientist :: Classify ( void ) return CLASS_HUMAN_PASSIVE; } - //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. @@ -647,7 +620,6 @@ void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 0; } break; - default: CTalkMonster::HandleAnimEvent( pEvent ); } @@ -671,7 +643,7 @@ void CScientist :: Spawn( void ) 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_flDistTooFar = 256.0; m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; @@ -679,14 +651,15 @@ void CScientist :: Spawn( void ) pev->skin = 0; if ( pev->body == -1 ) - {// -1 chooses a random head + { + // -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( &CTalkMonster::FollowerUse ); } @@ -713,7 +686,6 @@ void CScientist :: Precache( void ) // Init talk data void CScientist :: TalkInit() { - CTalkMonster::TalkInit(); // scientist will try to talk to friends in this order: @@ -742,7 +714,7 @@ void CScientist :: TalkInit() 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"; @@ -759,7 +731,6 @@ void CScientist :: TalkInit() int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { - if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) { Remember( bits_MEMORY_PROVOKED ); @@ -770,7 +741,6 @@ int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f 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, @@ -783,7 +753,7 @@ int CScientist :: ISoundMask ( void ) bits_SOUND_DANGER | bits_SOUND_PLAYER; } - + //========================================================= // PainSound //========================================================= @@ -791,7 +761,7 @@ 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)) @@ -812,14 +782,12 @@ 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; @@ -832,7 +800,6 @@ void CScientist :: SetActivity ( Activity newActivity ) CTalkMonster::SetActivity( newActivity ); } - Schedule_t* CScientist :: GetScheduleOfType ( int Type ) { Schedule_t *psched; @@ -849,22 +816,16 @@ Schedule_t* CScientist :: GetScheduleOfType ( int Type ) 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 @@ -874,13 +835,10 @@ Schedule_t* CScientist :: GetScheduleOfType ( int Type ) return slIdleSciStand; else return psched; - case SCHED_HIDE: return slScientistHide; - case SCHED_STARTLE: return slScientistStartle; - case SCHED_FEAR: return slFear; } @@ -905,7 +863,7 @@ Schedule_t *CScientist :: GetSchedule ( void ) switch( m_MonsterState ) { - case MONSTERSTATE_ALERT: + case MONSTERSTATE_ALERT: case MONSTERSTATE_IDLE: if ( pEnemy ) { @@ -1032,7 +990,6 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) StopFollowing( TRUE ); } break; - case MONSTERSTATE_COMBAT: { CBaseEntity *pEnemy = m_hEnemy; @@ -1045,6 +1002,7 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) m_hEnemy = NULL; return m_IdealMonsterState; } + // Follow if only scared a little if ( m_hTargetEnt != NULL ) { @@ -1058,7 +1016,6 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) m_IdealMonsterState = MONSTERSTATE_COMBAT; return m_IdealMonsterState; } - } } break; @@ -1069,7 +1026,6 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) return CTalkMonster::GetIdealState(); } - BOOL CScientist::CanHeal( void ) { if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (m_hTargetEnt->pev->health > (m_hTargetEnt->pev->max_health * 0.5)) ) @@ -1126,7 +1082,7 @@ void CDeadScientist::KeyValue( KeyValueData *pkvd ) else CBaseMonster::KeyValue( pkvd ); } -LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ); +LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ) // // ********** DeadScientist SPAWN ********** @@ -1138,15 +1094,18 @@ void CDeadScientist :: Spawn( ) 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 + { + // -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; @@ -1163,7 +1122,6 @@ void CDeadScientist :: Spawn( ) MonsterInitDead(); } - //========================================================= // Sitting Scientist PROP //========================================================= @@ -1189,15 +1147,15 @@ public: float m_flResponseDelay; }; -LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CSittingScientist ); -TYPEDESCRIPTION CSittingScientist::m_SaveData[] = +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 ); +IMPLEMENT_SAVERESTORE( CSittingScientist, CScientist ) // animation sequence aliases typedef enum @@ -1209,7 +1167,6 @@ SITTING_ANIM_sitting2, SITTING_ANIM_sitting3 } SITTING_ANIM; - // // ********** Scientist SPAWN ********** // @@ -1235,9 +1192,11 @@ void CSittingScientist :: Spawn( ) SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! if ( pev->body == -1 ) - {// -1 chooses a random head + { + // -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; @@ -1266,7 +1225,6 @@ int CSittingScientist :: Classify ( void ) return CLASS_HUMAN_PASSIVE; } - int CSittingScientist::FriendNumber( int arrayNumber ) { static int array[3] = { 2, 1, 0 }; @@ -1275,8 +1233,6 @@ int CSittingScientist::FriendNumber( int arrayNumber ) return arrayNumber; } - - //========================================================= // sit, do stuff //========================================================= @@ -1384,7 +1340,6 @@ void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) m_hTalkTarget = (CBaseMonster *)pSpeaker; } - //========================================================= // FIdleSpeak // ask question of nearby friend, or make statement diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index d68c967f..aa3701d8 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -36,8 +36,6 @@ #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 @@ -50,7 +48,6 @@ 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. // @@ -98,7 +95,7 @@ void CCineMonster :: KeyValue( KeyValueData *pkvd ) } } -TYPEDESCRIPTION CCineMonster::m_SaveData[] = +TYPEDESCRIPTION CCineMonster::m_SaveData[] = { DEFINE_FIELD( CCineMonster, m_iszIdle, FIELD_STRING ), DEFINE_FIELD( CCineMonster, m_iszPlay, FIELD_STRING ), @@ -117,14 +114,13 @@ TYPEDESCRIPTION CCineMonster::m_SaveData[] = DEFINE_FIELD( CCineMonster, m_interruptable, FIELD_BOOLEAN ), }; +IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ) -IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); +LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ) -LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); #define CLASSNAME "scripted_sequence" -LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ); - +LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ) void CCineMonster :: Spawn( void ) { @@ -132,13 +128,11 @@ void CCineMonster :: Spawn( void ) // 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 ) ) { @@ -174,7 +168,6 @@ BOOL CCineAI :: FCanOverrideState( void ) return TRUE; } - // // CineStart // @@ -203,7 +196,6 @@ void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP } } - // This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events void CCineMonster :: Blocked( CBaseEntity *pOther ) { @@ -222,19 +214,20 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) */ } - /* entvars_t *pevOther = VARS( gpGlobals->other ); if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-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 + { + // clear the onground so physics don't bitch pevOther->flags -= FL_ONGROUND; } @@ -242,7 +235,6 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) pevOther->velocity = pev->movedir * pev->speed; pevOther->velocity.z += m_flHeight; - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE } */ @@ -292,7 +284,7 @@ int CCineMonster :: FindEntity( void ) pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); pTarget = NULL; } - + if ( !pTarget ) { CBaseEntity *pEntity = NULL; @@ -336,7 +328,6 @@ void CCineMonster :: PossessEntity( void ) return; } #endif - pTarget->m_pGoalEnt = this; pTarget->m_pCine = this; pTarget->m_hTargetEnt = this; @@ -351,17 +342,14 @@ void CCineMonster :: PossessEntity( void ) 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; @@ -375,7 +363,7 @@ void CCineMonster :: PossessEntity( void ) // 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" ); + //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) @@ -423,15 +411,12 @@ void CCineAI :: PossessEntity( void ) 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 ); @@ -449,11 +434,10 @@ void CCineAI :: PossessEntity( void ) 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) { @@ -488,7 +472,6 @@ void CCineMonster :: CineThink( void ) } } - // lookup a sequence name and setup the target monster to play it BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) { @@ -505,7 +488,6 @@ BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL comp pTarget->pev->sequence = 0; // return FALSE; } - #if 0 char *s; if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) @@ -515,7 +497,6 @@ BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL comp 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; @@ -567,13 +548,13 @@ void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) SetThink( &CBaseEntity::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 ); @@ -642,7 +623,6 @@ BOOL CBaseMonster :: ExitScriptedSequence( ) return TRUE; } - void CCineMonster::AllowInterrupt( BOOL fAllow ) { if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) @@ -650,7 +630,6 @@ void CCineMonster::AllowInterrupt( BOOL fAllow ) m_interruptable = fAllow; } - BOOL CCineMonster::CanInterrupt( void ) { if ( !m_interruptable ) @@ -664,27 +643,26 @@ BOOL CCineMonster::CanInterrupt( void ) return FALSE; } - -int CCineMonster::IgnoreConditions( void ) +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 @@ -699,12 +677,11 @@ void ScriptEntityCancel( edict_t *pentCine ) } } - // 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() ); @@ -720,7 +697,6 @@ void CCineMonster :: CancelScript( void ) } } - // find all the cinematic entities with my targetname and tell them to wait before starting void CCineMonster :: DelayStart( int state ) { @@ -746,8 +722,6 @@ void CCineMonster :: DelayStart( int state ) } } - - // Find an entity that I'm interested in and precache the sounds he'll need in the sequence. void CCineMonster :: Activate( void ) { @@ -767,7 +741,7 @@ void CCineMonster :: Activate( void ) } pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); } - + // If no entity with that targetname, check the classname if ( !pTarget ) { @@ -778,6 +752,7 @@ void CCineMonster :: Activate( void ) pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); } } + // Found a compatible entity if ( pTarget ) { @@ -792,7 +767,6 @@ void CCineMonster :: Activate( void ) } } - BOOL CBaseMonster :: CineCleanup( ) { CCineMonster *pOldCine = m_pCine; @@ -873,7 +847,7 @@ BOOL CBaseMonster :: CineCleanup( ) 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; @@ -909,16 +883,12 @@ BOOL CBaseMonster :: CineCleanup( ) pev->deadflag = DEAD_NO; } - // SetAnimation( m_MonsterState ); ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); return TRUE; } - - - class CScriptedSentence : public CBaseToggle { public: @@ -938,7 +908,6 @@ public: 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 @@ -956,7 +925,7 @@ private: #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[] = +TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = { DEFINE_FIELD( CScriptedSentence, m_iszSentence, FIELD_STRING ), DEFINE_FIELD( CScriptedSentence, m_iszEntity, FIELD_STRING ), @@ -969,10 +938,9 @@ TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), }; +IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ) -IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ); +LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ) void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) { @@ -1020,21 +988,19 @@ void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) 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) ); + //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 ) @@ -1048,15 +1014,12 @@ void CScriptedSentence :: Spawn( void ) 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; @@ -1069,7 +1032,6 @@ void CScriptedSentence :: Spawn( void ) m_flVolume = 1.0; } - void CScriptedSentence :: FindThink( void ) { CBaseMonster *pMonster = FindEntity(); @@ -1081,16 +1043,15 @@ void CScriptedSentence :: FindThink( void ) 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) ); + //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) ); + //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; @@ -1099,7 +1060,6 @@ void CScriptedSentence :: DelayThink( void ) SetThink( &CScriptedSentence::FindThink ); } - BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) { if ( pMonster ) @@ -1120,13 +1080,11 @@ BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) return FALSE; } - CBaseMonster *CScriptedSentence :: FindEntity( void ) { edict_t *pentTarget; CBaseMonster *pMonster; - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); pMonster = NULL; @@ -1137,7 +1095,7 @@ CBaseMonster *CScriptedSentence :: FindEntity( void ) { if ( AcceptableSpeaker( pMonster ) ) return pMonster; -// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); + //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)); } @@ -1159,7 +1117,6 @@ CBaseMonster *CScriptedSentence :: FindEntity( void ) return NULL; } - BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) { if ( !pTarget ) @@ -1189,15 +1146,6 @@ BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) return TRUE; } - - - - -/* - -*/ - - //========================================================= // Furniture - this is the cool comment I cut-and-pasted //========================================================= @@ -1210,9 +1158,7 @@ public: virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } }; - -LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); - +LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ) //========================================================= // Furniture is killed @@ -1241,8 +1187,8 @@ void CFurniture :: Spawn( ) pev->sequence = 0; pev->frame = 0; -// pev->nextthink += 1.0; -// SetThink( &WalkMonsterDelay); + //pev->nextthink += 1.0; + //SetThink( &WalkMonsterDelay); ResetSequenceInfo( ); pev->frame = 0; @@ -1256,5 +1202,3 @@ int CFurniture::Classify ( void ) { return CLASS_NONE; } - - diff --git a/dlls/scripted.h b/dlls/scripted.h index dee12d72..25348114 100644 --- a/dlls/scripted.h +++ b/dlls/scripted.h @@ -34,7 +34,7 @@ enum SS_INTERRUPT { SS_INTERRUPT_IDLE = 0, SS_INTERRUPT_BY_NAME, - SS_INTERRUPT_AI, + SS_INTERRUPT_AI }; // when a monster finishes an AI scripted sequence, we can choose @@ -91,7 +91,7 @@ public: int m_saved_movetype; int m_saved_solid; int m_saved_effects; -// Vector m_vecOrigOrigin; + //Vector m_vecOrigOrigin; BOOL m_interruptable; }; @@ -102,6 +102,4 @@ class CCineAI : public CCineMonster BOOL FCanOverrideState ( void ); virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); }; - - -#endif //SCRIPTED_H +#endif //SCRIPTED_H diff --git a/dlls/scriptevent.h b/dlls/scriptevent.h index 42377cf0..714ac99c 100644 --- a/dlls/scriptevent.h +++ b/dlls/scriptevent.h @@ -26,4 +26,4 @@ #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 +#endif //SCRIPTEVENT_H diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index f0575482..6fe2c74e 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -39,7 +39,7 @@ enum shotgun_e { SHOTGUN_IDLE_DEEP }; -LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); +LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ) void CShotgun::Spawn( ) { @@ -52,7 +52,6 @@ void CShotgun::Spawn( ) FallInit();// get ready to fall } - void CShotgun::Precache( void ) { PRECACHE_MODEL("models/v_shotgun.mdl"); @@ -91,7 +90,6 @@ int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } - int CShotgun::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); @@ -109,8 +107,6 @@ int CShotgun::GetItemInfo(ItemInfo *p) return 1; } - - BOOL CShotgun::Deploy( ) { return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); @@ -146,7 +142,6 @@ void CShotgun::PrimaryAttack() flags = 0; #endif - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -170,7 +165,6 @@ void CShotgun::PrimaryAttack() 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); @@ -187,7 +181,6 @@ void CShotgun::PrimaryAttack() m_fInSpecialReload = 0; } - void CShotgun::SecondaryAttack( void ) { // don't fire underwater @@ -210,14 +203,12 @@ void CShotgun::SecondaryAttack( void ) 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 @@ -260,10 +251,8 @@ void CShotgun::SecondaryAttack( void ) m_flTimeWeaponIdle = 1.5; m_fInSpecialReload = 0; - } - void CShotgun::Reload( void ) { if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) @@ -310,7 +299,6 @@ void CShotgun::Reload( void ) } } - void CShotgun::WeaponIdle( void ) { ResetEmptySound( ); @@ -371,8 +359,6 @@ void CShotgun::WeaponIdle( void ) } } - - class CShotgunAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -396,6 +382,5 @@ class CShotgunAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ); - +LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ) diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 398b8cc7..e6358eed 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -15,6 +15,7 @@ // // teamplay_gamerules.cpp // + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -136,7 +137,6 @@ void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) { } - //========================================================= //========================================================= BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) @@ -239,7 +239,6 @@ int CHalfLifeRules::ItemShouldRespawn( CItem *pItem ) return GR_ITEM_RESPAWN_NO; } - //========================================================= // At what time in the future may this Item respawn? //========================================================= diff --git a/dlls/skill.cpp b/dlls/skill.cpp index d82a607b..e73b1b38 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -19,10 +19,8 @@ #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 @@ -32,7 +30,7 @@ float GetSkillCvar( char *pName ) int iCount; float flValue; char szBuffer[ 64 ]; - + iCount = sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); flValue = CVAR_GET_FLOAT ( szBuffer ); @@ -44,4 +42,3 @@ float GetSkillCvar( char *pName ) return flValue; } - diff --git a/dlls/skill.h b/dlls/skill.h index 5ec320c2..5e784bed 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -18,15 +18,14 @@ struct skilldata_t { - int iSkillLevel; // game skill level -// Monster Health & Damage + // Monster Health & Damage float agruntHealth; float agruntDmgPunch; float apacheHealth; - + float barneyHealth; float bigmommaHealthFactor; // Multiply each node's health by this @@ -90,8 +89,7 @@ struct skilldata_t float miniturretHealth; float sentryHealth; - -// Player Weapons + // Player Weapons float plrDmgCrowbar; float plrDmg9MM; float plrDmg357; @@ -109,27 +107,27 @@ struct skilldata_t float plrDmgSatchel; float plrDmgTripmine; -// weapons shared by monsters + // weapons shared by monsters float monDmg9MM; float monDmgMP5; float monDmg12MM; float monDmgHornet; -// health/suit charge + // health/suit charge float suitchargerCapacity; float batteryCapacity; float healthchargerCapacity; float healthkitCapacity; float scientistHeal; -// monster damage adj + // monster damage adj float monHead; float monChest; float monStomach; float monLeg; float monArm; -// player damage adj + // player damage adj float plrHead; float plrChest; float plrStomach; diff --git a/dlls/sound.cpp b/dlls/sound.cpp index e745b995..b45299e8 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -24,10 +24,8 @@ #include "talkmonster.h" #include "gamerules.h" - static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); - // ==================== GENERIC AMBIENT SOUND ====================================== // runtime pitch shift and volume fadein/out structure @@ -49,7 +47,6 @@ typedef struct dynpitchvol 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 @@ -59,7 +56,6 @@ typedef struct dynpitchvol int cspinup; // each trigger hit increments counter and spinup pitch - int cspincount; int pitch; @@ -75,14 +71,13 @@ typedef struct dynpitchvol int lfofrac; int lfomult; - } dynpitchvol_t; #define CDPVPRESETMAX 27 // presets for runtime pitch and vol modulation of ambient sounds -dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = +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}, @@ -136,8 +131,9 @@ public: BOOL m_fLooping; // TRUE when the sound played will loop }; -LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); -TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = +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 ), @@ -151,7 +147,7 @@ TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), }; -IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ) // // ambient_generic - general-purpose user-defined static sound @@ -165,7 +161,6 @@ void CAmbientGeneric :: Spawn( void ) 125 : "Medium Radius" 80 : "Large Radius" */ - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) { m_flAttenuation = ATTN_NONE; @@ -183,10 +178,11 @@ void CAmbientGeneric :: Spawn( void ) m_flAttenuation = ATTN_NORM; } else - {// if the designer didn't set a sound attenuation, default to one. + { + // 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 ) @@ -196,8 +192,8 @@ void CAmbientGeneric :: Spawn( void ) SetThink( &CBaseEntity::SUB_Remove ); return; } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; // Set up think function for dynamic modification // of ambient sound's pitch or volume. Don't @@ -219,7 +215,6 @@ void CAmbientGeneric :: Spawn( void ) Precache( ); } - void CAmbientGeneric :: Precache( void ) { char* szSoundFile = (char*) STRING(pev->message); @@ -229,6 +224,7 @@ void CAmbientGeneric :: Precache( void ) if (*szSoundFile != '!') PRECACHE_SOUND(szSoundFile); } + // init all dynamic modulation parms InitModulationParms(); @@ -330,7 +326,7 @@ void CAmbientGeneric :: RampThink( void ) { 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); @@ -382,7 +378,6 @@ void CAmbientGeneric :: RampThink( void ) m_dpv.lfomult = 255; else m_dpv.lfomult = 0; - break; case LFO_RANDOM: if (pos == 255) @@ -404,7 +399,6 @@ void CAmbientGeneric :: RampThink( void ) if (pitch > 255) pitch = 255; if (pitch < 1) pitch = 1; - fChanged |= (prev != pitch); flags |= SND_CHANGE_PITCH; } @@ -418,11 +412,10 @@ void CAmbientGeneric :: RampThink( void ) 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 @@ -508,7 +501,7 @@ void CAmbientGeneric :: InitModulationParms(void) m_dpv.lforate = abs(m_dpv.lforate); m_dpv.cspincount = 1; - + if (m_dpv.cspinup) { pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; @@ -520,7 +513,7 @@ void CAmbientGeneric :: InitModulationParms(void) 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! + // if we intend to pitch shift later! } // @@ -539,8 +532,8 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle 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. + // 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 { @@ -555,22 +548,18 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle 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 - + { + // 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; @@ -588,12 +577,11 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle 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; @@ -613,31 +601,30 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle } } else - {// turn sound on + { + // 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 + // 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; + pev->nextthink = gpGlobals->time + 0.1; } } + // KeyValue - load keyvalue pairs into member data of the // ambient generic. NOTE: called BEFORE spawn! @@ -652,7 +639,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) m_dpv.preset = atoi(pkvd->szValue); pkvd->fHandled = TRUE; } - // pitchrun else if (FStrEq(pkvd->szKeyName, "pitch")) { @@ -661,8 +647,7 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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")) { @@ -672,7 +657,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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")) { @@ -685,8 +669,7 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) m_dpv.spinup = (101 - m_dpv.spinup) * 64; m_dpv.spinupsav = m_dpv.spinup; pkvd->fHandled = TRUE; - } - + } // spindown else if (FStrEq(pkvd->szKeyName, "spindown")) { @@ -700,7 +683,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) m_dpv.spindownsav = m_dpv.spindown; pkvd->fHandled = TRUE; } - // volstart else if (FStrEq(pkvd->szKeyName, "volstart")) { @@ -708,17 +690,16 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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; @@ -727,12 +708,11 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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; @@ -741,7 +721,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) m_dpv.fadeoutsav = m_dpv.fadeout; pkvd->fHandled = TRUE; } - // lfotype else if (FStrEq(pkvd->szKeyName, "lfotype")) { @@ -749,12 +728,11 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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; @@ -768,11 +746,9 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) 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")) { @@ -782,7 +758,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) pkvd->fHandled = TRUE; } - // cspinup else if (FStrEq(pkvd->szKeyName, "cspinup")) { @@ -796,7 +771,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } - // =================== ROOM SOUND FX ========================================== class CEnvSound : public CPointEntity @@ -815,19 +789,18 @@ public: float m_flRoomtype; }; -LINK_ENTITY_TO_CLASS( env_sound, CEnvSound ); -TYPEDESCRIPTION CEnvSound::m_SaveData[] = +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 ); - +IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ) void CEnvSound :: KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "radius")) { m_flRadius = atof(pkvd->szValue); @@ -853,14 +826,12 @@ BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) TraceResult tr; UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - // check if line of sight crosses water boundary, or is blocked + // 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(); @@ -888,7 +859,6 @@ 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; @@ -900,32 +870,32 @@ void CEnvSound :: Think( void ) // 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))) { - + 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) { - + 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)) { + if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) + { pPlayer->m_flSndRange = flRange; goto env_sound_Think_fast; - } else { - + } + 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 { + } + else + { // entity is affecting player but is out of range, // wait passively for another entity to usurp it... goto env_sound_Think_slow; @@ -934,7 +904,6 @@ void CEnvSound :: Think( void ) // 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) @@ -943,13 +912,13 @@ void CEnvSound :: Think( void ) 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(); @@ -961,14 +930,12 @@ void CEnvSound :: Think( void ) // 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; @@ -996,7 +963,6 @@ 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 @@ -1014,7 +980,7 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count) { int i, j, k; unsigned char temp; - + if (!fSentencesInit) return; @@ -1046,7 +1012,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres char *szgroupname; unsigned char count; char sznum[8]; - + if (!fSentencesInit) return -1; @@ -1055,7 +1021,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres szgroupname = rgsentenceg[isentenceg].szgroupname; count = rgsentenceg[isentenceg].count; - + if (count == 0) return -1; @@ -1066,7 +1032,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres strcat(szfound, szgroupname); sprintf(sznum, "%d", ipick); strcat(szfound, sznum); - + if (ipick >= count) { if (freset) @@ -1079,8 +1045,6 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres 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. @@ -1098,7 +1062,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) char sznum[8]; unsigned char ipick; int ffound = FALSE; - + if (!fSentencesInit) return -1; @@ -1147,7 +1111,6 @@ int SENTENCEG_GetIndex(const char *szgroupname) return -1; // search rgsentenceg for match on szgroupname - i = 0; while (rgsentenceg[i].count) { @@ -1233,7 +1196,6 @@ int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, return ipicknext; } - // for this entity, for the given sentence within the sentence group, stop // the sentence. @@ -1241,7 +1203,7 @@ void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) { char buffer[64]; char sznum[8]; - + if (!fSentencesInit) return; @@ -1278,7 +1240,6 @@ void SENTENCEG_Init() memset(szgroup, 0, 64); isentencegs = -1; - int filePos = 0, fileSize; byte *pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/sentences.txt", &fileSize ); if ( !pMemFile ) @@ -1335,7 +1296,7 @@ void SENTENCEG_Init() continue; buffer[j+1] = 0; - + // if new name doesn't match previous group name, // make a new group. @@ -1366,7 +1327,7 @@ void SENTENCEG_Init() } g_engfuncs.pfnFreeFile( pMemFile ); - + fSentencesInit = TRUE; // init lru lists @@ -1378,7 +1339,6 @@ void SENTENCEG_Init() USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); i++; } - } // convert sentence (sample) name to !sentencenum, return !sentencenum @@ -1412,7 +1372,7 @@ void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volu { char name[32]; if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); + EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); else ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); } @@ -1509,7 +1469,6 @@ static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer i++; } - // If we actually advanced the pointer, copy it over if ( i != filePos ) { @@ -1517,7 +1476,7 @@ static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer 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; @@ -1531,7 +1490,6 @@ static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer return NULL; } - void TEXTURETYPE_Init() { char buffer[512]; @@ -1559,7 +1517,7 @@ void TEXTURETYPE_Init() i = 0; while(buffer[i] && isspace(buffer[i])) i++; - + if (!buffer[i]) continue; @@ -1573,7 +1531,7 @@ void TEXTURETYPE_Init() // skip whitespace while(buffer[i] && isspace(buffer[i])) i++; - + if (!buffer[i]) continue; @@ -1592,7 +1550,7 @@ void TEXTURETYPE_Init() } g_engfuncs.pfnFreeFile( pMemFile ); - + fTextureTypeInit = TRUE; } @@ -1621,8 +1579,7 @@ char TEXTURETYPE_Find(char *name) float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) { -// hit the world, try to play sound based on texture material type - + // hit the world, try to play sound based on texture material type char chTextureType; float fvol; float fvolbar; @@ -1660,7 +1617,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int 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 '!' @@ -1672,7 +1629,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int // '}}' strcpy(szbuffer, pTextureName); szbuffer[CBTEXTURENAMEMAX - 1] = 0; - + // ALERT ( at_console, "texture hit: %s\n", szbuffer); // get texture type @@ -1749,7 +1706,6 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int } // did we hit a breakable? - if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) { // drop volumes, the object will already play a damaged sound @@ -1759,7 +1715,6 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int else if (chTextureType == CHAR_TEX_COMPUTER) { // play random spark if computer - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) { UTIL_Sparks( ptr->vecEndPos ); @@ -1795,23 +1750,23 @@ public: 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[] = +LINK_ENTITY_TO_CLASS( speaker, CSpeaker ) +TYPEDESCRIPTION CSpeaker::m_SaveData[] = { DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ) // // ambient_generic - general-purpose user-defined static sound @@ -1827,15 +1782,13 @@ void CSpeaker :: Spawn( void ) SetThink( &CBaseEntity::SUB_Remove ); return; } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; + 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( ); @@ -1858,14 +1811,13 @@ void CSpeaker :: SpeakerThink( void ) 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 @@ -1884,9 +1836,10 @@ void CSpeaker :: SpeakerThink( void ) case 11: szSoundFile = "C3A1_"; break; case 12: szSoundFile = "C3A2_"; break; } - } else + } + else szSoundFile = (char*) STRING(pev->message); - + if (szSoundFile[0] == '!') { // play single sentence, one shot @@ -1899,13 +1852,11 @@ void CSpeaker :: SpeakerThink( void ) 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); + 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 } @@ -1913,7 +1864,6 @@ void CSpeaker :: SpeakerThink( void ) return; } - // // ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. // @@ -1922,7 +1872,7 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ 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 @@ -1943,12 +1893,9 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ // turn off announcements pev->nextthink = 0.0; return; - } // Toggle announcements - - if ( fActive ) { // turn off announcements @@ -1958,7 +1905,7 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ { // turn on announcements pev->nextthink = gpGlobals->time + 0.1; - } + } } // KeyValue - load keyvalue pairs into member data @@ -1966,7 +1913,6 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ void CSpeaker :: KeyValue( KeyValueData *pkvd ) { - // preset if (FStrEq(pkvd->szKeyName, "preset")) { diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index ad5ef337..b59511f4 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -12,14 +12,14 @@ * 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 ); +LINK_ENTITY_TO_CLASS( soundent, CSoundEnt ) CSoundEnt *pSoundEnt; @@ -123,7 +123,6 @@ void CSoundEnt :: Think ( void ) ALERT ( at_aiconsole, "Soundlist: %d / %d (%d)\n", ISoundsInList( SOUNDLISTTYPE_ACTIVE ),ISoundsInList( SOUNDLISTTYPE_FREE ), ISoundsInList( SOUNDLISTTYPE_ACTIVE ) - m_cLastActiveSounds ); m_cLastActiveSounds = ISoundsInList ( SOUNDLISTTYPE_ACTIVE ); } - } //========================================================= @@ -150,7 +149,7 @@ void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) { // 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 = m_SoundPool[ iSound ].m_iNext; pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = pSoundEnt->m_SoundPool[ iSound ].m_iNext; } else @@ -235,14 +234,14 @@ void CSoundEnt :: Initialize ( void ) m_iActiveSound = SOUNDLIST_EMPTY; for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) - {// clear all sounds, and link them into the free sound list. + { + // 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++ ) { diff --git a/dlls/soundent.h b/dlls/soundent.h index 150daac7..6c39a6c0 100644 --- a/dlls/soundent.h +++ b/dlls/soundent.h @@ -44,7 +44,6 @@ class CSound { public: - void Clear ( void ); void Reset ( void ); @@ -67,12 +66,11 @@ public: 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 @@ -84,7 +82,7 @@ public: 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) diff --git a/dlls/spectator.cpp b/dlls/spectator.cpp index 5f91731e..e4174a31 100644 --- a/dlls/spectator.cpp +++ b/dlls/spectator.cpp @@ -18,6 +18,7 @@ // Spectator functions // + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -36,7 +37,7 @@ void CBaseSpectator::SpectatorConnect(void) pev->flags = FL_SPECTATOR; pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NOCLIP; - + m_pGoalEnt = NULL; } @@ -64,7 +65,7 @@ void CBaseSpectator::SpectatorImpulseCommand(void) edict_t *pPreviousGoal; edict_t *pCurrentGoal; BOOL bFound; - + switch (pev->impulse) { case 1: @@ -96,7 +97,7 @@ void CBaseSpectator::SpectatorImpulseCommand(void) if (!bFound) // Didn't find a good spot. break; - + pGoal = pCurrentGoal; UTIL_SetOrigin( pev, pGoal->v.origin ); pev->angles = pGoal->v.angles; @@ -144,6 +145,6 @@ void CBaseSpectator::Spawn() pev->flags = FL_SPECTATOR; pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NOCLIP; - + m_pGoalEnt = NULL; } diff --git a/dlls/squad.h b/dlls/squad.h index 9acfccb2..bb2784bb 100644 --- a/dlls/squad.h +++ b/dlls/squad.h @@ -14,7 +14,8 @@ // 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 ) \ No newline at end of file +#define bits_SQUAD_ADVANCE ( 1 << 2 ) +#define bits_SQUAD_FLUSH_ATTACK ( 1 << 3 ) diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp index c2d85351..6785018c 100644 --- a/dlls/squadmonster.cpp +++ b/dlls/squadmonster.cpp @@ -15,6 +15,7 @@ //========================================================= // Squadmonster functions //========================================================= + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -28,7 +29,7 @@ //========================================================= // Save/Restore //========================================================= -TYPEDESCRIPTION CSquadMonster::m_SaveData[] = +TYPEDESCRIPTION CSquadMonster::m_SaveData[] = { DEFINE_FIELD( CSquadMonster, m_hSquadLeader, FIELD_EHANDLE ), DEFINE_ARRAY( CSquadMonster, m_hSquadMember, FIELD_EHANDLE, MAX_SQUAD_MEMBERS - 1 ), @@ -38,12 +39,9 @@ TYPEDESCRIPTION CSquadMonster::m_SaveData[] = DEFINE_FIELD( CSquadMonster, m_flLastEnemySightTime, FIELD_TIME ), DEFINE_FIELD( CSquadMonster, m_iMySlot, FIELD_INTEGER ), - - }; -IMPLEMENT_SAVERESTORE( CSquadMonster, CBaseMonster ); - +IMPLEMENT_SAVERESTORE( CSquadMonster, CBaseMonster ) //========================================================= // OccupySlot - if any slots of the passed slots are @@ -89,7 +87,7 @@ BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) // No, use this bit pSquadLeader->m_afSquadSlots |= iMask; m_iMySlot = iMask; -// ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); + //ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); return TRUE; } } @@ -105,7 +103,7 @@ void CSquadMonster :: VacateSlot() { if ( m_iMySlot != bits_NO_SLOT && InSquad() ) { -// ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); + //ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); MySquadLeader()->m_afSquadSlots &= ~m_iMySlot; m_iMySlot = bits_NO_SLOT; } @@ -205,7 +203,6 @@ BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) // should complain here } - //========================================================= // // SquadPasteEnemyInfo - called by squad members that have @@ -275,7 +272,6 @@ void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) } } - //========================================================= // // SquadCount(), return the number of members of this squad @@ -298,7 +294,6 @@ int CSquadMonster :: SquadCount( void ) return squadCount; } - //========================================================= // // SquadRecruit(), get some monsters of my classification and @@ -310,7 +305,6 @@ 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; @@ -342,7 +336,7 @@ int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) squadCount++; } } - + pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); } } @@ -432,7 +426,7 @@ void CSquadMonster :: StartMonster( void ) if ( iSquadSize ) { - ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); + ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); } if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) ) @@ -440,7 +434,6 @@ void CSquadMonster :: StartMonster( void ) SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack pev->skin = 0; } - } } @@ -486,13 +479,11 @@ BOOL CSquadMonster :: NoFriendlyFire( void ) 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++) { @@ -522,7 +513,7 @@ MONSTERSTATE CSquadMonster :: 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 ) { @@ -605,21 +596,17 @@ BOOL CSquadMonster :: SquadMemberInRange ( const Vector &vecLocation, float flDi 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/dlls/squadmonster.h b/dlls/squadmonster.h index 3c18b937..43363b98 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -19,7 +19,6 @@ #define SF_SQUADMONSTER_LEADER 32 - #define bits_NO_SLOT 0 // HUMAN GRUNT SLOTS @@ -117,4 +116,3 @@ public: MONSTERSTATE GetIdealState ( void ); Schedule_t *GetScheduleOfType ( int iType ); }; - diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index fa6c94b2..ab79638e 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -28,7 +28,7 @@ enum w_squeak_e { WSQUEAK_IDLE1 = 0, WSQUEAK_FIDGET, WSQUEAK_JUMP, - WSQUEAK_RUN, + WSQUEAK_RUN }; enum squeak_e { @@ -55,7 +55,7 @@ class CSqueakGrenade : public CGrenade virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); - + static TYPEDESCRIPTION m_SaveData[]; static float m_flNextBounceSoundTime; @@ -72,8 +72,9 @@ class CSqueakGrenade : public CGrenade float CSqueakGrenade::m_flNextBounceSoundTime = 0; -LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ); -TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = +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 ), @@ -83,7 +84,7 @@ TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = DEFINE_FIELD( CSqueakGrenade, m_hOwner, FIELD_EHANDLE ), }; -IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ); +IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ) #define SQUEEK_DETONATE_DELAY 15.0 @@ -112,6 +113,7 @@ int CSqueakGrenade :: Classify ( void ) void CSqueakGrenade :: Spawn( void ) { Precache( ); + // motor pev->movetype = MOVETYPE_BOUNCE; pev->solid = SOLID_BBOX; @@ -158,7 +160,6 @@ void CSqueakGrenade::Precache( void ) PRECACHE_SOUND("squeek/sqk_deploy1.wav"); } - void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible @@ -195,8 +196,6 @@ 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" ); @@ -240,7 +239,7 @@ void CSqueakGrenade::HuntThink( void ) return; m_flNextHunt = gpGlobals->time + 2.0; - + CBaseEntity *pOther = NULL; Vector vecDir; TraceResult tr; @@ -316,7 +315,6 @@ void CSqueakGrenade::HuntThink( void ) pev->angles.x = 0; } - void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) { float flpitch; @@ -406,11 +404,9 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. } - #endif -LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); - +LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ) void CSqueak::Spawn( ) { @@ -427,7 +423,6 @@ void CSqueak::Spawn( ) pev->framerate = 1.0; } - void CSqueak::Precache( void ) { PRECACHE_MODEL("models/w_sqknest.mdl"); @@ -440,7 +435,6 @@ void CSqueak::Precache( void ) m_usSnarkFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" ); } - int CSqueak::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); @@ -458,8 +452,6 @@ int CSqueak::GetItemInfo(ItemInfo *p) return 1; } - - BOOL CSqueak::Deploy( ) { // play hunt sound @@ -475,7 +467,6 @@ BOOL CSqueak::Deploy( ) 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; @@ -487,12 +478,11 @@ void CSqueak::Holster( int skiplocal /* = 0 */ ) pev->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 ] ) @@ -518,19 +508,16 @@ void CSqueak::PrimaryAttack() #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 ); @@ -551,13 +538,11 @@ void CSqueak::PrimaryAttack() } } - void CSqueak::SecondaryAttack( void ) { } - void CSqueak::WeaponIdle( void ) { if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) @@ -597,5 +582,4 @@ void CSqueak::WeaponIdle( void ) } SendWeaponAnim( iAnim ); } - #endif diff --git a/dlls/stats.cpp b/dlls/stats.cpp index 2f50395c..a725af1a 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -19,7 +19,6 @@ #include "decals.h" #include "gamerules.h" - float AmmoDamage( const char *pName ) { if ( !pName ) @@ -49,7 +48,6 @@ float AmmoDamage( const char *pName ) return 0; } - void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, int skillLevel ) { FILE *fp; @@ -61,7 +59,6 @@ void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, 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 @@ -103,7 +100,7 @@ void UpdateStats( CBasePlayer *pPlayer ) while (p) { ItemInfo II; - + memset(&II, 0, sizeof(II)); p->GetItemInfo(&II); @@ -153,4 +150,3 @@ void InitStats( CBasePlayer *pPlayer ) { gStats.lastGameTime = gpGlobals->time; // Fixup stats time } - diff --git a/dlls/subs.cpp b/dlls/subs.cpp index d3560bd5..a9a8caa1 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -33,28 +33,26 @@ 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); + //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); + +LINK_ENTITY_TO_CLASS(info_null,CNullEntity) class CBaseDMStart : public CPointEntity { @@ -66,9 +64,9 @@ 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); +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 ) { @@ -132,13 +130,13 @@ void CBaseEntity :: SUB_DoNothing( void ) // Global Savedata for Delay -TYPEDESCRIPTION CBaseDelay::m_SaveData[] = +TYPEDESCRIPTION CBaseDelay::m_SaveData[] = { DEFINE_FIELD( CBaseDelay, m_flDelay, FIELD_FLOAT ), DEFINE_FIELD( CBaseDelay, m_iszKillTarget, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ) void CBaseDelay :: KeyValue( KeyValueData *pkvd ) { @@ -158,7 +156,6 @@ void CBaseDelay :: KeyValue( KeyValueData *pkvd ) } } - /* ============================== SUB_UseTargets @@ -209,8 +206,7 @@ void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity * } } -LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ); - +LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ) void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) { @@ -232,7 +228,7 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl pTemp->pev->nextthink = gpGlobals->time + m_flDelay; pTemp->SetThink( &CBaseDelay::DelayThink ); - + // Save the useType pTemp->pev->button = (int)useType; pTemp->m_iszKillTarget = m_iszKillTarget; @@ -283,7 +279,6 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl } } - /* void CBaseDelay :: SUB_UseTargetsEntMethod( void ) { @@ -314,9 +309,6 @@ void SetMovedir( entvars_t *pev ) pev->angles = g_vecZero; } - - - void CBaseDelay::DelayThink( void ) { CBaseEntity *pActivator = NULL; @@ -325,14 +317,14 @@ void CBaseDelay::DelayThink( void ) { 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[] = +TYPEDESCRIPTION CBaseToggle::m_SaveData[] = { DEFINE_FIELD( CBaseToggle, m_toggle_state, FIELD_INTEGER ), DEFINE_FIELD( CBaseToggle, m_flActivateFinished, FIELD_TIME ), @@ -354,8 +346,8 @@ TYPEDESCRIPTION CBaseToggle::m_SaveData[] = DEFINE_FIELD( CBaseToggle, m_sMaster, FIELD_STRING), DEFINE_FIELD( CBaseToggle, m_bitsDamageInflict, FIELD_INTEGER ), // damage type inflicted }; -IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ); +IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ) void CBaseToggle::KeyValue( KeyValueData *pkvd ) { @@ -394,8 +386,8 @@ 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"); - + //ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined"); + m_vecFinalDest = vecDest; // Already there? @@ -404,10 +396,10 @@ void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) 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; @@ -419,7 +411,6 @@ void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) pev->velocity = vecDestDelta / flTravelTime; } - /* ============ After moving, set origin to exact final destination, call "move done" function @@ -454,8 +445,8 @@ 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"); - + //ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined"); + m_vecFinalAngle = vecDestAngle; // Already there? @@ -464,10 +455,10 @@ void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) 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; @@ -479,7 +470,6 @@ void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) pev->avelocity = vecDestDelta / flTravelTime; } - /* ============ After rotating, set angle to exact final angle, call "move done" function @@ -494,7 +484,6 @@ void CBaseToggle :: AngularMoveDone( void ) (this->*m_pfnCallWhenMoveDone)(); } - float CBaseToggle :: AxisValue( int flags, const Vector &angles ) { if ( FBitSet(flags, SF_DOOR_ROTATE_Z) ) @@ -505,7 +494,6 @@ float CBaseToggle :: AxisValue( int flags, const Vector &angles ) return angles.y; } - void CBaseToggle :: AxisDir( entvars_t *pev ) { if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) ) @@ -516,19 +504,17 @@ void CBaseToggle :: AxisDir( entvars_t *pev ) 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 @@ -536,17 +522,14 @@ FEntIsVisible returns TRUE if the passed entity is visible to caller, even if not infront () ============= */ - BOOL -FEntIsVisible( - entvars_t* pev, - entvars_t* pevTarget) - { +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 @@ -554,6 +537,4 @@ FEntIsVisible( return TRUE; return FALSE; - } - - +} diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index a6b88a57..b626a384 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -31,7 +32,7 @@ float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: u // NOTE: m_voicePitch & m_szGrp should be fixed up by precache each save/restore -TYPEDESCRIPTION CTalkMonster::m_SaveData[] = +TYPEDESCRIPTION CTalkMonster::m_SaveData[] = { DEFINE_FIELD( CTalkMonster, m_bitsSaid, FIELD_INTEGER ), DEFINE_FIELD( CTalkMonster, m_nSpeak, FIELD_INTEGER ), @@ -47,17 +48,16 @@ TYPEDESCRIPTION CTalkMonster::m_SaveData[] = DEFINE_FIELD( CTalkMonster, m_hTalkTarget, FIELD_EHANDLE ), }; -IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ) // array of friend names -char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = +char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = { "monster_barney", "monster_scientist", "monster_sitting_scientist", }; - //========================================================= // AI Schedules Specific to talking monsters //========================================================= @@ -100,7 +100,7 @@ Task_t tlIdleSpeak[] = Schedule_t slIdleSpeak[] = { - { + { tlIdleSpeak, ARRAYSIZE ( tlIdleSpeak ), bits_COND_NEW_ENEMY | @@ -149,7 +149,6 @@ Task_t tlIdleHello[] = { 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[] = @@ -210,7 +209,6 @@ Schedule_t slMoveAway[] = }, }; - Task_t tlMoveAwayFail[] = { { TASK_STOP_MOVING, (float)0 }, @@ -228,8 +226,6 @@ Schedule_t slMoveAwayFail[] = }, }; - - Task_t tlMoveAwayFollow[] = { { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_FACE }, @@ -319,7 +315,6 @@ Schedule_t slTlkIdleWatchClient[] = }, }; - Task_t tlTlkIdleEyecontact[] = { { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to @@ -330,7 +325,7 @@ Task_t tlTlkIdleEyecontact[] = Schedule_t slTlkIdleEyecontact[] = { - { + { tlTlkIdleEyecontact, ARRAYSIZE ( tlTlkIdleEyecontact ), bits_COND_NEW_ENEMY | @@ -342,7 +337,6 @@ Schedule_t slTlkIdleEyecontact[] = }, }; - DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) { slIdleResponse, @@ -358,21 +352,19 @@ DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) slTlkIdleEyecontact, }; -IMPLEMENT_CUSTOM_SCHEDULES( CTalkMonster, CBaseMonster ); - +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 ) @@ -382,36 +374,29 @@ void CTalkMonster :: StartTask( Task_t *pTask ) 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 != NULL) { @@ -432,29 +417,24 @@ void CTalkMonster :: StartTask( Task_t *pTask ) } 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; @@ -480,25 +460,21 @@ void CTalkMonster :: StartTask( Task_t *pTask ) } } 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. @@ -543,7 +519,6 @@ void CTalkMonster :: RunTask( Task_t *pTask ) TaskComplete(); } break; - case TASK_FACE_PLAYER: { // Get edict for one player @@ -565,7 +540,6 @@ void CTalkMonster :: RunTask( Task_t *pTask ) } } break; - case TASK_TLK_EYECONTACT: if (!IsMoving() && IsTalking() && m_hTalkTarget != NULL) { @@ -577,7 +551,6 @@ void CTalkMonster :: RunTask( Task_t *pTask ) TaskComplete(); } break; - case TASK_WALK_PATH_FOR_UNITS: { float distance; @@ -613,7 +586,6 @@ void CTalkMonster :: RunTask( Task_t *pTask ) if (TaskIsComplete()) IdleHeadTurn( pev->origin ); break; - default: if (IsTalking() && m_hTalkTarget != NULL) { @@ -627,7 +599,6 @@ void CTalkMonster :: RunTask( Task_t *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 @@ -644,8 +615,6 @@ void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) CBaseMonster::Killed( pevAttacker, iGib ); } - - CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) { CBaseEntity *pFriend = pPrevious; @@ -678,7 +647,6 @@ CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, return NULL; } - void CTalkMonster::AlertFriends( void ) { CBaseEntity *pFriend = NULL; @@ -699,8 +667,6 @@ void CTalkMonster::AlertFriends( void ) } } - - void CTalkMonster::ShutUpFriends( void ) { CBaseEntity *pFriend = NULL; @@ -720,7 +686,6 @@ void CTalkMonster::ShutUpFriends( void ) } } - // 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 ) @@ -729,6 +694,7 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) int i, count; count = 0; + // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { @@ -748,7 +714,6 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) } } - float CTalkMonster::TargetDistance( void ) { // If we lose the player, or he dies, return a really large distance @@ -758,7 +723,6 @@ float CTalkMonster::TargetDistance( void ) return (m_hTargetEnt->pev->origin - pev->origin).Length(); } - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -776,7 +740,6 @@ void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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; @@ -784,12 +747,10 @@ void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) } // 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; @@ -812,14 +773,13 @@ CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) 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) @@ -847,7 +807,6 @@ CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) 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); @@ -872,7 +831,6 @@ int CTalkMonster :: GetVoicePitch( void ) return m_voicePitch + RANDOM_LONG(0,3); } - void CTalkMonster :: Touch( CBaseEntity *pOther ) { // Did the player touch me? @@ -896,8 +854,6 @@ void CTalkMonster :: Touch( CBaseEntity *pOther ) } } - - //========================================================= // IdleRespond // Respond to a previous question @@ -905,7 +861,7 @@ void CTalkMonster :: Touch( CBaseEntity *pOther ) void CTalkMonster :: IdleRespond( void ) { int pitch = GetVoicePitch(); - + // play response PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); } @@ -945,7 +901,6 @@ int CTalkMonster :: FOkToSpeak( void ) return TRUE; } - int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) { if ( fDisregardState ) @@ -1002,11 +957,10 @@ int CTalkMonster :: FIdleHello( void ) return FALSE; } - // turn head towards supplied origin void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) { - // turn head in desired direction only if ent has a turnable head + // 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; @@ -1048,11 +1002,10 @@ int CTalkMonster :: FIdleSpeak ( void ) szQuestionGroup = m_szGrp[TLK_QUESTION]; // set global min delay for next conversation duration = RANDOM_FLOAT(2.8, 3.2); - } pitch = GetVoicePitch(); - + // player using this entity is alive and wounded? CBaseEntity *pTarget = m_hTargetEnt; @@ -1210,20 +1163,16 @@ int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, 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) @@ -1231,7 +1180,6 @@ Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) return slIdleSpeakWait; else return slIdleStand; - case SCHED_IDLE_STAND: { // if never seen player, try to greet him @@ -1294,7 +1242,6 @@ Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) return slIdleStand; } - // NOTE - caller must first CTalkMonster::GetScheduleOfType, // then check result and decide what to return ie: if sci gets back // slIdleStand, return slIdleSciStand @@ -1338,9 +1285,10 @@ void CTalkMonster :: TrySmellTalk( void ) // clear smell bits periodically if ( gpGlobals->time > m_flLastSaidSmelled ) { -// ALERT ( at_aiconsole, "Clear smell bits\n" ); + //ALERT ( at_aiconsole, "Clear smell bits\n" ); ClearBits(m_bitsSaid, bit_saidSmelled); } + // smelled something? if (!FBitSet(m_bitsSaid, bit_saidSmelled) && HasConditions ( bits_COND_SMELL )) { @@ -1350,8 +1298,6 @@ void CTalkMonster :: TrySmellTalk( void ) } } - - int CTalkMonster::IRelationship( CBaseEntity *pTarget ) { if ( pTarget->IsPlayer() ) @@ -1360,7 +1306,6 @@ int CTalkMonster::IRelationship( CBaseEntity *pTarget ) return CBaseMonster::IRelationship( pTarget ); } - void CTalkMonster::StopFollowing( BOOL clearSchedule ) { if ( IsFollowing() ) @@ -1381,7 +1326,6 @@ void CTalkMonster::StopFollowing( BOOL clearSchedule ) } } - void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) { if ( m_pCine ) @@ -1397,7 +1341,6 @@ void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) ClearSchedule(); } - BOOL CTalkMonster::CanFollow( void ) { if ( m_MonsterState == MONSTERSTATE_SCRIPT ) @@ -1412,7 +1355,6 @@ BOOL CTalkMonster::CanFollow( void ) return !IsFollowing(); } - void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // Don't allow use during a scripted_sentence @@ -1461,7 +1403,6 @@ void CTalkMonster::KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } - void CTalkMonster::Precache( void ) { if ( m_iszUse ) @@ -1469,4 +1410,3 @@ void CTalkMonster::Precache( void ) if ( m_iszUnUse ) m_szGrp[TLK_UNUSE] = STRING( m_iszUnUse ); } - diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 00f2bbaa..57c417e4 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -60,10 +60,9 @@ typedef enum TLK_WOUND, TLK_MORTAL, - TLK_CGROUPS, // MUST be last entry + TLK_CGROUPS // MUST be last entry } TALKGROUPNAMES; - enum { SCHED_CANT_FOLLOW = LAST_COMMON_SCHEDULE + 1, @@ -71,7 +70,7 @@ enum SCHED_MOVE_AWAY_FOLLOW, // same, but follow afterward SCHED_MOVE_AWAY_FAIL, // Turn back toward player - LAST_TALKMONSTER_SCHEDULE, // MUST be last + LAST_TALKMONSTER_SCHEDULE // MUST be last }; enum @@ -92,7 +91,7 @@ enum 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 + LAST_TALKMONSTER_TASK // MUST be last }; class CTalkMonster : public CBaseMonster @@ -122,7 +121,6 @@ public: void HandleAnimEvent( MonsterEvent_t *pEvent ); void PrescheduleThink( void ); - // Conversations / communication int GetVoicePitch( void ); void IdleRespond( void ); @@ -137,6 +135,7 @@ public: void ShutUpFriends( void ); BOOL IsTalking( void ); void Talk( float flDuration ); + // For following BOOL CanFollow( void ); BOOL IsFollowing( void ) { return m_hTargetEnt != NULL && m_hTargetEnt->IsPlayer(); } @@ -170,14 +169,12 @@ public: 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; + 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 +#endif //TALKMONSTER_H diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index c673d4c6..52f3512a 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -15,6 +15,7 @@ // // teamplay_gamerules.cpp // + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -147,12 +148,10 @@ void CHalfLifeTeamplay :: Think ( void ) //========================================================= BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { - #ifndef NO_VOICEGAMEMGR if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) return TRUE; #endif - if ( FStrEq( pcmd, "menuselect" ) ) { if ( CMD_ARGC() < 2 ) @@ -161,7 +160,6 @@ BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd int slot = atoi( CMD_ARGV(1) ); // select the item from the current menu - return TRUE; } @@ -181,7 +179,6 @@ void CHalfLifeTeamplay :: UpdateGameMode( CBasePlayer *pPlayer ) MESSAGE_END(); } - const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { // copy out the team name from the model @@ -194,7 +191,7 @@ const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) if ( pPlayer->m_szTeamName[0] == '\0' || !IsValidTeam( pPlayer->m_szTeamName ) || defaultteam.value ) { const char *pTeamName = NULL; - + if ( defaultteam.value ) { pTeamName = team_names[0]; @@ -209,7 +206,6 @@ const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) return pPlayer->m_szTeamName; } - //========================================================= // InitHUD //========================================================= @@ -262,7 +258,6 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) } } - void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) { int damageFlags = DMG_GENERIC; @@ -312,7 +307,6 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea MESSAGE_END(); } - //========================================================= // ClientUserInfoChanged //========================================================= @@ -360,6 +354,7 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob mdls ); ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); + // recound stuff RecountTeams( TRUE ); } @@ -373,7 +368,7 @@ void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, e { if ( m_DisableDeathMessages ) return; - + if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) { CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); @@ -406,7 +401,6 @@ void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller } } - //========================================================= // IsTeamplay //========================================================= @@ -489,7 +483,6 @@ const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) return pEntity->TeamID(); } - int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) { if ( pTeamName && *pTeamName != 0 ) @@ -501,11 +494,10 @@ int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) return tm; } } - + return -1; // No match } - const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) { if ( teamIndex < 0 || teamIndex >= num_teams ) @@ -514,7 +506,6 @@ const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) return team_names[ teamIndex ]; } - BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) { if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set @@ -558,7 +549,6 @@ const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) return pTeamName; } - //========================================================= //========================================================= void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) @@ -601,9 +591,10 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) 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 ) diff --git a/dlls/tempmonster.cpp b/dlls/tempmonster.cpp index 8c996248..80341410 100644 --- a/dlls/tempmonster.cpp +++ b/dlls/tempmonster.cpp @@ -36,7 +36,8 @@ public: int Classify ( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); }; -LINK_ENTITY_TO_CLASS( my_monster, CMyMonster ); + +LINK_ENTITY_TO_CLASS( my_monster, CMyMonster ) //========================================================= // Classify - indicates this monster's place in the @@ -109,7 +110,7 @@ void CMyMonster :: Precache() PRECACHE_SOUND("mysound.wav"); PRECACHE_MODEL("models/mymodel.mdl"); -} +} //========================================================= // AI Schedules Specific to this monster diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index 2fd7f057..3af50ee2 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -27,7 +27,6 @@ #include "weapons.h" #include "soundent.h" - #define ACT_T_IDLE 1010 #define ACT_T_TAP 1020 #define ACT_T_STRIKE 1030 @@ -108,12 +107,10 @@ public: static const char *pHitWater[]; }; - - int CTentacle :: g_fFlySound; int CTentacle :: g_fSquirmSound; -LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); +LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ) // stike sounds #define TE_NONE -1 @@ -121,13 +118,13 @@ LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); #define TE_DIRT 1 #define TE_WATER 2 -const char *CTentacle::pHitSilo[] = +const char *CTentacle::pHitSilo[] = { "tentacle/te_strike1.wav", "tentacle/te_strike2.wav", }; -const char *CTentacle::pHitDirt[] = +const char *CTentacle::pHitDirt[] = { "player/pl_dirt1.wav", "player/pl_dirt2.wav", @@ -135,7 +132,7 @@ const char *CTentacle::pHitDirt[] = "player/pl_dirt4.wav", }; -const char *CTentacle::pHitWater[] = +const char *CTentacle::pHitWater[] = { "player/pl_slosh1.wav", "player/pl_slosh2.wav", @@ -143,8 +140,7 @@ const char *CTentacle::pHitWater[] = "player/pl_slosh4.wav", }; - -TYPEDESCRIPTION CTentacle::m_SaveData[] = +TYPEDESCRIPTION CTentacle::m_SaveData[] = { DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), @@ -164,8 +160,8 @@ TYPEDESCRIPTION CTentacle::m_SaveData[] = DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ) // animation sequence aliases typedef enum @@ -231,15 +227,11 @@ typedef enum TENTACLE_ANIM_none } TENTACLE_ANIM; - - - - //========================================================= // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CTentacle :: Classify ( void ) +int CTentacle :: Classify ( void ) { return CLASS_ALIEN_MONSTER; } @@ -262,7 +254,7 @@ void CTentacle :: Spawn( ) pev->takedamage = DAMAGE_AIM; pev->flags |= FL_MONSTER; - + m_bloodColor = BLOOD_COLOR_GREEN; SetThink( &CTentacle::Start ); @@ -321,7 +313,6 @@ void CTentacle :: Precache( ) PRECACHE_SOUND_ARRAY( pHitWater ); } - CTentacle::CTentacle( ) { m_flMaxYaw = 65; @@ -339,14 +330,11 @@ void CTentacle::KeyValue( KeyValueData *pkvd ) { m_iTapSound = atoi(pkvd->szValue); pkvd->fHandled = TRUE; - } else CBaseMonster::KeyValue( pkvd ); } - - int CTentacle :: Level( float dz ) { if (dz < 216) @@ -358,7 +346,6 @@ int CTentacle :: Level( float dz ) return 3; } - float CTentacle :: MyHeight( ) { switch ( MyLevel( ) ) @@ -373,7 +360,6 @@ float CTentacle :: MyHeight( ) return 0; } - int CTentacle :: MyLevel( ) { switch( pev->sequence ) @@ -385,7 +371,6 @@ int CTentacle :: MyLevel( ) 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: @@ -396,7 +381,6 @@ int CTentacle :: MyLevel( ) 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: @@ -407,10 +391,8 @@ int CTentacle :: MyLevel( ) 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: @@ -421,10 +403,8 @@ int CTentacle :: MyLevel( ) 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: @@ -435,14 +415,12 @@ int CTentacle :: MyLevel( ) 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; @@ -451,8 +429,6 @@ void CTentacle :: Test( void ) pev->nextthink = gpGlobals->time + 0.1; } - - // // TentacleThink // @@ -705,8 +681,6 @@ void CTentacle :: Cycle( void ) } } - - void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); @@ -735,8 +709,6 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T } - - void CTentacle :: DieThink( void ) { pev->nextthink = gpGlobals-> time + 0.1; @@ -810,7 +782,6 @@ void CTentacle :: DieThink( void ) } } - void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) { char *sound; @@ -843,20 +814,16 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 { @@ -882,8 +849,6 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } break; - - case 7: // roar switch( RANDOM_LONG(0,1) ) { @@ -893,33 +858,27 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 // @@ -932,7 +891,7 @@ void CTentacle :: Start( void ) { EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); g_fFlySound = TRUE; -// pev->nextthink = gpGlobals-> time + 0.1; + //pev->nextthink = gpGlobals-> time + 0.1; } else if ( !g_fSquirmSound ) { @@ -943,9 +902,6 @@ void CTentacle :: Start( void ) pev->nextthink = gpGlobals->time + 0.1; } - - - void CTentacle :: HitTouch( CBaseEntity *pOther ) { TraceResult tr = UTIL_GetGlobalTrace( ); @@ -982,7 +938,6 @@ void CTentacle :: HitTouch( CBaseEntity *pOther ) // 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) @@ -996,17 +951,12 @@ int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return 1; } - - - void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) { m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; return; } - - class CTentacleMaw : public CBaseMonster { public: @@ -1014,7 +964,7 @@ public: void Precache( ); }; -LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ); +LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ) // // Tentacle Spawn @@ -1031,7 +981,7 @@ void CTentacleMaw :: Spawn( ) pev->health = 75; pev->yaw_speed = 8; pev->sequence = 0; - + pev->angles.x = 90; // ResetSequenceInfo( ); } @@ -1040,5 +990,4 @@ void CTentacleMaw :: Precache( ) { PRECACHE_MODEL("models/maw.mdl"); } - #endif diff --git a/dlls/trains.h b/dlls/trains.h index 87aec763..f1fabaae 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -40,7 +40,7 @@ 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 ); @@ -63,7 +63,6 @@ public: #if PATH_SPARKLE_DEBUG void EXPORT Sparkle(void); #endif - float m_length; string_t m_altName; CPathTrack *m_pnext; @@ -71,7 +70,6 @@ public: CPathTrack *m_paltpath; }; - class CFuncTrackTrain : public CBaseEntity { public: @@ -123,5 +121,4 @@ public: private: unsigned short m_usAdjustPitch; }; - #endif diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 515900f8..a6e8102b 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -56,16 +56,15 @@ public: float m_frictionFraction; // Sorry, couldn't resist this name :) }; -LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ); +LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ) // Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = +TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = { DEFINE_FIELD( CFrictionModifier, m_frictionFraction, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE(CFrictionModifier,CBaseEntity); - +IMPLEMENT_SAVERESTORE( CFrictionModifier, CBaseEntity ) // Modify an entity's friction void CFrictionModifier :: Spawn( void ) @@ -76,7 +75,6 @@ void CFrictionModifier :: Spawn( void ) SetTouch( &CFrictionModifier::ChangeFriction ); } - // Sets toucher's friction to m_frictionFraction (1.0 = normal friction) void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) { @@ -84,8 +82,6 @@ void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) pOther->pev->friction = m_frictionFraction; } - - // Sets toucher's friction to m_frictionFraction (1.0 = normal friction) void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) { @@ -98,7 +94,6 @@ void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) 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 @@ -122,15 +117,16 @@ private: int m_globalstate; USE_TYPE triggerType; }; -LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ); -TYPEDESCRIPTION CAutoTrigger::m_SaveData[] = +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); +IMPLEMENT_SAVERESTORE( CAutoTrigger, CBaseDelay ) void CAutoTrigger::KeyValue( KeyValueData *pkvd ) { @@ -160,19 +156,16 @@ void CAutoTrigger::KeyValue( KeyValueData *pkvd ) 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 ) @@ -183,8 +176,6 @@ void CAutoTrigger::Think( void ) } } - - #define SF_RELAY_FIREONCE 0x0001 class CTriggerRelay : public CBaseDelay @@ -203,14 +194,15 @@ public: private: USE_TYPE triggerType; }; -LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ); -TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = +LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ) + +TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = { DEFINE_FIELD( CTriggerRelay, triggerType, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE(CTriggerRelay,CBaseDelay); +IMPLEMENT_SAVERESTORE( CTriggerRelay, CBaseDelay ) void CTriggerRelay::KeyValue( KeyValueData *pkvd ) { @@ -235,14 +227,10 @@ void CTriggerRelay::KeyValue( KeyValueData *pkvd ) CBaseDelay::KeyValue( pkvd ); } - void CTriggerRelay::Spawn( void ) { } - - - void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { SUB_UseTargets( this, triggerType, 0 ); @@ -250,7 +238,6 @@ void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE UTIL_Remove( this ); } - //********************************************************** // The Multimanager Entity - when fired, will fire up to 16 targets // at specified times. @@ -271,7 +258,6 @@ public: #if _DEBUG void EXPORT ManagerReport( void ); #endif - BOOL HasTarget( string_t targetname ); int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } @@ -298,10 +284,11 @@ private: CMultiManager *Clone( void ); }; -LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ); + +LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ) // Global Savedata for multi_manager -TYPEDESCRIPTION CMultiManager::m_SaveData[] = +TYPEDESCRIPTION CMultiManager::m_SaveData[] = { DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), @@ -310,7 +297,7 @@ TYPEDESCRIPTION CMultiManager::m_SaveData[] = DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), }; -IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle); +IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle) void CMultiManager :: KeyValue( KeyValueData *pkvd ) { @@ -340,7 +327,6 @@ void CMultiManager :: KeyValue( KeyValueData *pkvd ) } } - void CMultiManager :: Spawn( void ) { pev->solid = SOLID_NOT; @@ -371,17 +357,15 @@ void CMultiManager :: Spawn( void ) } } - 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 ) @@ -425,7 +409,6 @@ CMultiManager *CMultiManager::Clone( void ) 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 ) { @@ -461,8 +444,6 @@ void CMultiManager :: ManagerReport ( void ) #endif //*********************************************************** - - // // Render parameters trigger // @@ -470,7 +451,6 @@ void CMultiManager :: ManagerReport ( void ) // 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) @@ -484,8 +464,7 @@ public: void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; -LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); - +LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ) void CRenderFxManager :: Spawn ( void ) { @@ -516,8 +495,6 @@ void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, US } } - - class CBaseTrigger : public CBaseToggle { public: @@ -535,7 +512,7 @@ public: virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; -LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ); +LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ) /* ================ @@ -555,7 +532,6 @@ void CBaseTrigger::InitTrigger( ) SetBits( pev->effects, EF_NODRAW ); } - // // Cache user-entity-field values until spawn is called. // @@ -588,7 +564,7 @@ public: void EXPORT RadiationThink( void ); }; -LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); +LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ) // // trigger_monsterjump @@ -601,13 +577,12 @@ public: void Think( void ); }; -LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ); - +LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ) void CTriggerMonsterJump :: Spawn ( void ) { SetMovedir ( pev ); - + InitTrigger (); pev->nextthink = 0; @@ -615,14 +590,14 @@ void CTriggerMonsterJump :: Spawn ( void ) m_flHeight = 150; if ( !FStringNull ( pev->targetname ) ) - {// if targetted, spawn turned off + { + // if targetted, spawn turned off pev->solid = SOLID_NOT; UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list SetUse( &CBaseTrigger::ToggleUse ); } } - void CTriggerMonsterJump :: Think( void ) { pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE @@ -635,14 +610,16 @@ void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) entvars_t *pevOther = pOther->pev; if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-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 + { + // clear the onground so physics don't bitch pevOther->flags &= ~FL_ONGROUND; } @@ -652,7 +629,6 @@ void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) pev->nextthink = gpGlobals->time; } - //===================================== // // trigger_cdaudio - starts/stops cd audio tracks @@ -667,7 +643,7 @@ public: void Touch ( CBaseEntity *pOther ); }; -LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); +LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ) // // Changes tracks or stops CD when player touches @@ -676,7 +652,8 @@ LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) { if ( !pOther->IsPlayer() ) - {// only clients may trigger these events + { + // only clients may trigger these events return; } @@ -696,10 +673,10 @@ void CTriggerCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY 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; @@ -723,17 +700,15 @@ void PlayCDTrack( int iTrack ) } } - // 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 { @@ -746,7 +721,7 @@ public: void Play( void ); }; -LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ); +LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ) void CTargetCDAudio :: KeyValue( KeyValueData *pkvd ) { @@ -777,19 +752,18 @@ void CTargetCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP 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 ) @@ -864,19 +838,16 @@ void CTriggerHurt :: RadiationThink( void ) 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(); @@ -897,14 +868,16 @@ void CTriggerHurt :: RadiationThink( void ) 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 + { + // if the trigger is off, turn it on pev->solid = SOLID_TRIGGER; - + // Force retouch gpGlobals->force_retouch++; } else - {// turn the trigger off + { + // turn the trigger off pev->solid = SOLID_NOT; } UTIL_SetOrigin( pev, pev->origin ); @@ -935,7 +908,8 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) if ( pev->dmgtime > gpGlobals->time ) { if ( gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity + { + // too early to hurt again, and not same frame with a different entity if ( pOther->IsPlayer() ) { int playerMask = 1 << (pOther->entindex() - 1); @@ -971,13 +945,12 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) 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 + { + // 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 @@ -985,7 +958,6 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) 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) @@ -1000,7 +972,6 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) case DMG_SLOWFREEZE: fldmg = SLOWFREEZE_DAMAGE/4; break; } #endif - if ( fldmg < 0 ) pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); else @@ -1012,8 +983,6 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) // 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. @@ -1032,7 +1001,6 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) } } - /*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. @@ -1054,8 +1022,7 @@ public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ); - +LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ) void CTriggerMultiple :: Spawn( void ) { @@ -1084,7 +1051,6 @@ void CTriggerMultiple :: Spawn( void ) } } - /*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. @@ -1103,16 +1069,15 @@ public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); +LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ) + void CTriggerOnce::Spawn( void ) { m_flWait = -1; - + CTriggerMultiple :: Spawn(); } - - void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) { entvars_t *pevToucher; @@ -1134,12 +1099,10 @@ void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) 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 @@ -1163,8 +1126,8 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) 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; + // don't trigger again until reset + // pev->takedamage = DAMAGE_NO; m_hActivator = pActivator; SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); @@ -1172,7 +1135,7 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) if ( pev->message && pActivator->IsPlayer() ) { UTIL_ShowMessage( STRING(pev->message), pActivator ); -// CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); + //CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); } if (m_flWait > 0) @@ -1190,20 +1153,18 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) } } - // 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; -// } + /*if (pev->max_health) + { + pev->health = pev->max_health; + pev->takedamage = DAMAGE_YES; + pev->solid = SOLID_BBOX; + }*/ SetThink( NULL ); } - // ========================= COUNTING TRIGGER ===================================== // @@ -1216,7 +1177,7 @@ void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US if (m_cTriggersLeft < 0) return; - + BOOL fTellActivator = (m_hActivator != 0) && FClassnameIs(m_hActivator->pev, "player") && @@ -1240,11 +1201,10 @@ void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US // !!!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 @@ -1256,7 +1216,8 @@ class CTriggerCounter : public CBaseTrigger public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ); + +LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ) void CTriggerCounter :: Spawn( void ) { @@ -1277,7 +1238,7 @@ public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ); +LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ) // Define space that travels across a level transition void CTriggerVolume :: Spawn( void ) @@ -1289,7 +1250,6 @@ void CTriggerVolume :: Spawn( void ) pev->modelindex = 0; } - // Fires a target after level transition and then dies class CFireAndDie : public CBaseDelay { @@ -1299,7 +1259,8 @@ public: void Think( void ); int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; } // Always go across transitions }; -LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ); + +LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ) void CFireAndDie::Spawn( void ) { @@ -1307,21 +1268,18 @@ void CFireAndDie::Spawn( void ) // 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 { @@ -1349,10 +1307,11 @@ public: int m_changeTarget; float m_changeTargetDelay; }; -LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); + +LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ) // Global Savedata for changelevel trigger -TYPEDESCRIPTION CChangeLevel::m_SaveData[] = +TYPEDESCRIPTION CChangeLevel::m_SaveData[] = { DEFINE_ARRAY( CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost ), DEFINE_ARRAY( CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost ), @@ -1360,7 +1319,7 @@ TYPEDESCRIPTION CChangeLevel::m_SaveData[] = DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger); +IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger) // // Cache user-entity-field values until spawn is called. @@ -1396,7 +1355,6 @@ void CChangeLevel :: KeyValue( KeyValueData *pkvd ) 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. */ @@ -1416,10 +1374,9 @@ void CChangeLevel :: Spawn( void ) InitTrigger(); if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) SetTouch( &CChangeLevel::TouchChangeLevel ); -// ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); + //ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); } - void CChangeLevel :: ExecuteChangeLevel( void ) { MESSAGE_BEGIN( MSG_ALL, SVC_CDTRACK ); @@ -1431,7 +1388,6 @@ void CChangeLevel :: ExecuteChangeLevel( void ) MESSAGE_END(); } - FILE_GLOBAL char st_szNextMap[cchMapNameMost]; FILE_GLOBAL char st_szNextSpot[cchMapNameMost]; @@ -1452,7 +1408,6 @@ edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) return NULL; } - //========================================================= // CChangeLevel :: Use - allows level transitions to be // triggered by buttons, etc. @@ -1480,7 +1435,6 @@ void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) pev->dmgtime = gpGlobals->time; - CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) { @@ -1498,10 +1452,12 @@ void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) 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); @@ -1516,7 +1472,7 @@ void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) strcpy(st_szNextSpot, m_szLandmarkName); gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; } -// ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); + //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 ); } @@ -1532,7 +1488,6 @@ void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) 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 ) @@ -1560,12 +1515,10 @@ 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; @@ -1596,7 +1549,6 @@ int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) return inVolume; } - // We can only ever move 512 entities across a transition #define MAX_ENTITY 512 @@ -1618,7 +1570,7 @@ int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) while ( !FNullEnt( pentChangelevel ) ) { CChangeLevel *pTrigger; - + pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); if ( pTrigger ) { @@ -1657,7 +1609,7 @@ int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) CBaseEntity *pEntity = CBaseEntity::Instance(pent); if ( pEntity ) { -// ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); + //ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); int caps = pEntity->ObjectCaps(); if ( !(caps & FCAP_DONT_SAVE) ) { @@ -1676,11 +1628,11 @@ int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) 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, "Failed %s\n", STRING(pEntity->pev->classname) ); } -// else -// ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); + //else + // ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); } pent = pent->v.chain; } @@ -1692,12 +1644,12 @@ int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) { // Mark entity table with 1<pev->classname) ); - + //else + // ALERT( at_console, "Screened out %s\n", STRING(pEntList[j]->pev->classname) ); } } } @@ -1713,10 +1665,10 @@ 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)) { @@ -1726,10 +1678,10 @@ void NextLevel( void ) } 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 ); @@ -1737,7 +1689,6 @@ void NextLevel( void ) } } - // ============================== LADDER ======================================= class CLadder : public CBaseTrigger @@ -1747,15 +1698,14 @@ public: void Spawn( void ); void Precache( void ); }; -LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); +LINK_ENTITY_TO_CLASS( func_ladder, CLadder ) void CLadder :: KeyValue( KeyValueData *pkvd ) { CBaseTrigger::KeyValue( pkvd ); } - //========================================================= // func_ladder - makes an area vertically negotiable //========================================================= @@ -1772,7 +1722,6 @@ void CLadder :: Precache( void ) pev->effects &= ~EF_NODRAW; } - void CLadder :: Spawn( void ) { Precache(); @@ -1781,7 +1730,6 @@ void CLadder :: Spawn( void ) pev->movetype = MOVETYPE_PUSH; } - // ========================== A TRIGGER THAT PUSHES YOU =============================== class CTriggerPush : public CBaseTrigger @@ -1791,15 +1739,14 @@ public: void KeyValue( KeyValueData *pkvd ); void Touch( CBaseEntity *pOther ); }; -LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); +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 */ @@ -1825,7 +1772,6 @@ void CTriggerPush :: Spawn( ) UTIL_SetOrigin( pev, pev->origin ); // Link into the list } - void CTriggerPush :: Touch( CBaseEntity *pOther ) { entvars_t* pevToucher = pOther->pev; @@ -1851,7 +1797,8 @@ void CTriggerPush :: Touch( CBaseEntity *pOther ) UTIL_Remove( this ); } else - { // Push field, transfer to base velocity + { + // Push field, transfer to base velocity Vector vecPush = (pev->speed * pev->movedir); if ( pevToucher->flags & FL_BASEVELOCITY ) vecPush = vecPush + pevToucher->basevelocity; @@ -1859,12 +1806,11 @@ void CTriggerPush :: Touch( CBaseEntity *pOther ) pevToucher->basevelocity = vecPush; pevToucher->flags |= FL_BASEVELOCITY; -// ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); + //ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); } } } - //====================================== // teleport trigger // @@ -1878,12 +1824,13 @@ void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) // 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! + { + // no monsters allowed! if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) { return; @@ -1891,17 +1838,18 @@ void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) } if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) - {// no clients allowed + { + // 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() ) @@ -1912,7 +1860,7 @@ void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) tmp.z++; pevToucher->flags &= ~FL_ONGROUND; - + UTIL_SetOrigin( pevToucher, tmp ); pevToucher->angles = pentTarget->v.angles; @@ -1926,13 +1874,13 @@ void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) pevToucher->velocity = pevToucher->basevelocity = g_vecZero; } - class CTriggerTeleport : public CBaseTrigger { public: void Spawn( void ); }; -LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ); + +LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ) void CTriggerTeleport :: Spawn( void ) { @@ -1941,10 +1889,7 @@ void CTriggerTeleport :: Spawn( void ) SetTouch( &CBaseTrigger::TeleportTouch ); } - -LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); - - +LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ) class CTriggerSave : public CBaseTrigger { @@ -1952,7 +1897,8 @@ public: void Spawn( void ); void EXPORT SaveTouch( CBaseEntity *pOther ); }; -LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); + +LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ) void CTriggerSave::Spawn( void ) { @@ -1974,7 +1920,7 @@ void CTriggerSave::SaveTouch( CBaseEntity *pOther ) // Only save on clients if ( !pOther->IsPlayer() ) return; - + SetTouch( NULL ); UTIL_Remove( this ); SERVER_COMMAND( "autosave\n" ); @@ -1990,15 +1936,15 @@ public: void KeyValue( KeyValueData *pkvd ); void EXPORT EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; -LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); +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 ) @@ -2019,6 +1965,7 @@ void CTriggerEndSection::Spawn( void ) 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 ); @@ -2029,7 +1976,7 @@ void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) // Only save on clients if ( !pOther->IsNetClient() ) return; - + SetTouch( NULL ); if (pev->message) @@ -2043,7 +1990,7 @@ void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "section")) { -// m_iszSectionName = ALLOC_STRING( pkvd->szValue ); + //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; @@ -2052,14 +1999,14 @@ void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) CBaseTrigger::KeyValue( pkvd ); } - class CTriggerGravity : public CBaseTrigger { public: void Spawn( void ); void EXPORT GravityTouch( CBaseEntity *pOther ); }; -LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); + +LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ) void CTriggerGravity::Spawn( void ) { @@ -2076,12 +2023,6 @@ void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) pOther->pev->gravity = pev->gravity; } - - - - - - // this is a really bad idea. class CTriggerChangeTarget : public CBaseDelay { @@ -2099,14 +2040,15 @@ public: private: int m_iszNewTarget; }; -LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ); -TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = +LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ) + +TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = { DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay); +IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay) void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) { @@ -2123,7 +2065,6 @@ 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 ) ); @@ -2139,9 +2080,6 @@ void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, U } } - - - #define SF_CAMERA_PLAYER_POSITION 1 #define SF_CAMERA_PLAYER_TARGET 2 #define SF_CAMERA_PLAYER_TAKECONTROL 4 @@ -2173,9 +2111,9 @@ public: float m_acceleration; float m_deceleration; int m_state; - }; -LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); + +LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ) // Global Savedata for changelevel friction modifier TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = @@ -2195,7 +2133,7 @@ TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay); +IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay) void CTriggerCamera::Spawn( void ) { @@ -2211,7 +2149,6 @@ void CTriggerCamera::Spawn( void ) m_deceleration = 500; } - void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "wait")) @@ -2238,8 +2175,6 @@ void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) CBaseDelay::KeyValue( pkvd ); } - - void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( !ShouldToggle( useType, m_state ) ) @@ -2278,7 +2213,6 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP return; } - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) { ((CBasePlayer *)pActivator)->EnableControl(FALSE); @@ -2328,7 +2262,6 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP Move(); } - void CTriggerCamera::FollowTarget( ) { if (m_hPlayer == NULL) @@ -2372,7 +2305,6 @@ void CTriggerCamera::FollowTarget( ) 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; @@ -2404,6 +2336,7 @@ void CTriggerCamera::Move() 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(); diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 1c780ed3..477aa466 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -24,8 +25,6 @@ #define TRIPMINE_PRIMARY_VOLUME 450 - - enum tripmine_e { TRIPMINE_IDLE1 = 0, TRIPMINE_IDLE2, @@ -35,12 +34,10 @@ enum tripmine_e { TRIPMINE_HOLSTER, TRIPMINE_DRAW, TRIPMINE_WORLD, - TRIPMINE_GROUND, + TRIPMINE_GROUND }; - #ifndef CLIENT_DLL - class CTripmineGrenade : public CGrenade { void Spawn( void ); @@ -74,9 +71,9 @@ class CTripmineGrenade : public CGrenade 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 ); +LINK_ENTITY_TO_CLASS( monster_tripmine, CTripmineGrenade ) -TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = +TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = { DEFINE_FIELD( CTripmineGrenade, m_flPowerUp, FIELD_TIME ), DEFINE_FIELD( CTripmineGrenade, m_vecDir, FIELD_VECTOR ), @@ -89,12 +86,12 @@ TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = DEFINE_FIELD( CTripmineGrenade, m_pRealOwner, FIELD_EDICT ), }; -IMPLEMENT_SAVERESTORE(CTripmineGrenade,CGrenade); - +IMPLEMENT_SAVERESTORE(CTripmineGrenade,CGrenade) void CTripmineGrenade :: Spawn( void ) { Precache( ); + // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_NOT; @@ -142,7 +139,6 @@ void CTripmineGrenade :: Spawn( void ) m_vecEnd = pev->origin + m_vecDir * 2048; } - void CTripmineGrenade :: Precache( void ) { PRECACHE_MODEL("models/v_tripmine.mdl"); @@ -151,7 +147,6 @@ void CTripmineGrenade :: Precache( void ) PRECACHE_SOUND("weapons/mine_charge.wav"); } - void CTripmineGrenade :: WarningThink( void ) { // play warning sound @@ -162,7 +157,6 @@ void CTripmineGrenade :: WarningThink( void ) pev->nextthink = gpGlobals->time + 1.0; } - void CTripmineGrenade :: PowerupThink( void ) { TraceResult tr; @@ -227,7 +221,6 @@ void CTripmineGrenade :: PowerupThink( void ) pev->nextthink = gpGlobals->time + 0.1; } - void CTripmineGrenade :: KillBeam( void ) { if ( m_pBeam ) @@ -237,7 +230,6 @@ void CTripmineGrenade :: KillBeam( void ) } } - void CTripmineGrenade :: MakeBeam( void ) { TraceResult tr; @@ -261,7 +253,6 @@ void CTripmineGrenade :: MakeBeam( void ) m_pBeam->SetBrightness( 64 ); } - void CTripmineGrenade :: BeamBreakThink( void ) { BOOL bBlowup = 0; @@ -341,7 +332,6 @@ void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) EMIT_SOUND( ENT(pev), CHAN_BODY, "common/null.wav", 0.5, ATTN_NORM ); // shut off chargeup } - void CTripmineGrenade::DelayDeathThink( void ) { KillBeam(); @@ -352,7 +342,7 @@ void CTripmineGrenade::DelayDeathThink( void ) } #endif -LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ); +LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ) void CTripmine::Spawn( ) { @@ -411,7 +401,6 @@ BOOL CTripmine::Deploy( ) 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; @@ -447,7 +436,6 @@ void CTripmine::PrimaryAttack( void ) #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) @@ -471,16 +459,16 @@ void CTripmine::PrimaryAttack( void ) return; } } - else + /*else { // ALERT( at_console, "no deploy\n" ); - } + }*/ } - else + /*else { - } - + }*/ + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -520,7 +508,3 @@ void CTripmine::WeaponIdle( void ) SendWeaponAnim( iAnim ); } - - - - diff --git a/dlls/turret.cpp b/dlls/turret.cpp index f940cbb1..0da7cd54 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -48,7 +48,7 @@ typedef enum TURRET_ANIM_SPIN, TURRET_ANIM_DEPLOY, TURRET_ANIM_RETIRE, - TURRET_ANIM_DIE, + TURRET_ANIM_DIE } TURRET_ANIM; class CBaseTurret : public CBaseMonster @@ -58,7 +58,7 @@ public: 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); @@ -67,7 +67,6 @@ public: void GibMonster( void ) {} // UNDONE: Throw turret gibs? // Think functions - void EXPORT ActiveThink(void); void EXPORT SearchThink(void); void EXPORT AutoSearchThink(void); @@ -84,7 +83,7 @@ public: void EXPORT Deploy(void); void EXPORT Retire(void); - + void EXPORT Initialize(void); virtual void Ping(void); @@ -93,7 +92,7 @@ public: virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); - + static TYPEDESCRIPTION m_SaveData[]; // other functions @@ -129,13 +128,11 @@ public: 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[] = +TYPEDESCRIPTION CBaseTurret::m_SaveData[] = { DEFINE_FIELD( CBaseTurret, m_flMaxSpin, FIELD_FLOAT ), DEFINE_FIELD( CBaseTurret, m_iSpin, FIELD_INTEGER ), @@ -153,7 +150,6 @@ TYPEDESCRIPTION CBaseTurret::m_SaveData[] = 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 ), @@ -167,7 +163,7 @@ TYPEDESCRIPTION CBaseTurret::m_SaveData[] = DEFINE_FIELD( CBaseTurret, m_flSpinUpTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ); +IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ) class CTurret : public CBaseTurret { @@ -188,15 +184,14 @@ public: private: int m_iStartSpin; - }; -TYPEDESCRIPTION CTurret::m_SaveData[] = + +TYPEDESCRIPTION CTurret::m_SaveData[] = { DEFINE_FIELD( CTurret, m_iStartSpin, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ); - +IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ) class CMiniTurret : public CBaseTurret { @@ -207,9 +202,8 @@ public: void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); }; - -LINK_ENTITY_TO_CLASS( monster_turret, CTurret ); -LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ); +LINK_ENTITY_TO_CLASS( monster_turret, CTurret ) +LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ) void CBaseTurret::KeyValue( KeyValueData *pkvd ) { @@ -245,7 +239,6 @@ void CBaseTurret::KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } - void CBaseTurret::Spawn() { Precache( ); @@ -272,7 +265,6 @@ void CBaseTurret::Spawn() // m_flSightRange = TURRET_RANGE; } - void CBaseTurret::Precache( ) { PRECACHE_SOUND ("turret/tu_fire1.wav"); @@ -306,7 +298,7 @@ void CTurret::Spawn() m_iDeployHeight = 32; m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - + SetThink( &CBaseTurret::Initialize); m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); @@ -325,7 +317,7 @@ void CTurret::Precache() } void CMiniTurret::Spawn() -{ +{ Precache( ); SET_MODEL(ENT(pev), "models/miniturret.mdl"); pev->health = gSkillData.miniturretHealth; @@ -343,7 +335,6 @@ void CMiniTurret::Spawn() pev->nextthink = gpGlobals->time + 0.3; } - void CMiniTurret::Precache() { CBaseTurret::Precache( ); @@ -398,6 +389,7 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ 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); } @@ -410,12 +402,11 @@ void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ { m_iAutoStart = TRUE; } - + SetThink( &CBaseTurret::Deploy); } } - void CBaseTurret::Ping( void ) { // make the pinging noise every second while searching @@ -433,7 +424,6 @@ void CBaseTurret::Ping( void ) } } - void CBaseTurret::EyeOn( ) { if (m_pEyeGlow) @@ -446,7 +436,6 @@ void CBaseTurret::EyeOn( ) } } - void CBaseTurret::EyeOff( ) { if (m_pEyeGlow) @@ -459,7 +448,6 @@ void CBaseTurret::EyeOff( ) } } - void CBaseTurret::ActiveThink(void) { int fAttack = 0; @@ -475,7 +463,7 @@ void CBaseTurret::ActiveThink(void) SetThink( &CBaseTurret::SearchThink); return; } - + // if it's dead, look for something new if ( !m_hEnemy->IsAlive() ) { @@ -579,7 +567,7 @@ void CBaseTurret::ActiveThink(void) vec.y += 360; //ALERT(at_console, "[%.2f]", vec.x); - + if (vec.x < -180) vec.x += 360; @@ -608,14 +596,12 @@ void CBaseTurret::ActiveThink(void) 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 ); @@ -623,7 +609,6 @@ void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) 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 ); @@ -637,7 +622,6 @@ void CMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) pev->effects = pev->effects | EF_MUZZLEFLASH; } - void CBaseTurret::Deploy(void) { pev->nextthink = gpGlobals->time + 0.1; @@ -723,7 +707,6 @@ void CBaseTurret::Retire(void) } } - void CTurret::SpinUpCall(void) { StudioFrameAdvance( ); @@ -733,6 +716,7 @@ void CTurret::SpinUpCall(void) if (!m_iSpin) { SetTurretAnim( TURRET_ANIM_SPIN ); + // for the first pass, spin up the the barrel if (!m_iStartSpin) { @@ -762,7 +746,6 @@ void CTurret::SpinUpCall(void) } } - void CTurret::SpinDownCall(void) { if (m_iSpin) @@ -782,7 +765,6 @@ void CTurret::SpinDownCall(void) } } - void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) { if (pev->sequence != anim) @@ -820,7 +802,6 @@ void CBaseTurret::SetTurretAnim(TURRET_ANIM 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 @@ -845,7 +826,6 @@ void CBaseTurret::SearchThink(void) m_hEnemy = NULL;// Dead enemy forces a search for new one } - // Acquire Target if (m_hEnemy == NULL) { @@ -884,8 +864,7 @@ void CBaseTurret::SearchThink(void) } } - -// +// // This think function will deploy the turret when something comes into range. This is for // automatically activated turrets. // @@ -918,8 +897,7 @@ void CBaseTurret::AutoSearchThink(void) } } - -void CBaseTurret :: TurretDeath( void ) +void CBaseTurret :: TurretDeath( void ) { BOOL iActive = FALSE; @@ -966,7 +944,7 @@ void CBaseTurret :: TurretDeath( void ) 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 ); @@ -985,8 +963,6 @@ void CBaseTurret :: TurretDeath( void ) } } - - void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if ( ptr->iHitgroup == 10 ) @@ -1008,7 +984,6 @@ void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector } // 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 ) @@ -1050,7 +1025,7 @@ 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 ; @@ -1131,16 +1106,13 @@ int CBaseTurret::MoveTurret(void) // // ID as a machine // -int CBaseTurret::Classify ( void ) +int CBaseTurret::Classify ( void ) { if (m_iOn || m_iAutoStart) return CLASS_MACHINE; return CLASS_NONE; } - - - //========================================================= // Sentry gun - smallest turret, placed near grunt entrenchments //========================================================= @@ -1154,19 +1126,18 @@ public: 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 ); +LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ) void CSentry::Precache() { CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/sentry.mdl"); + PRECACHE_MODEL ("models/sentry.mdl"); } void CSentry::Spawn() -{ +{ Precache( ); SET_MODEL(ENT(pev), "models/sentry.mdl"); pev->health = gSkillData.sentryHealth; @@ -1189,7 +1160,7 @@ void CSentry::Spawn() 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; @@ -1231,7 +1202,6 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f return 1; } - void CSentry::SentryTouch( CBaseEntity *pOther ) { if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) @@ -1240,7 +1210,6 @@ void CSentry::SentryTouch( CBaseEntity *pOther ) } } - void CSentry :: SentryDeath( void ) { BOOL iActive = FALSE; @@ -1292,7 +1261,7 @@ void CSentry :: SentryDeath( void ) WRITE_BYTE( 8 ); // framerate MESSAGE_END(); } - + if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) { UTIL_Sparks( vecSrc ); @@ -1304,4 +1273,3 @@ void CSentry :: SentryDeath( void ) SetThink( NULL ); } } - diff --git a/dlls/util.cpp b/dlls/util.cpp index 8391d944..223f973b 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -111,7 +111,6 @@ UTIL_SharedRandomFloat */ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) { - // unsigned int range; U_Srand( (int)seed + *(int *)&low + *(int *)&high ); @@ -197,11 +196,11 @@ UTIL_GroupTrace::~UTIL_GroupTrace( void ) ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); } -TYPEDESCRIPTION gEntvarsDescription[] = +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 ), @@ -310,7 +309,6 @@ TYPEDESCRIPTION gEntvarsDescription[] = #define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) - #ifdef DEBUG edict_t *DBG_EntOfVars( const entvars_t *pev ) { @@ -323,27 +321,20 @@ edict_t *DBG_EntOfVars( const entvars_t *pev ) ((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) - { +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 ) @@ -352,7 +343,7 @@ BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeap } // ripped this out of the engine -float UTIL_AngleMod(float a) +float UTIL_AngleMod( float a ) { /*if (a < 0) { @@ -392,8 +383,8 @@ Vector UTIL_VecToAngles( const Vector &vec ) VEC_TO_ANGLES(vec, rgflVecOut); return Vector(rgflVecOut); } - -// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType ) + +// 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]; @@ -402,7 +393,6 @@ void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int 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 ); @@ -418,7 +408,7 @@ int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, co { if ( pEdict->free ) // Not in use continue; - + if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? continue; @@ -444,7 +434,6 @@ int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, co return count; } - int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) { edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); @@ -462,7 +451,7 @@ int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢e { if ( pEdict->free ) // Not in use continue; - + if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? continue; @@ -474,7 +463,7 @@ int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢e 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; @@ -502,11 +491,9 @@ int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢e return count; } - return count; } - CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) { edict_t *pentEntity; @@ -523,7 +510,6 @@ CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &v return NULL; } - CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) { edict_t *pentEntity; @@ -550,7 +536,6 @@ CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); } - CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) { CBaseEntity *pEntity = NULL; @@ -574,7 +559,6 @@ CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, flo 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 @@ -594,13 +578,11 @@ CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) return pPlayer; } - void UTIL_MakeVectors( const Vector &vecAngles ) { MAKE_VECTORS( vecAngles ); } - void UTIL_MakeAimVectors( const Vector &vecAngles ) { float rgflVec[3]; @@ -609,7 +591,6 @@ void UTIL_MakeAimVectors( const Vector &vecAngles ) MAKE_VECTORS(rgflVec); } - #define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) @@ -624,7 +605,6 @@ void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) 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]; @@ -697,7 +677,7 @@ void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, f { 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; @@ -705,9 +685,9 @@ void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, f 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 @@ -717,14 +697,11 @@ void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, f } } - - 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 @@ -736,14 +713,13 @@ void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime 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) @@ -755,24 +731,21 @@ void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) 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; @@ -781,7 +754,6 @@ void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, UTIL_ScreenFadeWrite( fade, pEntity ); } - void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) { if ( !pEntity || !pEntity->IsNetClient() ) @@ -837,8 +809,7 @@ void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) 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 ) { @@ -895,7 +866,6 @@ void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ) MESSAGE_END(); } - char *UTIL_dtos1( int d ) { static char buf[8]; @@ -934,13 +904,11 @@ void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity ) 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 ); @@ -955,13 +923,11 @@ void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTE 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 ); @@ -972,7 +938,6 @@ void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumb g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr ); } - TraceResult UTIL_GetGlobalTrace( ) { TraceResult tr; @@ -990,19 +955,16 @@ TraceResult UTIL_GetGlobalTrace( ) 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); @@ -1015,7 +977,6 @@ void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, U PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); } - float UTIL_Approach( float target, float value, float speed ) { float delta = target - value; @@ -1030,12 +991,11 @@ float UTIL_Approach( float target, float value, float speed ) 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 @@ -1057,7 +1017,6 @@ float UTIL_ApproachAngle( float target, float value, float speed ) return value; } - float UTIL_AngleDistance( float next, float cur ) { float delta = next - cur; @@ -1070,7 +1029,6 @@ float UTIL_AngleDistance( float next, float cur ) return delta; } - float UTIL_SplineFraction( float value, float scale ) { value = scale * value; @@ -1080,19 +1038,18 @@ float UTIL_SplineFraction( float value, float scale ) return 3 * valueSquared - 2 * valueSquared * value; } - char* UTIL_VarArgs( 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; @@ -1105,7 +1062,7 @@ 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); @@ -1151,7 +1108,6 @@ void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, 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 ); @@ -1208,7 +1164,6 @@ Vector UTIL_RandomBloodVector( void ) return direction; } - void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) { if ( UTIL_ShouldShowBlood( bloodColor ) ) @@ -1220,7 +1175,6 @@ void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) } } - void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { short entityIndex; @@ -1291,7 +1245,7 @@ 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 ) @@ -1340,7 +1294,6 @@ void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) MESSAGE_END(); } - void UTIL_Sparks( const Vector &position ) { MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); @@ -1351,7 +1304,6 @@ void UTIL_Sparks( const Vector &position ) MESSAGE_END(); } - void UTIL_Ricochet( const Vector &position, float scale ) { MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); @@ -1363,7 +1315,6 @@ void UTIL_Ricochet( const Vector &position, float scale ) MESSAGE_END(); } - BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) { // Everyone matches unless it's teamplay @@ -1380,7 +1331,6 @@ BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) return FALSE; } - void UTIL_StringToVector( float *pVector, const char *pString ) { char *pstr, *pfront, tempString[128]; @@ -1411,7 +1361,6 @@ void UTIL_StringToVector( float *pVector, const char *pString ) } } - void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) { char *pstr, *pfront, tempString[128]; @@ -1466,7 +1415,6 @@ Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) return sourceVector.Normalize(); } - float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) { Vector midUp = position; @@ -1497,7 +1445,6 @@ float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) 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 ) @@ -1556,7 +1503,6 @@ void UTIL_BubbleTrail( Vector from, Vector to, int count ) MESSAGE_END(); } - void UTIL_Remove( CBaseEntity *pEntity ) { if ( !pEntity ) @@ -1567,7 +1513,6 @@ void UTIL_Remove( CBaseEntity *pEntity ) pEntity->pev->targetname = 0; } - BOOL UTIL_IsValidEntity( edict_t *pent ) { if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) @@ -1575,7 +1520,6 @@ BOOL UTIL_IsValidEntity( edict_t *pent ) return TRUE; } - void UTIL_PrecacheOther( const char *szClassname ) { edict_t *pent; @@ -1624,7 +1568,6 @@ float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vecto return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); } - //========================================================= // UTIL_StripToken - for redundant keynames //========================================================= @@ -1640,13 +1583,12 @@ void UTIL_StripToken( const char *pKey, char *pDest ) pDest[i] = 0; } - // -------------------------------------------------------------- // // CSave // // -------------------------------------------------------------- -static int gSizes[FIELD_TYPECOUNT] = +static int gSizes[FIELD_TYPECOUNT] = { sizeof(float), // FIELD_FLOAT sizeof(int), // FIELD_STRING @@ -1672,46 +1614,42 @@ static int gSizes[FIELD_TYPECOUNT] = 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 ) +int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) { if ( pEntity == NULL ) return -1; return EntityIndex( pEntity->pev ); } - -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) +int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) { if ( pevLookup == NULL ) return -1; return EntityIndex( ENT( pevLookup ) ); } -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) +int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) { return EntityIndex( ENT( eoLookup ) ); } -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) +int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) { if ( !m_pdata || pentLookup == NULL ) return -1; @@ -1728,7 +1666,6 @@ int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) return -1; } - edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) { if ( !m_pdata || entityIndex < 0 ) @@ -1746,8 +1683,7 @@ edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) return NULL; } - -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) +int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) { if ( !m_pdata || entityIndex < 0 ) return 0; @@ -1759,7 +1695,6 @@ int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) return m_pdata->pTable[ entityIndex ].flags; } - void CSaveRestoreBuffer :: BufferRewind( int size ) { if ( !m_pdata ) @@ -1776,20 +1711,21 @@ void CSaveRestoreBuffer :: BufferRewind( int size ) extern "C" { unsigned _rotr ( unsigned val, int shift) { - register unsigned lobit; /* non-zero means lo bit set */ - register unsigned num = val; /* number to rotate */ + 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 */ + 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 */ - } + 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; + return num; } } #endif @@ -1807,14 +1743,12 @@ unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) 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 @@ -1825,7 +1759,6 @@ unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); } #endif - int index = hash + i; if ( index >= m_pdata->tokenCount ) index -= m_pdata->tokenCount; @@ -1848,25 +1781,21 @@ 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; @@ -1887,7 +1816,6 @@ void CSave :: WriteTime( const char *pname, const float *data, int count ) } } - void CSave :: WriteString( const char *pname, const char *pdata ) { #ifdef TOKENIZE @@ -1898,11 +1826,9 @@ void CSave :: WriteString( const char *pname, const char *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 ); @@ -1912,7 +1838,6 @@ void CSave :: WriteString( const char *pname, const int *stringId, int count ) 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; @@ -1926,24 +1851,19 @@ void CSave :: WriteString( const char *pname, const int *stringId, int count ) #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; @@ -1953,7 +1873,6 @@ void CSave :: WritePositionVector( const char *pname, const Vector &value ) WriteVector( pname, value ); } - void CSave :: WritePositionVector( const char *pname, const float *value, int count ) { int i; @@ -1972,7 +1891,6 @@ void CSave :: WritePositionVector( const char *pname, const float *value, int co } } - void CSave :: WriteFunction( const char *pname, const int *data, int count ) { const char *functionName; @@ -1984,7 +1902,6 @@ void CSave :: WriteFunction( const char *pname, const int *data, int count ) ALERT( at_error, "Invalid function pointer in entity!" ); } - void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) { int i; @@ -2003,21 +1920,17 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) 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: @@ -2033,15 +1946,11 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) } } - - 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; @@ -2076,15 +1985,15 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p { case FIELD_FLOAT: WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; + break; case FIELD_TIME: WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; + break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; + break; case FIELD_CLASSPTR: case FIELD_EVARS: case FIELD_EDICT: @@ -2116,35 +2025,30 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p } } WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); - break; + break; case FIELD_POSITION_VECTOR: WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; + break; case FIELD_VECTOR: WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - + break; case FIELD_BOOLEAN: case FIELD_INTEGER: WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - + break; case FIELD_SHORT: WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); - break; - + break; case FIELD_CHARACTER: WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); - break; - + 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; - + break; case FIELD_FUNCTION: WriteFunction( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; + break; default: ALERT( at_error, "Bad field type\n" ); } @@ -2153,7 +2057,6 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p return 1; } - void CSave :: BufferString( char *pdata, int len ) { char c = 0; @@ -2162,7 +2065,6 @@ void CSave :: BufferString( char *pdata, int len ) BufferData( &c, 1 ); // Write a null terminator } - int CSave :: DataEmpty( const char *pdata, int size ) { for ( int i = 0; i < size; i++ ) @@ -2173,14 +2075,12 @@ int CSave :: DataEmpty( const char *pdata, int size ) 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 ); @@ -2190,7 +2090,6 @@ void CSave :: BufferHeader( const char *pname, int size ) BufferData( (const char *)&hashvalue, sizeof(short) ); } - void CSave :: BufferData( const char *pdata, int size ) { if ( !m_pdata ) @@ -2208,8 +2107,6 @@ void CSave :: BufferData( const char *pdata, int size ) m_pdata->size += size; } - - // -------------------------------------------------------------- // // CRestore @@ -2262,10 +2159,10 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou timeData += time; *((float *)pOutputData) = timeData; #endif - break; + break; case FIELD_FLOAT: memcpy(pOutputData, pInputData, 4); - break; + break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: @@ -2285,7 +2182,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou int string; string = ALLOC_STRING( (char *)pInputData ); - + *((int *)pOutputData) = string; if ( !FStringNull( string ) && m_precache ) @@ -2296,7 +2193,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou PRECACHE_SOUND( (char *)STRING( string ) ); } } - break; + break; case FIELD_EVARS: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); @@ -2304,7 +2201,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou *((entvars_t **)pOutputData) = VARS(pent); else *((entvars_t **)pOutputData) = NULL; - break; + break; case FIELD_CLASSPTR: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); @@ -2312,12 +2209,12 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); else *((CBaseEntity **)pOutputData) = NULL; - break; + break; case FIELD_EDICT: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); *((edict_t **)pOutputData) = pent; - break; + break; case FIELD_EHANDLE: // Input and Output sizes are different! pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); @@ -2327,7 +2224,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); else *((EHANDLE *)pOutputData) = NULL; - break; + break; case FIELD_ENTITY: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); @@ -2335,12 +2232,12 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou *((EOFFSET *)pOutputData) = OFFSET(pent); else *((EOFFSET *)pOutputData) = 0; - break; + break; case FIELD_VECTOR: ((float *)pOutputData)[0] = ((float *)pInputData)[0]; ((float *)pOutputData)[1] = ((float *)pInputData)[1]; ((float *)pOutputData)[2] = ((float *)pInputData)[2]; - break; + break; case FIELD_POSITION_VECTOR: #ifdef __VFP_FP__ float tmp; @@ -2358,31 +2255,26 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; #endif - break; - + break; case FIELD_BOOLEAN: case FIELD_INTEGER: *((int *)pOutputData) = *( int *)pInputData; - break; - + break; case FIELD_SHORT: *((short *)pOutputData) = *( short *)pInputData; - break; - + break; case FIELD_CHARACTER: *((char *)pOutputData) = *( char *)pInputData; - break; - + break; case FIELD_POINTER: *((void**)pOutputData) = *( void **)pInputData; - break; + break; case FIELD_FUNCTION: if ( strlen( (char *)pInputData ) == 0 ) *((void**)pOutputData) = 0; else *((void**)pOutputData) = (void**)FUNCTION_FROM_NAME( (char *)pInputData ); - break; - + break; default: ALERT( at_error, "Bad field type\n" ); } @@ -2397,17 +2289,14 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou 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; @@ -2422,7 +2311,7 @@ int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p // Check the struct name if ( token != TokenHash(pname) ) // Field Set marker { -// ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); + //ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); BufferRewind( 2*sizeof(short) ); return 0; } @@ -2450,7 +2339,6 @@ int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p return 1; } - void CRestore::BufferReadHeader( HEADER *pheader ) { ASSERT( pheader!=NULL ); @@ -2461,7 +2349,7 @@ void CRestore::BufferReadHeader( HEADER *pheader ) } -short CRestore::ReadShort( void ) +short CRestore::ReadShort( void ) { short tmp = 0; @@ -2470,7 +2358,7 @@ short CRestore::ReadShort( void ) return tmp; } -int CRestore::ReadInt( void ) +int CRestore::ReadInt( void ) { int tmp = 0; @@ -2499,7 +2387,6 @@ char *CRestore::ReadNamedString( const char *pName ) #endif } - char *CRestore::BufferPointer( void ) { if ( !m_pdata ) @@ -2528,7 +2415,6 @@ void CRestore::BufferReadBytes( char *pOutput, int size ) m_pdata->size += size; } - void CRestore::BufferSkipBytes( int bytes ) { BufferReadBytes( NULL, bytes ); @@ -2556,7 +2442,7 @@ int CRestore::BufferSkipZString( void ) return len; } -int CRestore::BufferCheckZString( const char *string ) +int CRestore::BufferCheckZString( const char *string ) { if ( !m_pdata ) return 0; @@ -2570,4 +2456,3 @@ int CRestore::BufferCheckZString( const char *string ) } return 0; } - diff --git a/dlls/util.h b/dlls/util.h index b478b781..80a42af8 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -27,7 +27,6 @@ #include "physcallback.h" #endif - #include #include inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file @@ -46,18 +45,18 @@ extern globalvars_t *gpGlobals; 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) @@ -100,7 +99,6 @@ typedef int BOOL; #define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" EXPORT void mapClassName( entvars_t *pev ); void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } - // // Conversion among the three types of "entity", including identity-conversions. // @@ -129,7 +127,10 @@ inline EOFFSET OFFSET(entvars_t *pev) #endif return OFFSET(ENT(pev)); } -inline entvars_t *VARS(entvars_t *pev) { return pev; } +inline entvars_t *VARS(entvars_t *pev) +{ + return pev; +} inline entvars_t *VARS(edict_t *pent) { @@ -172,7 +173,6 @@ inline BOOL FStringNull(int iString) { return iString == iStringNull; } typedef enum { - MONSTERSTATE_NONE = 0, MONSTERSTATE_IDLE, MONSTERSTATE_COMBAT, @@ -182,27 +182,34 @@ typedef enum 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; +} TOGGLE_STATE; // Misc useful inline BOOL FStrEq(const char*sz1, const char*sz2) - { return (strcmp(sz1, sz2) == 0); } +{ + return (strcmp(sz1, sz2) == 0); +} + inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) - { return FStrEq(STRING(VARS(pent)->classname), szClassname); } +{ + return FStrEq(STRING(VARS(pent)->classname), szClassname); +} + inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) - { return FStrEq(STRING(pev->classname), szClassname); } +{ + return FStrEq(STRING(pev->classname), szClassname); +} class CBaseEntity; @@ -249,11 +256,30 @@ 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; +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); -enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 }; + +enum +{ + point_hull = 0, + human_hull = 1, + large_hull = 2, + head_hull = 3 +}; + 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); @@ -296,6 +322,7 @@ 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 ); @@ -312,7 +339,6 @@ extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, extern void UTIL_SayText( const char *pText, CBaseEntity *pEntity ); extern void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ); - typedef struct hudtextparms_s { float x; @@ -362,7 +388,6 @@ void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int #define ASSERTSZ(f, sz) #endif // !DEBUG - extern DLL_GLOBAL const Vector g_vecZero; // @@ -405,7 +430,6 @@ extern DLL_GLOBAL int g_Language; #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 @@ -432,8 +456,6 @@ extern DLL_GLOBAL int g_Language; #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 @@ -461,13 +483,12 @@ extern DLL_GLOBAL int g_Language; #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!!! + // CVOXFILESENTENCEMAX in engine\sound.h!!! extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; extern int gcallsentences; diff --git a/dlls/vector.h b/dlls/vector.h index efc49838..81b3e575 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -28,7 +28,7 @@ public: 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 @@ -75,7 +75,7 @@ public: 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); } @@ -106,7 +106,4 @@ public: 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 \ No newline at end of file +#endif diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 84ad017d..f3d67ac6 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -34,7 +34,6 @@ extern CGraph WorldGraph; extern int gEvilImpulse101; - #define NOT_USED 255 DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam @@ -56,7 +55,6 @@ 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 @@ -75,7 +73,6 @@ int MaxAmmoCarry( int iszName ) ALERT( at_console, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) ); return -1; } - /* ============================================================================== @@ -97,7 +94,6 @@ void ClearMultiDamage(void) gMultiDamage.type = 0; } - // // ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity // @@ -109,14 +105,13 @@ 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 @@ -124,7 +119,7 @@ void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDama { if ( !pEntity ) return; - + gMultiDamage.type |= bitsDamageType; if ( pEntity != gMultiDamage.pEntity ) @@ -147,7 +142,6 @@ void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); } - int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { if ( !pEntity ) @@ -193,8 +187,6 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType ) } } - - // // EjectBrass - tosses a brass shell from passed origin at passed velocity // @@ -217,7 +209,6 @@ void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rota MESSAGE_END(); } - #if 0 // UNDONE: This is no longer used? void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) @@ -235,7 +226,6 @@ void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) } #endif - int giAmmoIndex = 0; // Precaches the ammo and queues the ammo info for sending to clients @@ -251,7 +241,6 @@ void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) return; // ammo already in registry, just quite } - giAmmoIndex++; ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); if ( giAmmoIndex >= MAX_AMMO_SLOTS ) @@ -261,7 +250,6 @@ void AddAmmoNameToAmmoRegistry( const char *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 ) { @@ -339,14 +327,12 @@ void W_Precache(void) 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" ); @@ -356,42 +342,30 @@ void W_Precache(void) // 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 @@ -402,7 +376,6 @@ void W_Precache(void) 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"); @@ -419,13 +392,9 @@ void W_Precache(void) PRECACHE_SOUND ("weapons/bullet_hit2.wav"); // hit by bullet PRECACHE_SOUND ("items/weapondrop1.wav");// weapon falls to the ground - } - - - -TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = +TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = { DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), @@ -434,10 +403,10 @@ TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = // DEFINE_FIELD( CBasePlayerItem, m_iIdPrimary, FIELD_INTEGER ), // DEFINE_FIELD( CBasePlayerItem, m_iIdSecondary, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); +IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ) -TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = +TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = { #if defined( CLIENT_WEAPONS ) DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_FLOAT ), @@ -456,8 +425,7 @@ TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = // DEFINE_FIELD( CBasePlayerWeapon, m_iClientWeaponState, FIELD_INTEGER ), reset to zero on load so hud gets updated correctly }; -IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); - +IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ) void CBasePlayerItem :: SetObjectCollisionBox( void ) { @@ -465,7 +433,6 @@ void CBasePlayerItem :: SetObjectCollisionBox( void ) pev->absmax = pev->origin + Vector(24, 24, 16); } - //========================================================= // Sets up movetype, size, solidtype for a new weapon. //========================================================= @@ -476,7 +443,7 @@ void CBasePlayerItem :: FallInit( void ) 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 ); @@ -530,7 +497,6 @@ void CBasePlayerItem::Materialize( void ) UTIL_SetOrigin( pev, pev->origin );// link into world. SetTouch( &CBasePlayerItem::DefaultTouch); SetThink( NULL ); - } //========================================================= @@ -710,7 +676,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) WeaponIdle( ); return; } - + // catch all if ( ShouldWeaponIdle() ) { @@ -784,7 +750,6 @@ int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) } } - int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); @@ -797,7 +762,6 @@ int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); } - if (bResult) return AddWeapon( ); return FALSE; @@ -858,7 +822,6 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) return 1; } - void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) { if ( UseDecrement() ) @@ -872,7 +835,6 @@ void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) 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. @@ -899,7 +861,7 @@ BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip { iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); } - + // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing if (iIdAmmo > 0) @@ -916,7 +878,6 @@ BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip return iIdAmmo > 0 ? TRUE : FALSE; } - BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { int iIdAmmo; @@ -1000,7 +961,6 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, return TRUE; } - BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) { if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) @@ -1188,9 +1148,9 @@ void CBasePlayerWeapon::RetireWeapon( void ) // weaponbox code: //********************************************************* -LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ); +LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ) -TYPEDESCRIPTION CWeaponBox::m_SaveData[] = +TYPEDESCRIPTION CWeaponBox::m_SaveData[] = { DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), @@ -1198,7 +1158,7 @@ TYPEDESCRIPTION CWeaponBox::m_SaveData[] = DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); +IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ) //========================================================= // @@ -1292,7 +1252,7 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) CBasePlayer *pPlayer = (CBasePlayer *)pOther; int i; -// dole out ammo + // dole out ammo for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) { if ( !FStringNull( m_rgiszAmmo[ i ] ) ) @@ -1308,9 +1268,9 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) } } -// 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. + // 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 ] ) @@ -1359,7 +1319,7 @@ BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) } int iWeaponSlot = pWeapon->iItemSlot(); - + if ( m_rgpPlayerItems[ iWeaponSlot ] ) { // there's already one weapon in this slot, so link this into the slot's column @@ -1402,7 +1362,7 @@ BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) ALERT ( at_console, "NULL String in PackAmmo!\n" ); return FALSE; } - + iMaxCarry = MaxAmmoCarry( iszName ); if ( iMaxCarry != -1 && iCount > 0 ) @@ -1514,32 +1474,33 @@ 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, "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_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_finsr: %i\n", m_fInSpecialReload ); ALERT( at_console, "m_iclip: %i\n", m_iClip ); } - -TYPEDESCRIPTION CRpg::m_SaveData[] = +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[] = +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[] = +IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ) + +TYPEDESCRIPTION CShotgun::m_SaveData[] = { DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), DEFINE_FIELD( CShotgun, m_fInSpecialReload, FIELD_INTEGER ), @@ -1547,34 +1508,38 @@ TYPEDESCRIPTION CShotgun::m_SaveData[] = // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ), DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ), }; -IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon ); -TYPEDESCRIPTION CGauss::m_SaveData[] = +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_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[] = +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_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 ); + +IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ) TYPEDESCRIPTION CSatchel::m_SaveData[] = { DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); + +IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ) diff --git a/dlls/weapons.h b/dlls/weapons.h index 8194a4d3..5112254a 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -55,7 +55,6 @@ public: 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 @@ -85,10 +84,8 @@ public: #define MAX_WEAPONS 32 - #define MAX_NORMAL_BATTERY 100 - // weapon weight factors (for auto-switching) (-1 = noswitch) #define CROWBAR_WEIGHT 0 #define GLOCK_WEIGHT 10 @@ -105,7 +102,6 @@ public: #define SATCHEL_WEIGHT -10 #define TRIPMINE_WEIGHT -10 - // weapon clip/carry ammo capacities #define URANIUM_MAX_CARRY 100 #define _9MM_MAX_CARRY 250 @@ -139,7 +135,6 @@ public: #define TRIPMINE_MAX_CLIP WEAPON_NOCLIP #define SNARK_MAX_CLIP WEAPON_NOCLIP - // the default amount of ammo that comes with each gun when it spawns #define GLOCK_DEFAULT_GIVE 17 #define PYTHON_DEFAULT_GIVE 6 @@ -182,10 +177,9 @@ typedef enum BULLET_MONSTER_9MM, BULLET_MONSTER_MP5, - BULLET_MONSTER_12MM, + BULLET_MONSTER_12MM } Bullet; - #define ITEM_FLAG_SELECTONEMPTY 1 #define ITEM_FLAG_NOAUTORELOAD 2 #define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 @@ -223,7 +217,7 @@ public: virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); - + static TYPEDESCRIPTION m_SaveData[]; virtual int AddToPlayer( CBasePlayer *pPlayer ); // return TRUE if the item you want the item added to the player inventory @@ -282,14 +276,13 @@ public: // int m_iIdSecondary; // Unique Id for secondary ammo }; - // inventory items that class CBasePlayerWeapon : public CBasePlayerItem { public: virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); - + static TYPEDESCRIPTION m_SaveData[]; // generic weapon versions of CBasePlayerItem calls @@ -331,7 +324,7 @@ public: virtual BOOL ShouldWeaponIdle( void ) {return FALSE; }; virtual void Holster( int skiplocal = 0 ); virtual BOOL UseDecrement( void ) { return FALSE; }; - + int PrimaryAmmoIndex(); int SecondaryAmmoIndex(); @@ -352,10 +345,8 @@ public: int m_fInReload; // Are we in the middle of a reload; int m_iDefaultAmmo;// how much ammo you get when you pick up this weapon as placed by a level designer. - }; - class CBasePlayerAmmo : public CBaseEntity { public: @@ -367,7 +358,6 @@ public: void EXPORT Materialize( void ); }; - extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam extern DLL_GLOBAL const char *g_pModelNameLaser; @@ -397,7 +387,6 @@ typedef struct extern MULTIDAMAGE gMultiDamage; - #define LOUD_GUN_VOLUME 1000 #define NORMAL_GUN_VOLUME 600 #define QUIET_GUN_VOLUME 200 @@ -448,7 +437,7 @@ public: BOOL HasWeapon( CBasePlayerItem *pCheckItem ); BOOL PackWeapon( CBasePlayerItem *pWeapon ); BOOL PackAmmo( int iszName, int iCount ); - + CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES];// one slot for each int m_rgiszAmmo[MAX_AMMO_SLOTS];// ammo names @@ -488,13 +477,11 @@ public: private: int m_iShell; - unsigned short m_usFireGlock1; unsigned short m_usFireGlock2; }; - class CCrowbar : public CBasePlayerWeapon { public: @@ -543,7 +530,7 @@ public: BOOL m_fInZoom;// don't save this. virtual BOOL UseDecrement( void ) - { + { #if defined( CLIENT_WEAPONS ) return TRUE; #else @@ -624,14 +611,11 @@ private: class CShotgun : public CBasePlayerWeapon { public: - #ifndef CLIENT_DLL int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; #endif - - void Spawn( void ); void Precache( void ); int iItemSlot( ) { return 3; } @@ -648,7 +632,7 @@ public: int m_iShell; virtual BOOL UseDecrement( void ) - { + { #if defined( CLIENT_WEAPONS ) return TRUE; #else @@ -671,20 +655,18 @@ class CLaserSpot : public CBaseEntity public: void Suspend( float flSuspendTime ); void EXPORT Revive( void ); - + static CLaserSpot *CreateSpot( void ); }; class CRpg : public CBasePlayerWeapon { public: - #ifndef CLIENT_DLL int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; #endif - void Spawn( void ); void Precache( void ); void Reload( void ); @@ -718,7 +700,6 @@ public: private: unsigned short m_usRpg; - }; class CRpgRocket : public CGrenade @@ -742,13 +723,11 @@ public: class CGauss : public CBasePlayerWeapon { public: - #ifndef CLIENT_DLL int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; #endif - void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 4; } @@ -761,7 +740,7 @@ public: void PrimaryAttack( void ); void SecondaryAttack( void ); void WeaponIdle( void ); - + void StartFire( void ); void Fire( Vector vecOrigSrc, Vector vecDirShooting, float flDamage ); float GetFullChargeTime( void ); @@ -796,7 +775,6 @@ public: int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; #endif - void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 4; } @@ -826,7 +804,7 @@ public: BOOL HasAmmo( void ); void UseAmmo( int count ); - + enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; CBeam *m_pBeam; @@ -834,7 +812,7 @@ public: CSprite *m_pSprite; virtual BOOL UseDecrement( void ) - { + { #if defined( CLIENT_WEAPONS ) return TRUE; #else @@ -872,7 +850,7 @@ public: float m_flNextAnimTime; float m_flRechargeTime; - + int m_iFirePhase;// don't save me. virtual BOOL UseDecrement( void ) @@ -887,8 +865,6 @@ private: unsigned short m_usHornetFire; }; - - class CHandGrenade : public CBasePlayerWeapon { public: @@ -902,7 +878,7 @@ public: BOOL CanHolster( void ); void Holster( int skiplocal = 0 ); void WeaponIdle( void ); - + virtual BOOL UseDecrement( void ) { #if defined( CLIENT_WEAPONS ) @@ -916,13 +892,11 @@ public: class CSatchel : public CBasePlayerWeapon { public: - #ifndef CLIENT_DLL int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; #endif - void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 5; } @@ -934,11 +908,11 @@ public: BOOL CanDeploy( void ); BOOL Deploy( void ); BOOL IsUseable( void ); - + void Holster( int skiplocal = 0 ); void WeaponIdle( void ); void Throw( void ); - + virtual BOOL UseDecrement( void ) { #if defined( CLIENT_WEAPONS ) @@ -949,7 +923,6 @@ public: } }; - class CTripmine : public CBasePlayerWeapon { public: @@ -980,7 +953,6 @@ public: private: unsigned short m_usTripFire; - }; class CSqueak : public CBasePlayerWeapon @@ -999,7 +971,7 @@ public: int m_fJustThrown; virtual BOOL UseDecrement( void ) - { + { #if defined( CLIENT_WEAPONS ) return TRUE; #else @@ -1010,6 +982,4 @@ public: private: unsigned short m_usSnarkFire; }; - - #endif // WEAPONS_H diff --git a/dlls/world.cpp b/dlls/world.cpp index d56a3fcf..ed416139 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -112,7 +112,7 @@ public: void EXPORT TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; -LINK_ENTITY_TO_CLASS( infodecal, CDecal ); +LINK_ENTITY_TO_CLASS( infodecal, CDecal ) // UNDONE: These won't get sent to joining players in multi-player void CDecal :: Spawn( void ) @@ -162,7 +162,6 @@ void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE pev->nextthink = gpGlobals->time + 0.1; } - void CDecal :: StaticDecal( void ) { TraceResult trace; @@ -181,13 +180,12 @@ void CDecal :: StaticDecal( void ) SUB_Remove(); } - void CDecal :: KeyValue( KeyValueData *pkvd ) { if (FStrEq(pkvd->szKeyName, "texture")) { pev->skin = DECAL_INDEX( pkvd->szValue ); - + // Found if ( pev->skin >= 0 ) return; @@ -197,14 +195,13 @@ void CDecal :: KeyValue( KeyValueData *pkvd ) 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 ); +LINK_ENTITY_TO_CLASS( bodyque, CCorpse ) static void InitBodyQue(void) { @@ -212,18 +209,17 @@ static void InitBodyQue(void) 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 // @@ -252,7 +248,7 @@ void CopyToBodyQue(entvars_t *pev) //pevHead->goalstarttime = pev->goalstarttime; //pevHead->goalframe = pev->goalframe; //pevHead->goalendtime = pev->goalendtime ; - + pevHead->sequence = pev->sequence; pevHead->animtime = pev->animtime; @@ -261,7 +257,6 @@ void CopyToBodyQue(entvars_t *pev) g_pBodyQueueHead = pevHead->owner; } - CGlobalState::CGlobalState( void ) { Reset(); @@ -281,20 +276,18 @@ globalentity_t *CGlobalState :: Find( string_t globalname ) 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 ) @@ -312,7 +305,6 @@ void CGlobalState :: DumpGlobals( void ) } //#endif - void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) { ASSERT( !Find(globalname) ); @@ -327,7 +319,6 @@ void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALEST m_listCount++; } - void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) { globalentity_t *pEnt = Find( globalname ); @@ -336,7 +327,6 @@ void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) pEnt->state = state; } - const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) { globalentity_t *pEnt = Find( globalname ); @@ -344,7 +334,6 @@ const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) return pEnt; } - GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) { globalentity_t *pEnt = Find( globalname ); @@ -354,22 +343,20 @@ GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) return GLOBAL_OFF; } - // Global Savedata for Delay -TYPEDESCRIPTION CGlobalState::m_SaveData[] = +TYPEDESCRIPTION CGlobalState::m_SaveData[] = { DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), }; // Global Savedata for Delay -TYPEDESCRIPTION gGlobalEntitySaveData[] = +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; @@ -395,11 +382,10 @@ 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 @@ -420,7 +406,6 @@ void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) strcpy( pEnt->levelName, STRING(mapname) ); } - void CGlobalState::ClearStates( void ) { globalentity_t *pFree = m_pList; @@ -433,21 +418,18 @@ void CGlobalState::ClearStates( void ) 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(); @@ -461,7 +443,7 @@ void ResetGlobalState( void ) // This spawns first when each level begins. //======================= -LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); +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 @@ -479,7 +461,6 @@ void CWorld :: Spawn( void ) void CWorld :: Precache( void ) { g_pLastSpawn = NULL; - #if 1 CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec CVAR_SET_STRING("sv_stepsize", "18"); @@ -487,7 +468,6 @@ void CWorld :: Precache( void ) 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 @@ -512,25 +492,21 @@ void CWorld :: Precache( void ) InitBodyQue(); -// init sentence group playback stuff from sentences.txt. -// ok to call this multiple times, calls after first are ignored. - + // 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 - + // init texture type array from materials.txt TEXTURETYPE_Init(); - -// the area based ambient sounds MUST be the first precache_sounds - -// player precaches + // 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 + // 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. @@ -554,51 +530,52 @@ void CWorld :: Precache( void ) 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. -// + + // + // 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 @@ -607,18 +584,21 @@ void CWorld :: Precache( void ) for ( int i = 0; i < ARRAYSIZE(gDecals); i++ ) gDecals[i].index = DECAL_INDEX( gDecals[i].name ); -// init the WorldGraph. + // init the WorldGraph. WorldGraph.InitGraph(); -// make sure the .NOD file is newer than the .BSP file. + // 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. + { + // NOD file is not present, or is older than the BSP file. WorldGraph.AllocNodes (); } else - {// Load the node graph for this level + { + // 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. + { + // couldn't load, so alloc and prepare to build a graph. ALERT ( at_console, "*Error opening .NOD file\n" ); WorldGraph.AllocNodes (); } @@ -677,7 +657,6 @@ void CWorld :: Precache( void ) g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? } - // // Just to ignore the "wad" field. // @@ -777,7 +756,7 @@ int DispatchCreateEntity( edict_t *pent, const char *szName ) // BUGBUG: old classname hanging in memory pent->v.classname = ALLOC_STRING( "item_battery" ); -// ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); + //ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); SpawnEdict( &pent->v ); return 0; // handled @@ -798,7 +777,7 @@ int DispatchPhysicsEntity( edict_t *pEdict ) if( !pEntity ) { -// ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); + //ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); return 0; // not initialized } @@ -813,11 +792,11 @@ int DispatchPhysicsEntity( edict_t *pEdict ) thinktime = pEntity->pev->nextthink; if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime ) return 1; - + if( thinktime < PHYSICS_TIME( )) thinktime = PHYSICS_TIME(); // don't let things stay in the past. - // it is possible to start that way - // by a trigger with a local time. + // it is possible to start that way + // by a trigger with a local time. pEntity->pev->nextthink = 0.0f; gpGlobals->time = thinktime; @@ -828,7 +807,6 @@ int DispatchPhysicsEntity( edict_t *pEdict ) pEntity->pev->origin.z -= 1; LINK_ENTITY( pEdict, true ); #endif - return 1; // handled } #endif diff --git a/dlls/xen.cpp b/dlls/xen.cpp index c7f9ebc4..feb61741 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -18,11 +18,9 @@ #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: @@ -39,15 +37,15 @@ private: Activity m_Activity; }; -TYPEDESCRIPTION CActAnimating::m_SaveData[] = +TYPEDESCRIPTION CActAnimating::m_SaveData[] = { DEFINE_FIELD( CActAnimating, m_Activity, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ); +IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ) void CActAnimating :: SetActivity( Activity act ) -{ +{ int sequence = LookupActivity( act ); if ( sequence != ACTIVITY_NOT_AVAILABLE ) { @@ -58,9 +56,6 @@ void CActAnimating :: SetActivity( Activity act ) } } - - - class CXenPLight : public CActAnimating { public: @@ -80,14 +75,14 @@ private: CSprite *m_pGlow; }; -LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ); +LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ) -TYPEDESCRIPTION CXenPLight::m_SaveData[] = +TYPEDESCRIPTION CXenPLight::m_SaveData[] = { DEFINE_FIELD( CXenPLight, m_pGlow, FIELD_CLASSPTR ), }; -IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ); +IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ) void CXenPLight :: Spawn( void ) { @@ -107,14 +102,12 @@ void CXenPLight :: Spawn( void ) 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(); @@ -129,7 +122,6 @@ void CXenPLight :: Think( void ) LightOff(); } break; - case ACT_CROUCHIDLE: if ( gpGlobals->time > pev->dmgtime ) { @@ -137,19 +129,16 @@ void CXenPLight :: Think( void ) 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() ) @@ -162,7 +151,6 @@ void CXenPLight :: Touch( CBaseEntity *pOther ) } } - void CXenPLight :: LightOn( void ) { SUB_UseTargets( this, USE_ON, 0 ); @@ -170,7 +158,6 @@ void CXenPLight :: LightOn( void ) m_pGlow->pev->effects &= ~EF_NODRAW; } - void CXenPLight :: LightOff( void ) { SUB_UseTargets( this, USE_OFF, 0 ); @@ -178,8 +165,6 @@ void CXenPLight :: LightOff( void ) m_pGlow->pev->effects |= EF_NODRAW; } - - class CXenHair : public CActAnimating { public: @@ -188,7 +173,7 @@ public: void Think( void ); }; -LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ); +LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ) #define SF_HAIR_SYNC 0x0001 @@ -211,27 +196,25 @@ void CXenHair::Spawn( void ) 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 ); + +LINK_ENTITY_TO_CLASS( xen_ttrigger, CXenTreeTrigger ) CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector &position ) { @@ -245,7 +228,6 @@ CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector return pTrigger; } - void CXenTreeTrigger::Touch( CBaseEntity *pOther ) { if ( pev->owner ) @@ -255,7 +237,6 @@ void CXenTreeTrigger::Touch( CBaseEntity *pOther ) } } - #define TREE_AE_ATTACK 1 class CXenTree : public CActAnimating @@ -281,14 +262,14 @@ private: CXenTreeTrigger *m_pTrigger; }; -LINK_ENTITY_TO_CLASS( xen_tree, CXenTree ); +LINK_ENTITY_TO_CLASS( xen_tree, CXenTree ) -TYPEDESCRIPTION CXenTree::m_SaveData[] = +TYPEDESCRIPTION CXenTree::m_SaveData[] = { DEFINE_FIELD( CXenTree, m_pTrigger, FIELD_CLASSPTR ), }; -IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ); +IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ) void CXenTree :: Spawn( void ) { @@ -314,14 +295,14 @@ void CXenTree :: Spawn( void ) UTIL_SetSize( m_pTrigger->pev, Vector( -24, -24, 0 ), Vector( 24, 24, 128 ) ); } -const char *CXenTree::pAttackHitSounds[] = +const char *CXenTree::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CXenTree::pAttackMissSounds[] = +const char *CXenTree::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", @@ -335,7 +316,6 @@ void CXenTree :: Precache( void ) PRECACHE_SOUND_ARRAY( pAttackMissSounds ); } - void CXenTree :: Touch( CBaseEntity *pOther ) { if ( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) @@ -344,7 +324,6 @@ void CXenTree :: Touch( CBaseEntity *pOther ) Attack(); } - void CXenTree :: Attack( void ) { if ( GetActivity() == ACT_IDLE ) @@ -355,7 +334,6 @@ void CXenTree :: Attack( void ) } } - void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) @@ -382,7 +360,7 @@ void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } } - + if ( sound ) { EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); @@ -409,15 +387,12 @@ void CXenTree :: Think( void ) 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 @@ -433,7 +408,7 @@ public: 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 HandleAnimEvent( MonsterEvent_t *pEvent ); void Attack( void ) {} static const char *pModelNames[]; @@ -482,11 +457,10 @@ CXenHull *CXenHull :: CreateHull( CBaseEntity *source, const Vector &mins, const 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 ); +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 ) { @@ -494,6 +468,7 @@ void CXenSporeSmall::Spawn( void ) CXenSpore::Spawn(); UTIL_SetSize( pev, Vector(-16,-16,0), Vector(16,16,64)); } + void CXenSporeMed::Spawn( void ) { pev->skin = 1; @@ -501,9 +476,8 @@ void CXenSporeMed::Spawn( void ) 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[] = +const Vector CXenSporeLarge::m_hullSizes[] = { Vector( 90, -25, 0 ), Vector( 25, 75, 0 ), @@ -517,7 +491,7 @@ 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 ); @@ -536,7 +510,7 @@ void CXenSpore :: Spawn( void ) pev->solid = SOLID_BBOX; pev->takedamage = DAMAGE_YES; -// SetActivity( ACT_IDLE ); + //SetActivity( ACT_IDLE ); pev->sequence = 0; pev->frame = RANDOM_FLOAT(0,255); pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); @@ -544,30 +518,26 @@ void CXenSpore :: Spawn( void ) pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit } -const char *CXenSpore::pModelNames[] = +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 ) { float flInterval = StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - #if 0 DispatchAnimEvents( flInterval ); @@ -576,9 +546,6 @@ void CXenSpore :: Think( void ) default: case ACT_IDLE: break; - } #endif } - - diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 89dc8231..2ae4b690 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -24,7 +24,6 @@ #include "monsters.h" #include "schedule.h" - //========================================================= // Monster's Anim Events Go Here //========================================================= @@ -64,28 +63,28 @@ public: int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); }; -LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ); +LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ) -const char *CZombie::pAttackHitSounds[] = +const char *CZombie::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CZombie::pAttackMissSounds[] = +const char *CZombie::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", }; -const char *CZombie::pAttackSounds[] = +const char *CZombie::pAttackSounds[] = { "zombie/zo_attack1.wav", "zombie/zo_attack2.wav", }; -const char *CZombie::pIdleSounds[] = +const char *CZombie::pIdleSounds[] = { "zombie/zo_idle1.wav", "zombie/zo_idle2.wav", @@ -93,14 +92,14 @@ const char *CZombie::pIdleSounds[] = "zombie/zo_idle4.wav", }; -const char *CZombie::pAlertSounds[] = +const char *CZombie::pAlertSounds[] = { "zombie/zo_alert10.wav", "zombie/zo_alert20.wav", "zombie/zo_alert30.wav", }; -const char *CZombie::pPainSounds[] = +const char *CZombie::pPainSounds[] = { "zombie/zo_pain1.wav", "zombie/zo_pain2.wav", @@ -110,7 +109,7 @@ const char *CZombie::pPainSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CZombie :: Classify ( void ) +int CZombie :: Classify ( void ) { return CLASS_ALIEN_MONSTER; } @@ -124,13 +123,11 @@ void CZombie :: SetYawSpeed ( void ) int ys; ys = 120; - #if 0 switch ( m_Activity ) { } #endif - pev->yaw_speed = ys; } @@ -181,7 +178,6 @@ void CZombie :: AttackSound( void ) 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. @@ -193,7 +189,7 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) case ZOMBIE_AE_ATTACK_RIGHT: { // do stuff for this event. - // ALERT( at_console, "Slash right!\n" ); + //ALERT( at_console, "Slash right!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); if ( pHurt ) { @@ -213,11 +209,10 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) AttackSound(); } break; - case ZOMBIE_AE_ATTACK_LEFT: { // do stuff for this event. - // ALERT( at_console, "Slash left!\n" ); + //ALERT( at_console, "Slash left!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); if ( pHurt ) { @@ -236,7 +231,6 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) AttackSound(); } break; - case ZOMBIE_AE_ATTACK_BOTH: { // do stuff for this event. @@ -257,7 +251,6 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) AttackSound(); } break; - default: CBaseMonster::HandleAnimEvent( pEvent ); break; @@ -312,14 +305,12 @@ void CZombie :: Precache() 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(); @@ -342,5 +333,4 @@ int CZombie::IgnoreConditions ( void ) } return iIgnore; - -} \ No newline at end of file +} diff --git a/engine/custom.h b/engine/custom.h index aed6d4a1..d48ee72d 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -31,7 +31,7 @@ typedef enum t_decal, t_generic, t_eventscript, - t_world, // Fake type for world, is really t_model + t_world // Fake type for world, is really t_model } resourcetype_t; typedef struct @@ -90,4 +90,4 @@ typedef struct customization_s #define FCUST_WIPEDATA ( 1<<1 ) #define FCUST_IGNOREINIT ( 1<<2 ) -#endif // CUSTOM_H \ No newline at end of file +#endif // CUSTOM_H diff --git a/engine/customentity.h b/engine/customentity.h index dc867e5b..63e672f8 100644 --- a/engine/customentity.h +++ b/engine/customentity.h @@ -28,7 +28,7 @@ enum BEAM_POINTS = 0, BEAM_ENTPOINT, BEAM_ENTS, - BEAM_HOSE, + BEAM_HOSE }; #define BEAM_FSINE 0x10 @@ -36,4 +36,4 @@ enum #define BEAM_FSHADEIN 0x40 #define BEAM_FSHADEOUT 0x80 -#endif//CUSTOMENTITY_H \ No newline at end of file +#endif//CUSTOMENTITY_H diff --git a/engine/eiface.h b/engine/eiface.h index 71d87c26..903451f5 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -49,7 +49,7 @@ typedef enum { print_console, print_center, - print_chat, + print_chat } PRINT_TYPE; // For integrity checking of content on clients @@ -57,7 +57,7 @@ typedef enum { 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 // For model files only, the geometry must fit in the specified bbox } FORCE_TYPE; // Returned by TraceLine @@ -351,7 +351,7 @@ typedef enum _fieldtypes FIELD_MODELNAME, // Engine string that is a model name (needs precache) FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) - FIELD_TYPECOUNT, // MUST BE LAST + FIELD_TYPECOUNT // MUST BE LAST } FIELDTYPE; #ifndef offsetof From a0a780d465ed9ad302b1d87e8fed1ad53f4df12e Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 21:36:56 +0500 Subject: [PATCH 040/227] Remove tempmonster.cpp from Android.mk --- dlls/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index 495abd6a..ac887f8b 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -114,7 +114,6 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ subs.cpp \ talkmonster.cpp \ teamplay_gamerules.cpp \ - tempmonster.cpp \ tentacle.cpp \ triggers.cpp \ tripmine.cpp \ From 769f1e765ee42bf2b5c44d3baceca6e530394a4a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 21:39:31 +0500 Subject: [PATCH 041/227] Move tempmonster.cpp to examples directory. --- dlls/{ => examples}/tempmonster.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dlls/{ => examples}/tempmonster.cpp (100%) diff --git a/dlls/tempmonster.cpp b/dlls/examples/tempmonster.cpp similarity index 100% rename from dlls/tempmonster.cpp rename to dlls/examples/tempmonster.cpp From 242983d0f453c8b0f47a0f21758b762e4a008987 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 21:45:47 +0500 Subject: [PATCH 042/227] move useless files to useless/dlls directory. --- {dlls => useless/dlls}/AI_BaseNPC_Schedule.cpp | 0 {dlls => useless/dlls}/Wxdebug.cpp | 0 {dlls => useless/dlls}/wxdebug.h | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {dlls => useless/dlls}/AI_BaseNPC_Schedule.cpp (100%) rename {dlls => useless/dlls}/Wxdebug.cpp (100%) rename {dlls => useless/dlls}/wxdebug.h (100%) diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/useless/dlls/AI_BaseNPC_Schedule.cpp similarity index 100% rename from dlls/AI_BaseNPC_Schedule.cpp rename to useless/dlls/AI_BaseNPC_Schedule.cpp diff --git a/dlls/Wxdebug.cpp b/useless/dlls/Wxdebug.cpp similarity index 100% rename from dlls/Wxdebug.cpp rename to useless/dlls/Wxdebug.cpp diff --git a/dlls/wxdebug.h b/useless/dlls/wxdebug.h similarity index 100% rename from dlls/wxdebug.h rename to useless/dlls/wxdebug.h From 34ec37cc9eddc5ec6ce79dc0dcbf849afcf1a6ff Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 21:54:13 +0500 Subject: [PATCH 043/227] Comment useless header. --- dlls/maprules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index de14cf39..3eea7486 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -26,7 +26,7 @@ #include "eiface.h" #include "util.h" #include "gamerules.h" -#include "maprules.h" +//#include "maprules.h" //empty file #include "cbase.h" #include "player.h" From fad7aa53d76cc56ac8777e0cfc5b2c1e4342cfe1 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 25 Jun 2016 23:21:01 +0500 Subject: [PATCH 044/227] Remove extra commas and semicolons. --- cl_dll/MOTD.cpp | 2 +- cl_dll/saytext.cpp | 2 +- cl_dll/scoreboard.cpp | 10 +++++----- cl_dll/status_icons.cpp | 2 +- cl_dll/statusbar.cpp | 4 ++-- cl_dll/text_message.cpp | 4 ++-- cl_dll/train.cpp | 4 ++-- cl_dll/tri.cpp | 2 +- common/bspfile.h | 4 ++-- dlls/bullsquid.cpp | 2 +- dlls/controller.cpp | 2 +- dlls/crossbow.cpp | 6 ++++-- dlls/func_tank.cpp | 2 +- dlls/gargantua.cpp | 2 +- dlls/hassassin.cpp | 2 +- dlls/roach.cpp | 2 +- dlls/rpg.cpp | 4 ++-- 17 files changed, 29 insertions(+), 27 deletions(-) diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp index 68030cf9..dfb587aa 100644 --- a/cl_dll/MOTD.cpp +++ b/cl_dll/MOTD.cpp @@ -26,7 +26,7 @@ #include #include -DECLARE_MESSAGE( m_MOTD, MOTD ); +DECLARE_MESSAGE( m_MOTD, MOTD ) int CHudMOTD :: Init( void ) { diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 10cf6ef3..2f785b83 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -44,7 +44,7 @@ static float flScrollTime = 0; // the time at which the lines next scroll up static int Y_START = 0; static int line_height = 0; -DECLARE_MESSAGE( m_SayText, SayText ); +DECLARE_MESSAGE( m_SayText, SayText ) int CHudSayText :: Init( void ) { diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 9fca2b7a..adcbb3e7 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -38,12 +38,12 @@ int g_iPlayerClass; //#include "vgui_TeamFortressViewport.h" -DECLARE_COMMAND( m_Scoreboard, ShowScores ); -DECLARE_COMMAND( m_Scoreboard, HideScores ); +DECLARE_COMMAND( m_Scoreboard, ShowScores ) +DECLARE_COMMAND( m_Scoreboard, HideScores ) -DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamScore ); +DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ) +DECLARE_MESSAGE( m_Scoreboard, TeamInfo ) +DECLARE_MESSAGE( m_Scoreboard, TeamScore ) int CHudScoreboard :: Init( void ) { diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index 53a3e743..375c9d57 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -25,7 +25,7 @@ #include "parsemsg.h" #include "event_api.h" -DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); +DECLARE_MESSAGE( m_StatusIcons, StatusIcon ) int CHudStatusIcons::Init( void ) { diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index 81566d1a..152fb9b1 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -26,8 +26,8 @@ #include #include -DECLARE_MESSAGE( m_StatusBar, StatusText ); -DECLARE_MESSAGE( m_StatusBar, StatusValue ); +DECLARE_MESSAGE( m_StatusBar, StatusText ) +DECLARE_MESSAGE( m_StatusBar, StatusValue ) #define STATUSBAR_ID_LINE 1 diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index 1228a07d..eb6f73a9 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -27,7 +27,7 @@ #include "parsemsg.h" -DECLARE_MESSAGE( m_TextMessage, TextMsg ); +DECLARE_MESSAGE( m_TextMessage, TextMsg ) int CHudTextMessage::Init(void) { @@ -38,7 +38,7 @@ int CHudTextMessage::Init(void) Reset(); return 1; -}; +} // Searches through the string for any msg names (indicated by a '#') // any found are looked up in titles.txt and the new message substituted diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp index 0286c689..1cbbb444 100644 --- a/cl_dll/train.cpp +++ b/cl_dll/train.cpp @@ -36,14 +36,14 @@ int CHudTrain::Init(void) gHUD.AddHudElem(this); return 1; -}; +} int CHudTrain::VidInit(void) { m_hSprite = 0; return 1; -}; +} int CHudTrain::Draw(float fTime) { diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp index 18dbc6b7..77d1d466 100644 --- a/cl_dll/tri.cpp +++ b/cl_dll/tri.cpp @@ -21,7 +21,7 @@ extern "C" { void DLLEXPORT HUD_DrawNormalTriangles( void ); void DLLEXPORT HUD_DrawTransparentTriangles( void ); -}; +} //#define TEST_IT #if defined( TEST_IT ) diff --git a/common/bspfile.h b/common/bspfile.h index 51452cd6..809e2fd0 100644 --- a/common/bspfile.h +++ b/common/bspfile.h @@ -119,7 +119,7 @@ enum AMBIENT_SKY, // wind AMBIENT_SLIME, // never used in quake AMBIENT_LAVA, // never used in quake - NUM_AMBIENTS, // automatic ambient sounds + NUM_AMBIENTS // automatic ambient sounds }; // @@ -243,4 +243,4 @@ typedef struct int lightofs; // start of [numstyles*surfsize] samples } dface_t; -#endif//BSPFILE_H \ No newline at end of file +#endif//BSPFILE_H diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index e295ffb5..63d847de 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -216,7 +216,7 @@ public: int Save( CSave &save ); int Restore( CRestore &restore ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES static TYPEDESCRIPTION m_SaveData[]; BOOL m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. diff --git a/dlls/controller.cpp b/dlls/controller.cpp index c3f57e0f..75754f62 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -59,7 +59,7 @@ public: Schedule_t* GetScheduleOfType ( int Type ); void StartTask ( Task_t *pTask ); void RunTask ( Task_t *pTask ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES void Stop( void ); void Move ( float flInterval ); diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index f84e6122..dee2562a 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -46,7 +46,8 @@ class CCrossbowBolt : public CBaseEntity public: static CCrossbowBolt *BoltCreate( void ); }; -LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ); + +LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ) CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) { @@ -557,7 +558,8 @@ class CCrossbowAmmo : public CBasePlayerAmmo return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); + +LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ) diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 81b20986..a61e5c14 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -903,7 +903,7 @@ public: void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); }; -LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); +LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ) void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) { diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index 6c48a666..65878f7e 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -242,7 +242,7 @@ public: virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES private: static const char *pAttackHitSounds[]; diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index d7a2e427..0889a2dd 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -80,7 +80,7 @@ public: void RunTask ( Task_t *pTask ); void DeathSound ( void ); void IdleSound ( void ); - CUSTOM_SCHEDULES; + CUSTOM_SCHEDULES int Save( CSave &save ); int Restore( CRestore &restore ); diff --git a/dlls/roach.cpp b/dlls/roach.cpp index c92a5dfe..78ff1c19 100644 --- a/dlls/roach.cpp +++ b/dlls/roach.cpp @@ -57,7 +57,7 @@ public: int m_iMode; // ----------------------------- }; -LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ); +LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ) //========================================================= // ISoundMask - returns a bit mask indicating which types diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 6a7b0558..093faf38 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -71,7 +71,7 @@ void CLaserSpot::Spawn( void ) SET_MODEL(ENT(pev), "sprites/laserdot.spr"); UTIL_SetOrigin( pev, pev->origin ); -}; +} //========================================================= // Suspend- make the laser sight invisible. @@ -97,7 +97,7 @@ void CLaserSpot::Revive( void ) void CLaserSpot::Precache( void ) { PRECACHE_MODEL("sprites/laserdot.spr"); -}; +} LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ) From 9e7debbb349346c363ef383ffc6139811d638d28 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 3 Jul 2016 18:39:55 +0500 Subject: [PATCH 045/227] Client format. --- cl_dll/ammo.cpp | 625 +++++++++--------- cl_dll/ammo.h | 5 +- cl_dll/ammo_secondary.cpp | 64 +- cl_dll/ammohistory.cpp | 95 ++- cl_dll/ammohistory.h | 20 +- cl_dll/battery.cpp | 65 +- cl_dll/camera.h | 7 +- cl_dll/cdll_int.cpp | 34 +- cl_dll/cl_dll.h | 2 +- cl_dll/cl_util.h | 105 ++- cl_dll/com_weapons.cpp | 48 +- cl_dll/com_weapons.h | 10 +- cl_dll/death.cpp | 113 ++-- cl_dll/demo.cpp | 53 +- cl_dll/demo.h | 3 +- cl_dll/entity.cpp | 313 +++++---- cl_dll/ev_common.cpp | 29 +- cl_dll/ev_hldm.cpp | 638 +++++++++--------- cl_dll/ev_hldm.h | 15 +- cl_dll/eventscripts.h | 4 +- cl_dll/flashlight.cpp | 81 ++- cl_dll/geiger.cpp | 75 ++- cl_dll/health.cpp | 283 ++++---- cl_dll/health.h | 29 +- cl_dll/hl/hl_baseentity.cpp | 338 +++++----- cl_dll/hl/hl_events.cpp | 41 +- cl_dll/hl/hl_objects.cpp | 23 +- cl_dll/hl/hl_weapons.cpp | 525 ++++++++------- cl_dll/hud.cpp | 192 +++--- cl_dll/hud.h | 169 +++-- cl_dll/hud_iface.h | 3 +- cl_dll/hud_msg.cpp | 39 +- cl_dll/hud_redraw.cpp | 186 +++--- cl_dll/hud_servers.cpp | 315 +++++---- cl_dll/hud_servers.h | 7 +- cl_dll/hud_servers_priv.h | 49 +- cl_dll/hud_spectator.cpp | 1216 +++++++++++++++++------------------ cl_dll/hud_spectator.h | 78 ++- cl_dll/hud_update.cpp | 12 +- cl_dll/in_camera.cpp | 453 +++++++------ cl_dll/in_defs.h | 4 +- cl_dll/input.cpp | 682 ++++++++++++-------- cl_dll/input_xash3d.cpp | 77 +-- cl_dll/inputw32.cpp | 492 +++++++------- cl_dll/kbutton.h | 7 +- cl_dll/menu.cpp | 61 +- cl_dll/message.cpp | 181 +++--- cl_dll/overview.cpp | 84 ++- cl_dll/overview.h | 5 +- cl_dll/parsemsg.cpp | 92 ++- cl_dll/saytext.cpp | 116 ++-- cl_dll/scoreboard.cpp | 216 +++---- cl_dll/soundsystem.cpp | 19 +- cl_dll/status_icons.cpp | 34 +- cl_dll/statusbar.cpp | 76 +-- cl_dll/studio_util.cpp | 117 ++-- cl_dll/studio_util.h | 15 +- cl_dll/text_message.cpp | 45 +- cl_dll/tf_defs.h | 74 +-- cl_dll/train.cpp | 33 +- cl_dll/tri.cpp | 12 +- cl_dll/util.cpp | 78 ++- cl_dll/util_vector.h | 87 +-- cl_dll/view.cpp | 1019 ++++++++++++++--------------- cl_dll/view.h | 3 +- 65 files changed, 4946 insertions(+), 5045 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index d55a9f5e..988bd6fa 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -38,49 +38,48 @@ WeaponsResource gWR; int g_weaponselect = 0; -void WeaponsResource :: LoadAllWeaponSprites( void ) +void WeaponsResource::LoadAllWeaponSprites( void ) { - for (int i = 0; i < MAX_WEAPONS; i++) + for( int i = 0; i < MAX_WEAPONS; i++ ) { - if ( rgWeapons[i].iId ) + if( rgWeapons[i].iId ) LoadWeaponSprites( &rgWeapons[i] ); } } -int WeaponsResource :: CountAmmo( int iId ) +int WeaponsResource::CountAmmo( int iId ) { - if ( iId < 0 ) + if( iId < 0 ) return 0; return riAmmo[iId]; } -int WeaponsResource :: HasAmmo( WEAPON *p ) +int WeaponsResource::HasAmmo( WEAPON *p ) { - if ( !p ) + if( !p ) return FALSE; // weapons with no max ammo can always be selected - if ( p->iMax1 == -1 ) + if( p->iMax1 == -1 ) return TRUE; - return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) - || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); + return ( p->iAmmoType == -1 ) || p->iClip > 0 || CountAmmo( p->iAmmoType ) + || CountAmmo( p->iAmmo2Type ) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); } - -void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) +void WeaponsResource::LoadWeaponSprites( WEAPON *pWeapon ) { int i, iRes; - if (ScreenWidth < 640) + if( ScreenWidth < 640 ) iRes = 320; else iRes = 640; char sz[128]; - if ( !pWeapon ) + if( !pWeapon ) return; memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); @@ -92,39 +91,39 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->hAmmo = 0; pWeapon->hAmmo2 = 0; - sprintf(sz, "sprites/%s.txt", pWeapon->szName); - client_sprite_t *pList = SPR_GetList(sz, &i); + sprintf( sz, "sprites/%s.txt", pWeapon->szName ); + client_sprite_t *pList = SPR_GetList( sz, &i ); - if (!pList) + if( !pList ) return; client_sprite_t *p; - + p = GetSpriteList( pList, "crosshair", iRes, i ); - if (p) + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hCrosshair = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hCrosshair = SPR_Load( sz ); pWeapon->rcCrosshair = p->rc; } else pWeapon->hCrosshair = 0; - p = GetSpriteList(pList, "autoaim", iRes, i); - if (p) + p = GetSpriteList( pList, "autoaim", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAutoaim = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hAutoaim = SPR_Load( sz ); pWeapon->rcAutoaim = p->rc; } else pWeapon->hAutoaim = 0; p = GetSpriteList( pList, "zoom", iRes, i ); - if (p) + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedCrosshair = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hZoomedCrosshair = SPR_Load( sz ); pWeapon->rcZoomedCrosshair = p->rc; } else @@ -133,11 +132,11 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; } - p = GetSpriteList(pList, "zoom_autoaim", iRes, i); - if (p) + p = GetSpriteList( pList, "zoom_autoaim", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedAutoaim = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hZoomedAutoaim = SPR_Load( sz ); pWeapon->rcZoomedAutoaim = p->rc; } else @@ -146,11 +145,11 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; } - p = GetSpriteList(pList, "weapon", iRes, i); - if (p) + p = GetSpriteList( pList, "weapon", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hInactive = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hInactive = SPR_Load( sz ); pWeapon->rcInactive = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); @@ -158,21 +157,21 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) else pWeapon->hInactive = 0; - p = GetSpriteList(pList, "weapon_s", iRes, i); - if (p) + p = GetSpriteList( pList, "weapon_s", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hActive = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hActive = SPR_Load( sz ); pWeapon->rcActive = p->rc; } else pWeapon->hActive = 0; - p = GetSpriteList(pList, "ammo", iRes, i); - if (p) + p = GetSpriteList( pList, "ammo", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hAmmo = SPR_Load( sz ); pWeapon->rcAmmo = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); @@ -180,26 +179,25 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) else pWeapon->hAmmo = 0; - p = GetSpriteList(pList, "ammo2", iRes, i); - if (p) + p = GetSpriteList( pList, "ammo2", iRes, i ); + if( p ) { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo2 = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + pWeapon->hAmmo2 = SPR_Load( sz ); pWeapon->rcAmmo2 = p->rc; gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); } else pWeapon->hAmmo2 = 0; - } // Returns the first weapon for a given slot. -WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) +WEAPON *WeaponsResource::GetFirstPos( int iSlot ) { WEAPON *pret = NULL; - for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) + for( int i = 0; i < MAX_WEAPON_POSITIONS; i++ ) { if ( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] ) ) { @@ -211,46 +209,44 @@ WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) return pret; } - -WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) +WEAPON* WeaponsResource::GetNextActivePos( int iSlot, int iSlotPos ) { if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) return NULL; - WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; + WEAPON *p = gWR.rgSlots[iSlot][iSlotPos + 1]; - if ( !p || !gWR.HasAmmo(p) ) + if ( !p || !gWR.HasAmmo( p ) ) return GetNextActivePos( iSlot, iSlotPos + 1 ); return p; } - int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height HSPRITE ghsprBuckets; // Sprite for top row of weapons menu -DECLARE_MESSAGE(m_Ammo, CurWeapon ) // Current weapon and clip -DECLARE_MESSAGE(m_Ammo, WeaponList) // new weapon type -DECLARE_MESSAGE(m_Ammo, AmmoX) // update known ammo type's count -DECLARE_MESSAGE(m_Ammo, AmmoPickup) // flashes an ammo pickup record -DECLARE_MESSAGE(m_Ammo, WeapPickup) // flashes a weapon pickup record -DECLARE_MESSAGE(m_Ammo, HideWeapon) // hides the weapon, ammo, and crosshair displays temporarily -DECLARE_MESSAGE(m_Ammo, ItemPickup) +DECLARE_MESSAGE( m_Ammo, CurWeapon ) // Current weapon and clip +DECLARE_MESSAGE( m_Ammo, WeaponList ) // new weapon type +DECLARE_MESSAGE( m_Ammo, AmmoX ) // update known ammo type's count +DECLARE_MESSAGE( m_Ammo, AmmoPickup ) // flashes an ammo pickup record +DECLARE_MESSAGE( m_Ammo, WeapPickup ) // flashes a weapon pickup record +DECLARE_MESSAGE( m_Ammo, HideWeapon ) // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE( m_Ammo, ItemPickup ) -DECLARE_COMMAND(m_Ammo, Slot1) -DECLARE_COMMAND(m_Ammo, Slot2) -DECLARE_COMMAND(m_Ammo, Slot3) -DECLARE_COMMAND(m_Ammo, Slot4) -DECLARE_COMMAND(m_Ammo, Slot5) -DECLARE_COMMAND(m_Ammo, Slot6) -DECLARE_COMMAND(m_Ammo, Slot7) -DECLARE_COMMAND(m_Ammo, Slot8) -DECLARE_COMMAND(m_Ammo, Slot9) -DECLARE_COMMAND(m_Ammo, Slot10) -DECLARE_COMMAND(m_Ammo, Close) -DECLARE_COMMAND(m_Ammo, NextWeapon) -DECLARE_COMMAND(m_Ammo, PrevWeapon) +DECLARE_COMMAND( m_Ammo, Slot1 ) +DECLARE_COMMAND( m_Ammo, Slot2 ) +DECLARE_COMMAND( m_Ammo, Slot3 ) +DECLARE_COMMAND( m_Ammo, Slot4 ) +DECLARE_COMMAND( m_Ammo, Slot5 ) +DECLARE_COMMAND( m_Ammo, Slot6 ) +DECLARE_COMMAND( m_Ammo, Slot7 ) +DECLARE_COMMAND( m_Ammo, Slot8 ) +DECLARE_COMMAND( m_Ammo, Slot9 ) +DECLARE_COMMAND( m_Ammo, Slot10 ) +DECLARE_COMMAND( m_Ammo, Close ) +DECLARE_COMMAND( m_Ammo, NextWeapon ) +DECLARE_COMMAND( m_Ammo, PrevWeapon ) // width of ammo fonts #define AMMO_SMALL_WIDTH 10 @@ -258,31 +254,31 @@ DECLARE_COMMAND(m_Ammo, PrevWeapon) #define HISTORY_DRAW_TIME "5" -int CHudAmmo::Init(void) +int CHudAmmo::Init( void ) { - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); - HOOK_MESSAGE(CurWeapon); - HOOK_MESSAGE(WeaponList); - HOOK_MESSAGE(AmmoPickup); - HOOK_MESSAGE(WeapPickup); - HOOK_MESSAGE(ItemPickup); - HOOK_MESSAGE(HideWeapon); - HOOK_MESSAGE(AmmoX); + HOOK_MESSAGE( CurWeapon ); + HOOK_MESSAGE( WeaponList ); + HOOK_MESSAGE( AmmoPickup ); + HOOK_MESSAGE( WeapPickup ); + HOOK_MESSAGE( ItemPickup ); + HOOK_MESSAGE( HideWeapon ); + HOOK_MESSAGE( AmmoX ); - HOOK_COMMAND("slot1", Slot1); - HOOK_COMMAND("slot2", Slot2); - HOOK_COMMAND("slot3", Slot3); - HOOK_COMMAND("slot4", Slot4); - HOOK_COMMAND("slot5", Slot5); - HOOK_COMMAND("slot6", Slot6); - HOOK_COMMAND("slot7", Slot7); - HOOK_COMMAND("slot8", Slot8); - HOOK_COMMAND("slot9", Slot9); - HOOK_COMMAND("slot10", Slot10); - HOOK_COMMAND("cancelselect", Close); - HOOK_COMMAND("invnext", NextWeapon); - HOOK_COMMAND("invprev", PrevWeapon); + HOOK_COMMAND( "slot1", Slot1 ); + HOOK_COMMAND( "slot2", Slot2 ); + HOOK_COMMAND( "slot3", Slot3 ); + HOOK_COMMAND( "slot4", Slot4 ); + HOOK_COMMAND( "slot5", Slot5 ); + HOOK_COMMAND( "slot6", Slot6 ); + HOOK_COMMAND( "slot7", Slot7 ); + HOOK_COMMAND( "slot8", Slot8 ); + HOOK_COMMAND( "slot9", Slot9 ); + HOOK_COMMAND( "slot10", Slot10 ); + HOOK_COMMAND( "cancelselect", Close ); + HOOK_COMMAND( "invnext", NextWeapon ); + HOOK_COMMAND( "invprev", PrevWeapon ); Reset(); @@ -297,7 +293,7 @@ int CHudAmmo::Init(void) return 1; } -void CHudAmmo::Reset(void) +void CHudAmmo::Reset( void ) { m_fFade = 0; m_iFlags |= HUD_ACTIVE; //!!! @@ -308,26 +304,25 @@ void CHudAmmo::Reset(void) gWR.Reset(); gHR.Reset(); - // VidInit(); - + //VidInit(); } -int CHudAmmo::VidInit(void) +int CHudAmmo::VidInit( void ) { // Load sprites for buckets (top row of weapon menu) m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); - ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); - giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; - giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; + ghsprBuckets = gHUD.GetSprite( m_HUD_bucket0 ); + giBucketWidth = gHUD.GetSpriteRect( m_HUD_bucket0 ).right - gHUD.GetSpriteRect( m_HUD_bucket0 ).left; + giBucketHeight = gHUD.GetSpriteRect( m_HUD_bucket0 ).bottom - gHUD.GetSpriteRect( m_HUD_bucket0 ).top; - gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); + gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect( m_HUD_bucket0 ).bottom - gHUD.GetSpriteRect( m_HUD_bucket0 ).top ); // If we've already loaded weapons, let's get new sprites gWR.LoadAllWeaponSprites(); - if (ScreenWidth >= 640) + if( ScreenWidth >= 640 ) { giABWidth = 20; giABHeight = 4; @@ -345,22 +340,22 @@ int CHudAmmo::VidInit(void) // Think: // Used for selection of weapon menu item. // -void CHudAmmo::Think(void) +void CHudAmmo::Think( void ) { - if ( gHUD.m_fPlayerDead ) + if( gHUD.m_fPlayerDead ) return; - if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) + if( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) { gWR.iOldWeaponBits = gHUD.m_iWeaponBits; - for (int i = MAX_WEAPONS-1; i > 0; i-- ) + for( int i = MAX_WEAPONS-1; i > 0; i-- ) { - WEAPON *p = gWR.GetWeapon(i); + WEAPON *p = gWR.GetWeapon( i ); - if ( p ) + if( p ) { - if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) + if( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) gWR.PickupWeapon( p ); else gWR.DropWeapon( p ); @@ -368,15 +363,15 @@ void CHudAmmo::Think(void) } } - if (!gpActiveSel) + if( !gpActiveSel ) return; // has the player selected one? - if (gHUD.m_iKeyBits & IN_ATTACK) + if( gHUD.m_iKeyBits & IN_ATTACK ) { - if (gpActiveSel != (WEAPON *)1) + if( gpActiveSel != (WEAPON *) 1 ) { - ServerCmd(gpActiveSel->szName); + ServerCmd( gpActiveSel->szName ); g_weaponselect = gpActiveSel->iId; } @@ -384,7 +379,7 @@ void CHudAmmo::Think(void) gpActiveSel = NULL; gHUD.m_iKeyBits &= ~IN_ATTACK; - PlaySound("common/wpn_select.wav", 1); + PlaySound( "common/wpn_select.wav", 1 ); } } @@ -392,17 +387,16 @@ void CHudAmmo::Think(void) // // Helper function to return a Ammo pointer from id // - -HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) +HSPRITE* WeaponsResource::GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) { - for ( int i = 0; i < MAX_WEAPONS; i++ ) + for( int i = 0; i < MAX_WEAPONS; i++ ) { - if ( rgWeapons[i].iAmmoType == iAmmoId ) + if( rgWeapons[i].iAmmoType == iAmmoId ) { rect = rgWeapons[i].rcAmmo; return &rgWeapons[i].hAmmo; } - else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) + else if( rgWeapons[i].iAmmo2Type == iAmmoId ) { rect = rgWeapons[i].rcAmmo2; return &rgWeapons[i].hAmmo2; @@ -412,33 +406,32 @@ HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) return NULL; } - // Menu Selection Code - -void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) +void WeaponsResource::SelectSlot( int iSlot, int fAdvance, int iDirection ) { - if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) - { // menu is overriding slot use commands + if( gHUD.m_Menu.m_fMenuDisplayed && ( fAdvance == FALSE ) && ( iDirection == 1 ) ) + { + // menu is overriding slot use commands gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers return; } - if ( iSlot > MAX_WEAPON_SLOTS ) + if( iSlot > MAX_WEAPON_SLOTS ) return; - if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + if( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) return; - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + if ( !( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) ) return; - if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) + if( ! ( gHUD.m_iWeaponBits & ~( 1 << ( WEAPON_SUIT ) ) ) ) return; WEAPON *p = NULL; bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; - if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) + if ( ( gpActiveSel == NULL ) || ( gpActiveSel == (WEAPON *) 1 ) || ( iSlot != gpActiveSel->iSlot ) ) { PlaySound( "common/wpn_hudon.wav", 1 ); p = GetFirstPos( iSlot ); @@ -449,7 +442,8 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) // but only if there is only one item in the bucket WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); if ( !p2 ) - { // only one active item in bucket, so change directly to weapon + { + // only one active item in bucket, so change directly to weapon ServerCmd( p->szName ); g_weaponselect = p->iId; return; @@ -458,7 +452,7 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) } else { - PlaySound("common/wpn_moveselect.wav", 1); + PlaySound( "common/wpn_moveselect.wav", 1 ); if ( gpActiveSel ) p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); if ( !p ) @@ -485,14 +479,14 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) // // AmmoX -- Update the count of a known type of ammo // -int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) +int CHudAmmo::MsgFunc_AmmoX( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int iIndex = READ_BYTE(); int iCount = READ_BYTE(); - gWR.SetAmmo( iIndex, abs(iCount) ); + gWR.SetAmmo( iIndex, abs( iCount ) ); return 1; } @@ -504,7 +498,7 @@ int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) int iCount = READ_BYTE(); // Add ammo to the history - gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); + gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs( iCount ) ); return 1; } @@ -531,17 +525,16 @@ int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) return 1; } - int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); gHUD.m_iHideHUDDisplay = READ_BYTE(); - if (gEngfuncs.IsSpectateOnly()) + if( gEngfuncs.IsSpectateOnly() ) return 1; - if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + if( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) { static wrect_t nullrc; gpActiveSel = NULL; @@ -561,7 +554,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) // counts are updated with AmmoX. Server assures that the Weapon ammo type // numbers match a real ammo type. // -int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) +int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) { static wrect_t nullrc; int fOnTarget = FALSE; @@ -573,21 +566,21 @@ int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) int iClip = READ_CHAR(); // detect if we're also on target - if ( iState > 1 ) + if( iState > 1 ) { fOnTarget = TRUE; } - if ( iId < 1 ) + if( iId < 1 ) { - SetCrosshair(0, nullrc, 0, 0, 0); + SetCrosshair( 0, nullrc, 0, 0, 0 ); return 0; } - if ( g_iUser1 != OBS_IN_EYE ) + if( g_iUser1 != OBS_IN_EYE ) { // Is player dead??? - if ((iId == -1) && (iClip == -1)) + if( ( iId == -1 ) && ( iClip == -1 ) ) { gHUD.m_fPlayerDead = TRUE; gpActiveSel = NULL; @@ -598,33 +591,34 @@ int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) WEAPON *pWeapon = gWR.GetWeapon( iId ); - if ( !pWeapon ) + if( !pWeapon ) return 0; - if ( iClip < -1 ) - pWeapon->iClip = abs(iClip); + if( iClip < -1 ) + pWeapon->iClip = abs( iClip ); else pWeapon->iClip = iClip; - - if ( iState == 0 ) // we're not the current weapon, so update no more + if( iState == 0 ) // we're not the current weapon, so update no more return 1; m_pWeapon = pWeapon; - if ( gHUD.m_iFOV >= 90 ) - { // normal crosshairs - if (fOnTarget && m_pWeapon->hAutoaim) - SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); + if( gHUD.m_iFOV >= 90 ) + { + // normal crosshairs + if( fOnTarget && m_pWeapon->hAutoaim ) + SetCrosshair( m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255 ); else - SetCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); } else - { // zoomed crosshairs - if (fOnTarget && m_pWeapon->hZoomedAutoaim) - SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); + { + // zoomed crosshairs + if( fOnTarget && m_pWeapon->hZoomedAutoaim ) + SetCrosshair( m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255 ); else - SetCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); + SetCrosshair( m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255 ); } @@ -637,7 +631,7 @@ int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) // // WeaponList -- Tells the hud about a new weapon type. // -int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) +int CHudAmmo::MsgFunc_WeaponList( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -647,12 +641,12 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) Weapon.iAmmoType = (int)READ_CHAR(); Weapon.iMax1 = READ_BYTE(); - if (Weapon.iMax1 == 255) + if( Weapon.iMax1 == 255 ) Weapon.iMax1 = -1; Weapon.iAmmo2Type = READ_CHAR(); Weapon.iMax2 = READ_BYTE(); - if (Weapon.iMax2 == 255) + if( Weapon.iMax2 == 255 ) Weapon.iMax2 = -1; Weapon.iSlot = READ_CHAR(); @@ -664,7 +658,6 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) gWR.AddWeapon( &Weapon ); return 1; - } //------------------------------------------------------------------------ @@ -674,82 +667,82 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) void CHudAmmo::SlotInput( int iSlot ) { // Let the Viewport use it first, for menus -// if ( gViewPort && gViewPort->SlotInput( iSlot ) ) +// if( gViewPort && gViewPort->SlotInput( iSlot ) ) // return; gWR.SelectSlot(iSlot, FALSE, 1); } -void CHudAmmo::UserCmd_Slot1(void) +void CHudAmmo::UserCmd_Slot1( void ) { SlotInput( 0 ); } -void CHudAmmo::UserCmd_Slot2(void) +void CHudAmmo::UserCmd_Slot2( void ) { SlotInput( 1 ); } -void CHudAmmo::UserCmd_Slot3(void) +void CHudAmmo::UserCmd_Slot3( void ) { SlotInput( 2 ); } -void CHudAmmo::UserCmd_Slot4(void) +void CHudAmmo::UserCmd_Slot4( void ) { SlotInput( 3 ); } -void CHudAmmo::UserCmd_Slot5(void) +void CHudAmmo::UserCmd_Slot5( void ) { SlotInput( 4 ); } -void CHudAmmo::UserCmd_Slot6(void) +void CHudAmmo::UserCmd_Slot6( void ) { SlotInput( 5 ); } -void CHudAmmo::UserCmd_Slot7(void) +void CHudAmmo::UserCmd_Slot7( void ) { SlotInput( 6 ); } -void CHudAmmo::UserCmd_Slot8(void) +void CHudAmmo::UserCmd_Slot8( void ) { SlotInput( 7 ); } -void CHudAmmo::UserCmd_Slot9(void) +void CHudAmmo::UserCmd_Slot9( void ) { SlotInput( 8 ); } -void CHudAmmo::UserCmd_Slot10(void) +void CHudAmmo::UserCmd_Slot10( void ) { SlotInput( 9 ); } -void CHudAmmo::UserCmd_Close(void) +void CHudAmmo::UserCmd_Close( void ) { - if (gpActiveSel) + if( gpActiveSel ) { gpLastSel = gpActiveSel; gpActiveSel = NULL; - PlaySound("common/wpn_hudoff.wav", 1); + PlaySound( "common/wpn_hudoff.wav", 1 ); } else - ClientCmd("escape"); + ClientCmd( "escape" ); } // Selects the next item in the weapon menu -void CHudAmmo::UserCmd_NextWeapon(void) +void CHudAmmo::UserCmd_NextWeapon( void ) { - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + if( gHUD.m_fPlayerDead || ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) return; - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + if( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) gpActiveSel = m_pWeapon; int pos = 0; @@ -760,15 +753,15 @@ void CHudAmmo::UserCmd_NextWeapon(void) slot = gpActiveSel->iSlot; } - for ( int loop = 0; loop <= 1; loop++ ) + for( int loop = 0; loop <= 1; loop++ ) { - for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) + for( ; slot < MAX_WEAPON_SLOTS; slot++ ) { - for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) + for( ; pos < MAX_WEAPON_POSITIONS; pos++ ) { WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - if ( wsp && gWR.HasAmmo(wsp) ) + if( wsp && gWR.HasAmmo( wsp ) ) { gpActiveSel = wsp; return; @@ -785,109 +778,104 @@ void CHudAmmo::UserCmd_NextWeapon(void) } // Selects the previous item in the menu -void CHudAmmo::UserCmd_PrevWeapon(void) +void CHudAmmo::UserCmd_PrevWeapon( void ) { - if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + if( gHUD.m_fPlayerDead || ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) return; - if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + if( !gpActiveSel || gpActiveSel == (WEAPON*) 1 ) gpActiveSel = m_pWeapon; - int pos = MAX_WEAPON_POSITIONS-1; - int slot = MAX_WEAPON_SLOTS-1; - if ( gpActiveSel ) + int pos = MAX_WEAPON_POSITIONS - 1; + int slot = MAX_WEAPON_SLOTS - 1; + if( gpActiveSel ) { pos = gpActiveSel->iSlotPos - 1; slot = gpActiveSel->iSlot; } - for ( int loop = 0; loop <= 1; loop++ ) + for( int loop = 0; loop <= 1; loop++ ) { - for ( ; slot >= 0; slot-- ) + for( ; slot >= 0; slot-- ) { - for ( ; pos >= 0; pos-- ) + for( ; pos >= 0; pos-- ) { WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - if ( wsp && gWR.HasAmmo(wsp) ) + if( wsp && gWR.HasAmmo( wsp ) ) { gpActiveSel = wsp; return; } } - pos = MAX_WEAPON_POSITIONS-1; + pos = MAX_WEAPON_POSITIONS - 1; } - slot = MAX_WEAPON_SLOTS-1; + slot = MAX_WEAPON_SLOTS - 1; } gpActiveSel = NULL; } - - //------------------------------------------------------------------------- // Drawing code //------------------------------------------------------------------------- - -int CHudAmmo::Draw(float flTime) +int CHudAmmo::Draw( float flTime ) { int a, x, y, r, g, b; int AmmoWidth; - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + if( !( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) ) return 1; - if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + if( ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) return 1; // Draw Weapon Menu - DrawWList(flTime); + DrawWList( flTime ); // Draw ammo pickup history gHR.DrawAmmoHistory( flTime ); - if (!(m_iFlags & HUD_ACTIVE)) + if( !( m_iFlags & HUD_ACTIVE ) ) return 0; - if (!m_pWeapon) + if( !m_pWeapon ) return 0; WEAPON *pw = m_pWeapon; // shorthand // SPR_Draw Ammo - if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) + if( ( pw->iAmmoType < 0 ) && ( pw->iAmmo2Type < 0 ) ) return 0; - int iFlags = DHN_DRAWZERO; // draw 0 values - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + AmmoWidth = gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).right - gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).left; - a = (int) max( MIN_ALPHA, m_fFade ); + a = (int)max( MIN_ALPHA, m_fFade ); - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); + if( m_fFade > 0 ) + m_fFade -= ( gHUD.m_flTimeDelta * 20 ); - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r, g, b, RGB_YELLOWISH ); - ScaleColors(r, g, b, a ); + ScaleColors( r, g, b, a ); // Does this weapon have a clip? - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; // Does weapon have any ammo at all? - if (m_pWeapon->iAmmoType > 0) + if( m_pWeapon->iAmmoType > 0 ) { int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; - - if (pw->iClip >= 0) + + if( pw->iClip >= 0 ) { // room for the number and the '|' and the current ammo - - x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); + x = ScreenWidth - ( 8 * AmmoWidth ) - iIconWidth; + x = gHUD.DrawHudNumber( x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b ); wrect_t rc; rc.top = 0; @@ -895,174 +883,163 @@ int CHudAmmo::Draw(float flTime) rc.right = AmmoWidth; rc.bottom = 100; - int iBarWidth = AmmoWidth/10; + int iBarWidth = AmmoWidth / 10; - x += AmmoWidth/2; + x += AmmoWidth / 2; - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r,g,b, RGB_YELLOWISH ); // draw the | bar - FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); + FillRGBA( x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a ); - x += iBarWidth + AmmoWidth/2;; + x += iBarWidth + AmmoWidth / 2; // GL Seems to need this - ScaleColors(r, g, b, a ); - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - - + ScaleColors( r, g, b, a ); + x = gHUD.DrawHudNumber( x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo( pw->iAmmoType ), r, g, b ); } else { // SPR_Draw a bullets only line x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + x = gHUD.DrawHudNumber( x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo( pw->iAmmoType ), r, g, b ); } // Draw the ammo Icon - int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; - SPR_Set(m_pWeapon->hAmmo, r, g, b); - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); + int iOffset = ( m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top ) / 8; + SPR_Set( m_pWeapon->hAmmo, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, &m_pWeapon->rcAmmo ); } // Does weapon have seconday ammo? - if (pw->iAmmo2Type > 0) + if( pw->iAmmo2Type > 0 ) { int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; // Do we have secondary ammo? - if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) + if( ( pw->iAmmo2Type != 0 ) && ( gWR.CountAmmo( pw->iAmmo2Type ) > 0 ) ) { - y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; + y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight / 4; x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); + x = gHUD.DrawHudNumber( x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo( pw->iAmmo2Type ), r, g, b ); // Draw the ammo Icon - SPR_Set(m_pWeapon->hAmmo2, r, g, b); - int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); + SPR_Set( m_pWeapon->hAmmo2, r, g, b ); + int iOffset = ( m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top) / 8; + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2 ); } } return 1; } - // // Draws the ammo bar on the hud // -int DrawBar(int x, int y, int width, int height, float f) +int DrawBar( int x, int y, int width, int height, float f ) { int r, g, b; - if (f < 0) + if( f < 0 ) f = 0; - if (f > 1) + if( f > 1 ) f = 1; - if (f) + if( f ) { int w = f * width; // Always show at least one pixel if we have ammo. - if (w <= 0) + if( w <= 0 ) w = 1; - UnpackRGB(r, g, b, RGB_GREENISH); - FillRGBA(x, y, w, height, r, g, b, 255); + UnpackRGB( r, g, b, RGB_GREENISH ); + FillRGBA( x, y, w, height, r, g, b, 255 ); x += w; width -= w; } - UnpackRGB(r, g, b, RGB_YELLOWISH); + UnpackRGB( r, g, b, RGB_YELLOWISH ); - FillRGBA(x, y, width, height, r, g, b, 128); + FillRGBA( x, y, width, height, r, g, b, 128 ); - return (x + width); + return ( x + width ); } - - -void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) +void DrawAmmoBar( WEAPON *p, int x, int y, int width, int height ) { - if ( !p ) + if( !p ) return; - - if (p->iAmmoType != -1) + + if( p->iAmmoType != -1 ) { - if (!gWR.CountAmmo(p->iAmmoType)) + if( !gWR.CountAmmo( p->iAmmoType ) ) return; - float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; + float f = (float)gWR.CountAmmo( p->iAmmoType ) / (float)p->iMax1; - x = DrawBar(x, y, width, height, f); - + x = DrawBar( x, y, width, height, f ); // Do we have secondary ammo too? - - if (p->iAmmo2Type != -1) + if( p->iAmmo2Type != -1 ) { - f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; + f = (float)gWR.CountAmmo( p->iAmmo2Type ) / (float)p->iMax2; x += 5; //!!! - DrawBar(x, y, width, height, f); + DrawBar( x, y, width, height, f ); } } } - - - // // Draw Weapon Menu // -int CHudAmmo::DrawWList(float flTime) +int CHudAmmo::DrawWList( float flTime ) { - int r,g,b,x,y,a,i; + int r, g, b, x, y, a, i; - if ( !gpActiveSel ) + if( !gpActiveSel ) return 0; int iActiveSlot; - if ( gpActiveSel == (WEAPON *)1 ) + if( gpActiveSel == (WEAPON *) 1 ) iActiveSlot = -1; // current slot has no weapons else iActiveSlot = gpActiveSel->iSlot; x = 10; //!!! y = 10; //!!! - // Ensure that there are available choices in the active slot - if ( iActiveSlot > 0 ) + if( iActiveSlot > 0 ) { - if ( !gWR.GetFirstPos( iActiveSlot ) ) + if( !gWR.GetFirstPos( iActiveSlot ) ) { - gpActiveSel = (WEAPON *)1; + gpActiveSel = (WEAPON *) 1; iActiveSlot = -1; } } - + // Draw top line - for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) + for( i = 0; i < MAX_WEAPON_SLOTS; i++ ) { int iWidth; - UnpackRGB(r,g,b, RGB_YELLOWISH); - - if ( iActiveSlot == i ) + UnpackRGB( r, g, b, RGB_YELLOWISH ); + + if( iActiveSlot == i ) a = 255; else a = 192; - ScaleColors(r, g, b, 255); - SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); + ScaleColors( r, g, b, 255 ); + SPR_Set( gHUD.GetSprite( m_HUD_bucket0 + i ), r, g, b ); // make active slot wide enough to accomodate gun pictures - if ( i == iActiveSlot ) + if( i == iActiveSlot ) { - WEAPON *p = gWR.GetFirstPos(iActiveSlot); - if ( p ) + WEAPON *p = gWR.GetFirstPos( iActiveSlot ); + if( p ) iWidth = p->rcActive.right - p->rcActive.left; else iWidth = giBucketWidth; @@ -1070,58 +1047,55 @@ int CHudAmmo::DrawWList(float flTime) else iWidth = giBucketWidth; - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_bucket0 + i ) ); x += iWidth + 5; } - a = 128; //!!! x = 10; // Draw all of the buckets - for (i = 0; i < MAX_WEAPON_SLOTS; i++) + for( i = 0; i < MAX_WEAPON_SLOTS; i++ ) { y = giBucketHeight + 10; // If this is the active slot, draw the bigger pictures, // otherwise just draw boxes - if ( i == iActiveSlot ) + if( i == iActiveSlot ) { WEAPON *p = gWR.GetFirstPos( i ); int iWidth = giBucketWidth; - if ( p ) + if( p ) iWidth = p->rcActive.right - p->rcActive.left; - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) { p = gWR.GetWeaponSlot( i, iPos ); - if ( !p || !p->iId ) + if( !p || !p->iId ) continue; - UnpackRGB( r,g,b, RGB_YELLOWISH ); - + UnpackRGB( r, g, b, RGB_YELLOWISH ); + // if active, then we must have ammo. - - if ( gpActiveSel == p ) + if( gpActiveSel == p ) { - SPR_Set(p->hActive, r, g, b ); - SPR_DrawAdditive(0, x, y, &p->rcActive); + SPR_Set( p->hActive, r, g, b ); + SPR_DrawAdditive( 0, x, y, &p->rcActive ); - SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); + SPR_Set( gHUD.GetSprite( m_HUD_selection ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_selection ) ); } else { // Draw Weapon if Red if no ammo - - if ( gWR.HasAmmo(p) ) - ScaleColors(r, g, b, 192); + if( gWR.HasAmmo( p ) ) + ScaleColors( r, g, b, 192 ); else { - UnpackRGB(r,g,b, RGB_REDISH); - ScaleColors(r, g, b, 128); + UnpackRGB( r, g, b, RGB_REDISH ); + ScaleColors( r, g, b, 128 ); } SPR_Set( p->hInactive, r, g, b ); @@ -1129,36 +1103,33 @@ int CHudAmmo::DrawWList(float flTime) } // Draw Ammo Bar - - DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); + DrawAmmoBar( p, x + giABWidth / 2, y, giABWidth, giABHeight ); y += p->rcActive.bottom - p->rcActive.top + 5; } x += iWidth + 5; - } else { // Draw Row of weapons. + UnpackRGB( r, g, b, RGB_YELLOWISH ); - UnpackRGB(r,g,b, RGB_YELLOWISH); - - for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) { WEAPON *p = gWR.GetWeaponSlot( i, iPos ); - - if ( !p || !p->iId ) + + if( !p || !p->iId ) continue; - if ( gWR.HasAmmo(p) ) + if( gWR.HasAmmo( p ) ) { - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r, g, b, RGB_YELLOWISH ); a = 128; } else { - UnpackRGB(r,g,b, RGB_REDISH); + UnpackRGB( r, g, b, RGB_REDISH ); a = 96; } @@ -1169,13 +1140,11 @@ int CHudAmmo::DrawWList(float flTime) x += giBucketWidth + 5; } - } + } return 1; - } - /* ================================= GetSpriteList @@ -1184,17 +1153,17 @@ sprite name 'psz' and resolution 'iRes' in the given sprite list 'pList' iCount is the number of items in the pList ================================= */ -client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) +client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ) { - if (!pList) + if( !pList ) return NULL; int i = iCount; client_sprite_t *p = pList; - while(i--) + while( i-- ) { - if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) + if( ( !strcmp( psz, p->szName ) ) && ( p->iRes == iRes ) ) return p; p++; } diff --git a/cl_dll/ammo.h b/cl_dll/ammo.h index 5e44065a..9134681c 100644 --- a/cl_dll/ammo.h +++ b/cl_dll/ammo.h @@ -18,7 +18,6 @@ #define MAX_WEAPON_NAME 128 - #define WEAPON_FLAGS_SELECTONEMPTY 1 #define WEAPON_IS_ONTARGET 0x40 @@ -57,6 +56,4 @@ struct WEAPON }; typedef int AMMO; - - -#endif \ No newline at end of file +#endif diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index 8038c216..994350ed 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -27,7 +27,7 @@ DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ) DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ) -int CHudAmmoSecondary :: Init( void ) +int CHudAmmoSecondary::Init( void ) { HOOK_MESSAGE( SecAmmoVal ); HOOK_MESSAGE( SecAmmoIcon ); @@ -43,67 +43,68 @@ int CHudAmmoSecondary :: Init( void ) return 1; } -void CHudAmmoSecondary :: Reset( void ) +void CHudAmmoSecondary::Reset( void ) { m_fFade = 0; } -int CHudAmmoSecondary :: VidInit( void ) +int CHudAmmoSecondary::VidInit( void ) { return 1; } -int CHudAmmoSecondary :: Draw(float flTime) +int CHudAmmoSecondary::Draw( float flTime ) { - if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + if ( ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) return 1; // draw secondary ammo icons above normal ammo readout int a, x, y, r, g, b, AmmoWidth; UnpackRGB( r, g, b, RGB_YELLOWISH ); - a = (int) max( MIN_ALPHA, m_fFade ); - if (m_fFade > 0) - m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons + a = (int)max( MIN_ALPHA, m_fFade ); + if( m_fFade > 0 ) + m_fFade -= ( gHUD.m_flTimeDelta * 20 ); // slowly lower alpha to fade out icons ScaleColors( r, g, b, a ); - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + AmmoWidth = gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).right - gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).left; - y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values + y = ScreenHeight - ( gHUD.m_iFontHeight * 4 ); // this is one font height higher than the weapon ammo values x = ScreenWidth - AmmoWidth; - if ( m_HUD_ammoicon ) + if( m_HUD_ammoicon ) { // Draw the ammo icon - x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); - y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); + x -= ( gHUD.GetSpriteRect( m_HUD_ammoicon ).right - gHUD.GetSpriteRect( m_HUD_ammoicon ).left ); + y -= ( gHUD.GetSpriteRect( m_HUD_ammoicon ).top - gHUD.GetSpriteRect( m_HUD_ammoicon ).bottom ); - SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); + SPR_Set( gHUD.GetSprite( m_HUD_ammoicon ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_ammoicon ) ); } else - { // move the cursor by the '0' char instead, since we don't have an icon to work with + { + // move the cursor by the '0' char instead, since we don't have an icon to work with x -= AmmoWidth; - y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); + y -= ( gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).top - gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).bottom ); } // draw the ammo counts, in reverse order, from right to left - for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) + for( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) { - if ( m_iAmmoAmounts[i] < 0 ) + if( m_iAmmoAmounts[i] < 0 ) continue; // negative ammo amounts imply that they shouldn't be drawn // half a char gap between the ammo number and the previous pic - x -= (AmmoWidth / 2); + x -= ( AmmoWidth / 2 ); // draw the number, right-aligned - x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); + x -= ( gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth ); gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); - if ( i != 0 ) + if( i != 0 ) { // draw the divider bar - x -= (AmmoWidth / 2); - FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); + x -= ( AmmoWidth / 2 ); + FillRGBA( x, y, ( AmmoWidth/10 ), gHUD.m_iFontHeight, r, g, b, a ); } } @@ -113,7 +114,7 @@ int CHudAmmoSecondary :: Draw(float flTime) // Message handler for Secondary Ammo Value // accepts one value: // string: sprite name -int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) +int CHudAmmoSecondary::MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); @@ -126,12 +127,12 @@ int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, vo // takes two values: // byte: ammo index // byte: ammo value -int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) +int CHudAmmoSecondary::MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int index = READ_BYTE(); - if ( index < 0 || index >= MAX_SEC_AMMO_VALUES ) + if( index < 0 || index >= MAX_SEC_AMMO_VALUES ) return 1; m_iAmmoAmounts[index] = READ_BYTE(); @@ -139,13 +140,14 @@ int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, voi // check to see if there is anything left to draw int count = 0; - for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + for( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) { count += max( 0, m_iAmmoAmounts[i] ); } - if ( count == 0 ) - { // the ammo fields are all empty, so turn off this hud area + if( count == 0 ) + { + // the ammo fields are all empty, so turn off this hud area m_iFlags &= ~HUD_ACTIVE; return 1; } @@ -155,5 +157,3 @@ int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, voi return 1; } - - diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp index 86e9cb09..4b1e6745 100644 --- a/cl_dll/ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -28,9 +28,9 @@ HistoryResource gHR; -#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) -#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) -#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) +#define AMMO_PICKUP_GAP ( gHR.iHistoryGap + 5 ) +#define AMMO_PICKUP_PICK_HEIGHT ( 32 + ( gHR.iHistoryGap * 2 ) ) +#define AMMO_PICKUP_HEIGHT_MAX ( ScreenHeight - 100 ) #define MAX_ITEM_NAME 32 int HISTORY_DRAW_TIME = 5; @@ -43,13 +43,14 @@ struct ITEM_INFO wrect_t rect; }; -void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) +void HistoryResource::AddToHistory( int iType, int iId, int iCount ) { - if ( iType == HISTSLOT_AMMO && !iCount ) + if( iType == HISTSLOT_AMMO && !iCount ) return; // no amount, so don't add - if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { // the pic would have to be drawn too high + if( ( ( ( AMMO_PICKUP_GAP * iCurrentHistorySlot ) + AMMO_PICKUP_PICK_HEIGHT ) > AMMO_PICKUP_HEIGHT_MAX ) || ( iCurrentHistorySlot >= MAX_HISTORY ) ) + { + // the pic would have to be drawn too high // so start from the bottom iCurrentHistorySlot = 0; } @@ -63,13 +64,14 @@ void HistoryResource :: AddToHistory( int iType, int iId, int iCount ) freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; } -void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount ) +void HistoryResource::AddToHistory( int iType, const char *szName, int iCount ) { - if ( iType != HISTSLOT_ITEM ) + if( iType != HISTSLOT_ITEM ) return; - if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { // the pic would have to be drawn too high + if( ( ( ( AMMO_PICKUP_GAP * iCurrentHistorySlot ) + AMMO_PICKUP_PICK_HEIGHT ) > AMMO_PICKUP_HEIGHT_MAX ) || ( iCurrentHistorySlot >= MAX_HISTORY ) ) + { + // the pic would have to be drawn too high // so start from the bottom iCurrentHistorySlot = 0; } @@ -77,9 +79,8 @@ void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot // I am really unhappy with all the code in this file - int i = gHUD.GetSpriteIndex( szName ); - if ( i == -1 ) + if( i == -1 ) return; // unknown sprite name, don't add it to history freeslot->iId = i; @@ -90,12 +91,11 @@ void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME; } - -void HistoryResource :: CheckClearHistory( void ) +void HistoryResource::CheckClearHistory( void ) { - for ( int i = 0; i < MAX_HISTORY; i++ ) + for( int i = 0; i < MAX_HISTORY; i++ ) { - if ( rgAmmoHistory[i].type ) + if( rgAmmoHistory[i].type ) return; } @@ -105,79 +105,81 @@ void HistoryResource :: CheckClearHistory( void ) // // Draw Ammo pickup history // -int HistoryResource :: DrawAmmoHistory( float flTime ) +int HistoryResource::DrawAmmoHistory( float flTime ) { - for ( int i = 0; i < MAX_HISTORY; i++ ) + for( int i = 0; i < MAX_HISTORY; i++ ) { - if ( rgAmmoHistory[i].type ) + if( rgAmmoHistory[i].type ) { rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); - if ( rgAmmoHistory[i].DisplayTime <= flTime ) - { // pic drawing time has expired + if( rgAmmoHistory[i].DisplayTime <= flTime ) + { + // pic drawing time has expired memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); CheckClearHistory(); } - else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO ) + else if( rgAmmoHistory[i].type == HISTSLOT_AMMO ) { wrect_t rcPic; HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); int r, g, b; - UnpackRGB(r,g,b, RGB_YELLOWISH); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); + UnpackRGB( r, g, b, RGB_YELLOWISH ); + float scale = ( rgAmmoHistory[i].DisplayTime - flTime ) * 80; + ScaleColors( r, g, b, min( scale, 255 ) ); // Draw the pic int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); int xpos = ScreenWidth - 24; - if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic - { // the dll has to make sure it has sent info the weapons you need + if( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic + { + // the dll has to make sure it has sent info the weapons you need SPR_Set( *spr, r, g, b ); SPR_DrawAdditive( 0, xpos, ypos, &rcPic ); } // do not draw black console string - if( !(( hud_textmode->value == 2 ) && ( scale < 200 )) ) + if( !( ( hud_textmode->value == 2 ) && ( scale < 200 ) ) ) // Draw the number gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b ); } - else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP ) + else if( rgAmmoHistory[i].type == HISTSLOT_WEAP ) { WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId ); - if ( !weap ) + if( !weap ) return 1; // we don't know about the weapon yet, so don't draw anything int r, g, b; - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r,g,b, RGB_YELLOWISH ); - if ( !gWR.HasAmmo( weap ) ) - UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red + if( !gWR.HasAmmo( weap ) ) + UnpackRGB( r, g, b, RGB_REDISH ); // if the weapon doesn't have ammo, display it as red - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); + float scale = ( rgAmmoHistory[i].DisplayTime - flTime ) * 80; + ScaleColors( r, g, b, min( scale, 255 ) ); - int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left); + int ypos = ScreenHeight - ( AMMO_PICKUP_PICK_HEIGHT + ( AMMO_PICKUP_GAP * i ) ); + int xpos = ScreenWidth - ( weap->rcInactive.right - weap->rcInactive.left ); SPR_Set( weap->hInactive, r, g, b ); SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive ); } - else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM ) + else if( rgAmmoHistory[i].type == HISTSLOT_ITEM ) { int r, g, b; - if ( !rgAmmoHistory[i].iId ) + if( !rgAmmoHistory[i].iId ) continue; // sprite not loaded wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); - UnpackRGB(r,g,b, RGB_YELLOWISH); - float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; - ScaleColors(r, g, b, min(scale, 255) ); + UnpackRGB( r, g, b, RGB_YELLOWISH ); + float scale = ( rgAmmoHistory[i].DisplayTime - flTime ) * 80; + ScaleColors( r, g, b, min( scale, 255 ) ); - int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i)); - int xpos = ScreenWidth - (rect.right - rect.left) - 10; + int ypos = ScreenHeight - ( AMMO_PICKUP_PICK_HEIGHT + ( AMMO_PICKUP_GAP * i ) ); + int xpos = ScreenWidth - ( rect.right - rect.left ) - 10; SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b ); SPR_DrawAdditive( 0, xpos, ypos, &rect ); @@ -185,8 +187,5 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) } } - return 1; } - - diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 3d7d5947..f1063ae1 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -26,8 +26,8 @@ private: WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array // counts of weapons * ammo - WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there - int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type + WEAPON* rgSlots[MAX_WEAPON_SLOTS + 1][MAX_WEAPON_POSITIONS + 1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there + int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type public: void Init( void ) @@ -49,25 +49,25 @@ public: WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; } void AddWeapon( WEAPON *wp ) { - rgWeapons[ wp->iId ] = *wp; - LoadWeaponSprites( &rgWeapons[ wp->iId ] ); + rgWeapons[wp->iId] = *wp; + LoadWeaponSprites( &rgWeapons[wp->iId] ); } void PickupWeapon( WEAPON *wp ) { - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp; + rgSlots[wp->iSlot][wp->iSlotPos] = wp; } void DropWeapon( WEAPON *wp ) { - rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL; + rgSlots[wp->iSlot][wp->iSlotPos] = NULL; } void DropAllWeapons( void ) { - for ( int i = 0; i < MAX_WEAPONS; i++ ) + for( int i = 0; i < MAX_WEAPONS; i++ ) { - if ( rgWeapons[i].iId ) + if( rgWeapons[i].iId ) DropWeapon( &rgWeapons[i] ); } } @@ -94,7 +94,6 @@ public: extern WeaponsResource gWR; - #define MAX_HISTORY 12 enum { HISTSLOT_EMPTY, @@ -138,6 +137,3 @@ public: }; extern HistoryResource gHR; - - - diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp index 4d08892d..2f26057f 100644 --- a/cl_dll/battery.cpp +++ b/cl_dll/battery.cpp @@ -25,23 +25,22 @@ #include #include -DECLARE_MESSAGE(m_Battery, Battery) +DECLARE_MESSAGE( m_Battery, Battery ) -int CHudBattery::Init(void) +int CHudBattery::Init( void ) { m_iBat = 0; m_fFade = 0; m_iFlags = 0; - HOOK_MESSAGE(Battery); + HOOK_MESSAGE( Battery ); - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); return 1; } - -int CHudBattery::VidInit(void) +int CHudBattery::VidInit( void ) { int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); @@ -54,15 +53,14 @@ int CHudBattery::VidInit(void) return 1; } -int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) +int CHudBattery::MsgFunc_Battery( const char *pszName, int iSize, void *pbuf ) { m_iFlags |= HUD_ACTIVE; - BEGIN_READ( pbuf, iSize ); int x = READ_SHORT(); - if (x != m_iBat) + if( x != m_iBat ) { m_fFade = FADE_TIME; m_iBat = x; @@ -71,68 +69,65 @@ int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) return 1; } - -int CHudBattery::Draw(float flTime) +int CHudBattery::Draw( float flTime ) { - if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + if( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) return 1; int r, g, b, x, y, a; wrect_t rc; rc = *m_prc2; - rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + rc.top += m_iHeight * ( (float)( 100 - ( min( 100,m_iBat ) ) ) * 0.01 ); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r, g, b, RGB_YELLOWISH ); - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + if( !( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) ) return 1; // Has health changed? Flash the health # - if (m_fFade) + if( m_fFade ) { - if (m_fFade > FADE_TIME) + if( m_fFade > FADE_TIME ) m_fFade = FADE_TIME; - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) + m_fFade -= ( gHUD.m_flTimeDelta * 20 ); + if( m_fFade <= 0 ) { a = 128; m_fFade = 0; } // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - + a = MIN_ALPHA + ( m_fFade / FADE_TIME ) * 128; } else a = MIN_ALPHA; - ScaleColors(r, g, b, a ); - - int iOffset = (m_prc1->bottom - m_prc1->top)/6; + ScaleColors( r, g, b, a ); + + int iOffset = ( m_prc1->bottom - m_prc1->top ) / 6; y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = ScreenWidth/5; + x = ScreenWidth / 5; // make sure we have the right sprite handles - if ( !m_hSprite1 ) + if( !m_hSprite1 ) m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); - if ( !m_hSprite2 ) + if( !m_hSprite2 ) m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); + SPR_Set( m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, m_prc1 ); - if (rc.bottom > rc.top) + if( rc.bottom > rc.top ) { - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); + SPR_Set( m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset + ( rc.top - m_prc2->top ), &rc ); } - x += (m_prc1->right - m_prc1->left); - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); + x += ( m_prc1->right - m_prc1->left ); + x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b ); return 1; } diff --git a/cl_dll/camera.h b/cl_dll/camera.h index 08c87920..448b22ca 100644 --- a/cl_dll/camera.h +++ b/cl_dll/camera.h @@ -18,7 +18,6 @@ extern int cam_thirdperson; void CAM_Init( void ); void CAM_ClearStates( void ); -void CAM_StartMouseMove(void); -void CAM_EndMouseMove(void); - -#endif // _CAMERA_H_ +void CAM_StartMouseMove( void ); +void CAM_EndMouseMove( void ); +#endif // _CAMERA_H_ diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 80fdfe81..096548a1 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -32,7 +32,7 @@ extern "C" cl_enginefunc_t gEngfuncs; CHud gHUD; mobile_engfuncs_t *gMobileEngfuncs = NULL; -void InitInput (void); +void InitInput( void ); void EV_HookEvents( void ); void IN_Commands( void ); @@ -73,16 +73,16 @@ int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) { int iret = 0; - switch ( hullnumber ) + switch( hullnumber ) { case 0: // Normal player - mins = Vector(-16, -16, -36); - maxs = Vector(16, 16, 36); + mins = Vector( -16, -16, -36 ); + maxs = Vector( 16, 16, 36 ); iret = 1; break; case 1: // Crouched player - mins = Vector(-16, -16, -18 ); - maxs = Vector(16, 16, 18 ); + mins = Vector( -16, -16, -18 ); + maxs = Vector( 16, 16, 18 ); iret = 1; break; case 2: // Point based hull @@ -103,7 +103,7 @@ HUD_ConnectionlessPacket size of the response_buffer, so you must zero it out if you choose not to respond. ================================ */ -int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) { // Parse stuff from args int max_buffer_size = *response_buffer_size; @@ -136,17 +136,16 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) { gEngfuncs = *pEnginefuncs; - if (iVersion != CLDLL_INTERFACE_VERSION) + if( iVersion != CLDLL_INTERFACE_VERSION ) return 0; - memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + memcpy( &gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t) ); EV_HookEvents(); return 1; } - /* ========================== HUD_VidInit @@ -180,7 +179,6 @@ void DLLEXPORT HUD_Init( void ) gHUD.Init(); } - /* ========================== HUD_Redraw @@ -197,7 +195,6 @@ int DLLEXPORT HUD_Redraw( float time, int intermission ) return 1; } - /* ========================== HUD_UpdateClientData @@ -211,11 +208,11 @@ returns 1 if anything has been changed, 0 otherwise. ========================== */ -int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) +int DLLEXPORT HUD_UpdateClientData( client_data_t *pcldata, float flTime ) { IN_Commands(); - return gHUD.UpdateClientData(pcldata, flTime ); + return gHUD.UpdateClientData( pcldata, flTime ); } /* @@ -243,7 +240,6 @@ void DLLEXPORT HUD_Frame( double time ) { } - /* ========================== HUD_VoiceStatus @@ -252,7 +248,7 @@ Called when a player starts or stops talking. ========================== */ -void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +void DLLEXPORT HUD_VoiceStatus( int entindex, qboolean bTalking ) { } @@ -272,7 +268,7 @@ void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ) { - if( gpMobileEngfuncs->version != MOBILITY_API_VERSION ) - return; - gMobileEngfuncs = gpMobileEngfuncs; + if( gpMobileEngfuncs->version != MOBILITY_API_VERSION ) + return; + gMobileEngfuncs = gpMobileEngfuncs; } diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index de1b5d4a..fda4b812 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -28,7 +28,7 @@ typedef unsigned char byte; typedef unsigned short word; typedef float vec_t; -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +typedef int ( *pfnUserMsgHook )( const char *pszName, int iSize, void *pbuf ); #include "util_vector.h" diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index aa2cd853..8d9661b2 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -15,6 +15,7 @@ // // cl_util.h // + #include "exportdef.h" #include "cvardef.h" @@ -25,72 +26,70 @@ // Macros to hook function calls into the HUD object -#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ - { \ - return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ - } +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg( #x, __MsgFunc_##x ); +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x( const char *pszName, int iSize, void *pbuf ) \ + { \ + return gHUD.y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } #define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); #define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ - { \ - gHUD.y.UserCmd_##x( ); \ - } - + { \ + gHUD.y.UserCmd_##x( ); \ + } inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } -#define SPR_Load (*gEngfuncs.pfnSPR_Load) -#define SPR_Set (*gEngfuncs.pfnSPR_Set) -#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) -#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) +#define SPR_Load( *gEngfuncs.pfnSPR_Load ) +#define SPR_Set( *gEngfuncs.pfnSPR_Set ) +#define SPR_Frames( *gEngfuncs.pfnSPR_Frames ) +#define SPR_GetList( *gEngfuncs.pfnSPR_GetList ) // SPR_Draw draws a the current sprite as solid -#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) -// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) -#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) +#define SPR_Draw( *gEngfuncs.pfnSPR_Draw ) +// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) +#define SPR_DrawHoles( *gEngfuncs.pfnSPR_DrawHoles ) // SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) -#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) +#define SPR_DrawAdditive( *gEngfuncs.pfnSPR_DrawAdditive ) -// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. -#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) +// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. +#define SPR_EnableScissor( *gEngfuncs.pfnSPR_EnableScissor ) // SPR_DisableScissor disables the clipping rect -#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) +#define SPR_DisableScissor( *gEngfuncs.pfnSPR_DisableScissor ) // -#define FillRGBA (*gEngfuncs.pfnFillRGBA) - +#define FillRGBA( *gEngfuncs.pfnFillRGBA ) // ScreenHeight returns the height of the screen, in pixels -#define ScreenHeight (gHUD.m_scrinfo.iHeight) +#define ScreenHeight( gHUD.m_scrinfo.iHeight ) // ScreenWidth returns the width of the screen, in pixels -#define ScreenWidth (gHUD.m_scrinfo.iWidth) +#define ScreenWidth( gHUD.m_scrinfo.iWidth ) // Use this to set any co-ords in 640x480 space -#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) -#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) +#define XRES(x) ( (int)( float(x) * ( (float)ScreenWidth / 640.0f ) + 0.5f ) ) +#define YRES(y) ( (int)( float(y) * ( (float)ScreenHeight / 480.0f ) + 0.5f ) ) // use this to project world coordinates to screen coordinates -#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f ) -#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f ) +#define XPROJECT(x) ( ( 1.0f + (x) ) * ScreenWidth * 0.5f ) +#define YPROJECT(y) ( ( 1.0f - (y) ) * ScreenHeight * 0.5f ) -#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) -#define ServerCmd (*gEngfuncs.pfnServerCmd) -#define ClientCmd (*gEngfuncs.pfnClientCmd) -#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) -#define AngleVectors (*gEngfuncs.pfnAngleVectors) +#define GetScreenInfo( *gEngfuncs.pfnGetScreenInfo ) +#define ServerCmd( *gEngfuncs.pfnServerCmd ) +#define ClientCmd( *gEngfuncs.pfnClientCmd ) +#define SetCrosshair( *gEngfuncs.pfnSetCrosshair ) +#define AngleVectors( *gEngfuncs.pfnAngleVectors ) extern cvar_t *hud_textmode; extern float g_hud_text_color[3]; -inline void DrawSetTextColor(float r, float g, float b) +inline void DrawSetTextColor( float r, float g, float b ) { if( hud_textmode->value == 1 ) - g_hud_text_color[0]=r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; + g_hud_text_color[0] = r, g_hud_text_color[1] = g, g_hud_text_color[2] = b; else gEngfuncs.pfnDrawSetTextColor( r, g, b ); } + // Gets the height & width of a sprite, at the specified frame inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } @@ -104,7 +103,7 @@ inline int TextMessageDrawChar( int x, int y, int number, int r, int g, in inline int DrawConsoleString( int x, int y, const char *string ) { if( hud_textmode->value == 1 ) - return gHUD.DrawHudString( x, y, 9999, (char*)string, 255*g_hud_text_color[0], 255*g_hud_text_color[1], 255*g_hud_text_color[2]); + return gHUD.DrawHudString( x, y, 9999, (char*)string, 255 * g_hud_text_color[0], 255 * g_hud_text_color[1], 255 * g_hud_text_color[2] ); return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); } @@ -120,7 +119,7 @@ inline int ConsoleStringLen( const char *string ) { int _width = 0, _height = 0; if( hud_textmode->value == 1 ) - return gHUD.DrawHudStringLen((char*)string); + return gHUD.DrawHudStringLen( (char*)string ); GetConsoleStringSize( string, &_width, &_height ); return _width; } @@ -136,7 +135,7 @@ inline void CenterPrint( const char *string ) } // returns the players name of entity no. -#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) +#define GetPlayerInfo( *gEngfuncs.pfnGetPlayerInfo ) // sound functions inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } @@ -148,16 +147,16 @@ inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( void ScaleColors( int &r, int &g, int &b, int a ); -#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -#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];} -inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} -float Length(const float *v); -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); -void VectorScale (const float *in, float scale, float *out); -float VectorNormalize (float *v); -void VectorInverse ( float *v ); +#define DotProduct(x, y) ((x)[0] * (y)[0] + (x)[1] * (y)[1] + (x)[2] * (y)[2]) +#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]; } +inline void VectorClear( float *a ) { a[0] = 0.0; a[1] = 0.0; a[2] = 0.0; } +float Length( const float *v ); +void VectorMA( const float *veca, float scale, const float *vecb, float *vecc ); +void VectorScale( const float *in, float scale, float *out ); +float VectorNormalize( float *v ); +void VectorInverse( float *v ); extern vec3_t vec3_origin; @@ -166,11 +165,11 @@ extern vec3_t vec3_origin; // disable 'truncation from 'const double' to 'float' warning message #pragma warning( disable: 4305 ) -inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ +inline void UnpackRGB( int &r, int &g, int &b, unsigned long ulRGB )\ {\ - r = (ulRGB & 0xFF0000) >>16;\ - g = (ulRGB & 0xFF00) >> 8;\ + r = ( ulRGB & 0xFF0000 ) >> 16;\ + g = ( ulRGB & 0xFF00 ) >> 8;\ b = ulRGB & 0xFF;\ } -HSPRITE LoadSprite(const char *pszName); +HSPRITE LoadSprite( const char *pszName ); diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index df84daf8..3a3f0a6f 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -27,7 +27,7 @@ // g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing // command. If it is 1, then we should play events/sounds etc., otherwise, we just will be // updating state info, but not firing events -int g_runfuncs = 0; +int g_runfuncs = 0; // During our weapon prediction processing, we'll need to reference some data that is part of // the final state passed into the postthink functionality. We'll set this pointer and then @@ -41,14 +41,14 @@ COM_Log Log debug messages to file ( appends ) ==================== */ -void COM_Log( char *pszFile, char *fmt, ...) +void COM_Log( char *pszFile, char *fmt, ... ) { va_list argptr; char string[1024]; FILE *fp; char *pfilename; - - if ( !pszFile ) + + if( !pszFile ) { pfilename = "c:\\hllog.txt"; } @@ -57,15 +57,15 @@ void COM_Log( char *pszFile, char *fmt, ...) pfilename = pszFile; } - va_start (argptr,fmt); - vsprintf (string, fmt,argptr); - va_end (argptr); + va_start( argptr, fmt ); + vsprintf( string, fmt, argptr ); + va_end( argptr ); fp = fopen( pfilename, "a+t"); - if (fp) + if( fp ) { - fprintf(fp, "%s", string); - fclose(fp); + fprintf( fp, "%s", string ); + fclose( fp ); } } @@ -83,7 +83,7 @@ Change weapon model animation void HUD_SendWeaponAnim( int iAnim, int body, int force ) { // Don't actually change it. - if ( !g_runfuncs && !force ) + if( !g_runfuncs && !force ) return; g_currentanim = iAnim; @@ -113,7 +113,7 @@ Play a sound, if we are seeing this command for the first time */ void HUD_PlaySound( char *sound, float volume ) { - if ( !g_runfuncs || !g_finalstate ) + if( !g_runfuncs || !g_finalstate ) return; gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); @@ -132,7 +132,7 @@ void HUD_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short event vec3_t org; vec3_t ang; - if ( !g_runfuncs || !g_finalstate ) + if( !g_runfuncs || !g_finalstate ) return; // Weapon prediction events are assumed to occur at the player's origin @@ -151,7 +151,6 @@ void HUD_SetMaxSpeed( const edict_t *ed, float speed ) { } - /* ===================== UTIL_WeaponTimeBase @@ -167,7 +166,7 @@ float UTIL_WeaponTimeBase( void ) static unsigned int glSeed = 0; -unsigned int seed_table[ 256 ] = +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, @@ -188,16 +187,16 @@ unsigned int seed_table[ 256 ] = }; unsigned int U_Random( void ) -{ +{ glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); + glSeed += seed_table[glSeed & 0xff]; + + return ( ++glSeed & 0x0fffffff ); } void U_Srand( unsigned int seed ) { - glSeed = seed_table[ seed & 0xff ]; + glSeed = seed_table[seed & 0xff]; } /* @@ -212,7 +211,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) U_Srand( (int)seed + low + high ); range = high - low + 1; - if ( !(range - 1) ) + if( !( range - 1 ) ) { return low; } @@ -225,7 +224,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) offset = rnum % range; - return (low + offset); + return ( low + offset ); } } @@ -236,7 +235,6 @@ UTIL_SharedRandomFloat */ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) { - // unsigned int range; U_Srand( (int)seed + *(int *)&low + *(int *)&high ); @@ -245,7 +243,7 @@ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) U_Random(); range = high - low; - if ( !range ) + if( !range ) { return low; } @@ -258,7 +256,7 @@ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) offset = (float)tensixrand / 65536.0; - return (low + offset * range ); + return ( low + offset * range ); } } diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index c924d8b4..7e1fdd77 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -20,7 +20,7 @@ extern "C" void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); } -void COM_Log( char *pszFile, char *fmt, ...); +void COM_Log( char *pszFile, char *fmt, ... ); int CL_IsDead( void ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); @@ -34,9 +34,8 @@ void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); int stub_PrecacheModel( char* s ); int stub_PrecacheSound( char* s ); unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction ( unsigned long function ); -void stub_SetModel ( struct edict_s *e, const char *m ); - +const char *stub_NameForFunction( unsigned long function ); +void stub_SetModel( struct edict_s *e, const char *m ); extern cvar_t *cl_lw; @@ -44,5 +43,4 @@ extern int g_runfuncs; extern vec3_t v_angles; extern float g_lastFOV; extern struct local_state_s *g_finalstate; - -#endif \ No newline at end of file +#endif diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 70c0393f..455dfd36 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -15,6 +15,7 @@ // // death notice // + #include "hud.h" #include "cl_util.h" #include "parsemsg.h" @@ -25,8 +26,8 @@ DECLARE_MESSAGE( m_DeathNotice, DeathMsg ) struct DeathNoticeItem { - char szKiller[MAX_PLAYER_NAME_LENGTH*2]; - char szVictim[MAX_PLAYER_NAME_LENGTH*2]; + char szKiller[MAX_PLAYER_NAME_LENGTH * 2]; + char szVictim[MAX_PLAYER_NAME_LENGTH * 2]; int iId; // the index number of the associated sprite int iSuicide; int iTeamKill; @@ -41,31 +42,30 @@ static int DEATHNOTICE_DISPLAY_TIME = 6; #define DEATHNOTICE_TOP 32 -DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; +DeathNoticeItem rgDeathNoticeList[MAX_DEATHNOTICES + 1]; float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; -float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; +float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; float *GetClientColor( int clientIndex ) { - switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) + switch( g_PlayerExtraInfo[clientIndex].teamnumber ) { case 1: return g_ColorBlue; case 2: return g_ColorRed; case 3: return g_ColorYellow; case 4: return g_ColorGreen; case 0: return g_ColorYellow; - - default : return g_ColorGrey; + default: return g_ColorGrey; } return NULL; } -int CHudDeathNotice :: Init( void ) +int CHudDeathNotice::Init( void ) { gHUD.AddHudElem( this ); @@ -76,33 +76,32 @@ int CHudDeathNotice :: Init( void ) return 1; } - -void CHudDeathNotice :: InitHUDData( void ) +void CHudDeathNotice::InitHUDData( void ) { memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); } - -int CHudDeathNotice :: VidInit( void ) +int CHudDeathNotice::VidInit( void ) { m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); return 1; } -int CHudDeathNotice :: Draw( float flTime ) +int CHudDeathNotice::Draw( float flTime ) { int x, y, r, g, b; - for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + for( int i = 0; i < MAX_DEATHNOTICES; i++ ) { - if ( rgDeathNoticeList[i].iId == 0 ) + if( rgDeathNoticeList[i].iId == 0 ) break; // we've gone through them all - if ( rgDeathNoticeList[i].flDisplayTime < flTime ) - { // display time has expired + if( rgDeathNoticeList[i].flDisplayTime < flTime ) + { + // display time has expired // remove the current item from the list - memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); + memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i + 1], sizeof(DeathNoticeItem) * ( MAX_DEATHNOTICES - i ) ); i--; // continue on the next item; stop the counter getting incremented continue; } @@ -111,26 +110,26 @@ int CHudDeathNotice :: Draw( float flTime ) // Only draw if the viewport will let me // vgui dropped out - //if ( gViewPort && gViewPort->AllowedToPrintText() ) + //if( gViewPort && gViewPort->AllowedToPrintText() ) { // Draw the death notice - y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!! + y = YRES( DEATHNOTICE_TOP ) + 2 + ( 20 * i ); //!!! - int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; - x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + int id = ( rgDeathNoticeList[i].iId == -1 ) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth - ConsoleStringLen( rgDeathNoticeList[i].szVictim ) - ( gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left ); - if ( !rgDeathNoticeList[i].iSuicide ) + if( !rgDeathNoticeList[i].iSuicide ) { - x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + x -= ( 5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); // Draw killers name - if ( rgDeathNoticeList[i].KillerColor ) + if( rgDeathNoticeList[i].KillerColor ) DrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); } - r = 255; g = 80; b = 0; - if ( rgDeathNoticeList[i].iTeamKill ) + r = 255; g = 80; b = 0; + if( rgDeathNoticeList[i].iTeamKill ) { r = 10; g = 240; b = 10; // display it in sickly green } @@ -139,12 +138,12 @@ int CHudDeathNotice :: Draw( float flTime ) SPR_Set( gHUD.GetSprite(id), r, g, b ); SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); - x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + x += ( gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left ); // Draw victims name (if it was a player that was killed) - if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + if( rgDeathNoticeList[i].iNonPlayerKill == FALSE ) { - if ( rgDeathNoticeList[i].VictimColor ) + if( rgDeathNoticeList[i].VictimColor ) DrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); } @@ -155,7 +154,7 @@ int CHudDeathNotice :: Draw( float flTime ) } // This message handler may be better off elsewhere -int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) +int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) { int i; m_iFlags |= HUD_ACTIVE; @@ -169,27 +168,27 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p strcpy( killedwith, "d_" ); strncat( killedwith, READ_STRING(), sizeof(killedwith) - strlen(killedwith) - 1 ); - gHUD.m_Spectator.DeathMessage(victim); + gHUD.m_Spectator.DeathMessage( victim ); - for ( i = 0; i < MAX_DEATHNOTICES; i++ ) + for( i = 0; i < MAX_DEATHNOTICES; i++ ) { - if ( rgDeathNoticeList[i].iId == 0 ) + if( rgDeathNoticeList[i].iId == 0 ) break; } - if ( i == MAX_DEATHNOTICES ) - { // move the rest of the list forward to make room for this item - memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); + if( i == MAX_DEATHNOTICES ) + { + // move the rest of the list forward to make room for this item + memmove( rgDeathNoticeList, rgDeathNoticeList + 1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); i = MAX_DEATHNOTICES - 1; } - //if (gViewPort) + //if(gViewPort) // gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); - // Get the Killer's name - char *killer_name = g_PlayerInfoList[ killer ].name; - if ( !killer_name ) + char *killer_name = g_PlayerInfoList[killer].name; + if( !killer_name ) { killer_name = ""; rgDeathNoticeList[i].szKiller[0] = 0; @@ -198,14 +197,14 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p { rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH - 1] = 0; } // Get the Victim's name char *victim_name = NULL; // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) - if ( ((char)victim) != -1 ) - victim_name = g_PlayerInfoList[ victim ].name; + if ( ( (char)victim ) != -1 ) + victim_name = g_PlayerInfoList[victim].name; if ( !victim_name ) { victim_name = ""; @@ -215,16 +214,16 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p { rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); - rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH - 1] = 0; } // Is it a non-player object kill? - if ( ((char)victim) == -1 ) + if ( ( (char)victim ) == -1 ) { rgDeathNoticeList[i].iNonPlayerKill = TRUE; // Store the object's name in the Victim slot (skip the d_ bit) - strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); + strcpy( rgDeathNoticeList[i].szVictim, killedwith + 2 ); } else { @@ -243,7 +242,7 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; - if (rgDeathNoticeList[i].iNonPlayerKill) + if( rgDeathNoticeList[i].iNonPlayerKill ) { ConsolePrint( rgDeathNoticeList[i].szKiller ); ConsolePrint( " killed a " ); @@ -253,11 +252,11 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p else { // record the death notice in the console - if ( rgDeathNoticeList[i].iSuicide ) + if( rgDeathNoticeList[i].iSuicide ) { ConsolePrint( rgDeathNoticeList[i].szVictim ); - if ( !strcmp( killedwith, "d_world" ) ) + if( !strcmp( killedwith, "d_world" ) ) { ConsolePrint( " died" ); } @@ -266,7 +265,7 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p ConsolePrint( " killed self" ); } } - else if ( rgDeathNoticeList[i].iTeamKill ) + else if( rgDeathNoticeList[i].iTeamKill ) { ConsolePrint( rgDeathNoticeList[i].szKiller ); ConsolePrint( " killed his teammate " ); @@ -279,17 +278,17 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p ConsolePrint( rgDeathNoticeList[i].szVictim ); } - if ( *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + if( *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) { ConsolePrint( " with " ); // replace the code names with the 'real' names - if ( !strcmp( killedwith+2, "egon" ) ) + if( !strcmp( killedwith + 2, "egon" ) ) strcpy( killedwith, "d_gluon gun" ); - if ( !strcmp( killedwith+2, "gauss" ) ) + if ( !strcmp( killedwith + 2, "gauss" ) ) strcpy( killedwith, "d_tau cannon" ); - ConsolePrint( killedwith+2 ); // skip over the "d_" part + ConsolePrint( killedwith + 2 ); // skip over the "d_" part } ConsolePrint( "\n" ); @@ -297,7 +296,3 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p return 1; } - - - - diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp index dfa7f8ef..f114ead0 100644 --- a/cl_dll/demo.cpp +++ b/cl_dll/demo.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "hud.h" #include "cl_util.h" #include "demo.h" @@ -41,14 +42,14 @@ Write some data to the demo stream void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) { int pos = 0; - unsigned char buf[ 32 * 1024 ]; - *( int * )&buf[pos] = type; - pos+=sizeof( int ); + unsigned char buf[32 * 1024]; + *(int *)&buf[pos] = type; + pos += sizeof(int); memcpy( &buf[pos], buffer, size ); // Write full buffer out - gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof(int), buf ); } /* @@ -63,36 +64,36 @@ void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) int type; int i = 0; - type = *( int * )buffer; - i += sizeof( int ); - switch ( type ) + type = *(int *)buffer; + i += sizeof(int); + switch( type ) { case TYPE_SNIPERDOT: - g_demosniper = *(int * )&buffer[ i ]; - i += sizeof( int ); + g_demosniper = *(int *)&buffer[i]; + i += sizeof(int); - if ( g_demosniper ) + if( g_demosniper ) { - g_demosniperdamage = *( int * )&buffer[ i ]; - i += sizeof( int ); + g_demosniperdamage = *(int *)&buffer[i]; + i += sizeof(int); - g_demosniperangles[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperangles[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 0 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 1 ] = *(float *)&buffer[i]; - i += sizeof( float ); - g_demosniperorg[ 2 ] = *(float *)&buffer[i]; - i += sizeof( float ); + g_demosniperangles[0] = *(float *)&buffer[i]; + i += sizeof(float); + g_demosniperangles[1] = *(float *)&buffer[i]; + i += sizeof(float); + g_demosniperangles[2] = *(float *)&buffer[i]; + i += sizeof(float); + g_demosniperorg[0] = *(float *)&buffer[i]; + i += sizeof(float); + g_demosniperorg[1] = *(float *)&buffer[i]; + i += sizeof(float); + g_demosniperorg[2] = *(float *)&buffer[i]; + i += sizeof(float); } break; case TYPE_ZOOM: - g_demozoom = *(float * )&buffer[ i ]; - i += sizeof( float ); + g_demozoom = *(float *)&buffer[i]; + i += sizeof(float); break; default: gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); diff --git a/cl_dll/demo.h b/cl_dll/demo.h index 3163ef38..a0a1b30e 100644 --- a/cl_dll/demo.h +++ b/cl_dll/demo.h @@ -23,5 +23,4 @@ extern int g_demosniperdamage; extern float g_demosniperorg[3]; extern float g_demosniperangles[3]; extern float g_demozoom; - -#endif \ No newline at end of file +#endif diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index 8dbdd383..07bd0ff3 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -20,14 +20,13 @@ #include "pmtrace.h" #include "pm_shared.h" - void Game_AddObjects( void ); extern vec3_t v_origin; int g_iAlive = 1; -extern "C" +extern "C" { int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); void DLLEXPORT HUD_CreateEntities( void ); @@ -47,7 +46,7 @@ HUD_AddEntity */ int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) { - switch ( type ) + switch( type ) { case ET_NORMAL: case ET_PLAYER: @@ -62,14 +61,13 @@ int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *mode // each frame every entity passes this function, so the overview hooks // it to filter the overview entities - if ( g_iUser1 ) + if( g_iUser1 ) { gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); - if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && + if( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent->index == g_iUser2 ) return 0; // don't draw the player we are following in eye - } return 1; @@ -115,16 +113,16 @@ void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct VectorCopy( src->velocity, dst->velocity ); - dst->frame = src->frame; + dst->frame = src->frame; dst->modelindex = src->modelindex; - dst->skin = src->skin; + dst->skin = src->skin; dst->effects = src->effects; dst->weaponmodel = src->weaponmodel; dst->movetype = src->movetype; dst->sequence = src->sequence; dst->animtime = src->animtime; - dst->solid = src->solid; + dst->solid = src->solid; dst->rendermode = src->rendermode; dst->renderamt = src->renderamt; @@ -134,10 +132,10 @@ void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct dst->renderfx = src->renderfx; dst->framerate = src->framerate; - dst->body = src->body; + dst->body = src->body; - memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); - memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof(byte) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof(byte) ); VectorCopy( src->basevelocity, dst->basevelocity ); @@ -147,12 +145,12 @@ void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct dst->spectator = src->spectator; dst->usehull = src->usehull; dst->playerclass = src->playerclass; - dst->team = src->team; + dst->team = src->team; dst->colormap = src->colormap; // Save off some data so other areas of the Client DLL can get to it cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index - if ( dst->number == player->index ) + if( dst->number == player->index ) { g_iPlayerClass = dst->playerclass; g_iTeamNumber = dst->team; @@ -173,7 +171,7 @@ Because we can predict an arbitrary number of frames before the server responds update is occupying. ========================= */ -void DLLEXPORT HUD_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 ) +void DLLEXPORT HUD_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 ) { ps->oldbuttons = pps->oldbuttons; ps->flFallVelocity = pps->flFallVelocity; @@ -181,13 +179,13 @@ void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct ps->playerclass = pps->playerclass; pcd->viewmodel = ppcd->viewmodel; - pcd->m_iId = ppcd->m_iId; + pcd->m_iId = ppcd->m_iId; pcd->ammo_shells = ppcd->ammo_shells; pcd->ammo_nails = ppcd->ammo_nails; pcd->ammo_cells = ppcd->ammo_cells; pcd->ammo_rockets = ppcd->ammo_rockets; pcd->m_flNextAttack = ppcd->m_flNextAttack; - pcd->fov = ppcd->fov; + pcd->fov = ppcd->fov; pcd->weaponanim = ppcd->weaponanim; pcd->tfstate = ppcd->tfstate; pcd->maxspeed = ppcd->maxspeed; @@ -204,18 +202,17 @@ void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct // Duck prevention pcd->iuser3 = ppcd->iuser3; - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { // in specator mode we tell the engine who we want to spectate and how // iuser3 is not used for duck prevention (since the spectator can't duck at all) pcd->iuser1 = g_iUser1; // observer mode pcd->iuser2 = g_iUser2; // first target pcd->iuser3 = g_iUser3; // second target - } // Fire prevention - pcd->iuser4 = ppcd->iuser4; + pcd->iuser4 = ppcd->iuser4; pcd->fuser2 = ppcd->fuser2; pcd->fuser3 = ppcd->fuser3; @@ -225,7 +222,7 @@ void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct VectorCopy( ppcd->vuser3, pcd->vuser3 ); VectorCopy( ppcd->vuser4, pcd->vuser4 ); - memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); + memcpy( wd, pwd, 32 * sizeof(weapon_data_t) ); } /* @@ -243,35 +240,33 @@ void MoveModel( void ) // Load it up with some bogus data player = gEngfuncs.GetLocalPlayer(); - if ( !player ) + if( !player ) return; mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - for ( j = 0; j < 3; j++ ) + for( j = 0; j < 3; j++ ) { // Don't draw over ourself... - if ( ( i == 1 ) && ( j == 1 ) ) + if( ( i == 1 ) && ( j == 1 ) ) continue; - mymodel[ i * 3 + j ] = *player; + mymodel[i * 3 + j] = *player; - mymodel[ i * 3 + j ].player = 0; + mymodel[i * 3 + j].player = 0; - mymodel[ i * 3 + j ].model = mod; - mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + mymodel[i * 3 + j].model = mod; + mymodel[i * 3 + j].curstate.modelindex = modelindex; - // Move it out a bit - mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); - mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + // Move it out a bit + mymodel[i * 3 + j].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[i * 3 + j].origin[1] = player->origin[1] + 50 * ( 1 - j ); - gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i * 3 + j] ); } } - } - #endif //#define TRACE_TEST @@ -285,12 +280,12 @@ void TraceModel( void ) { cl_entity_t *ent; - if ( hitent <= 0 ) + if( hitent <= 0 ) return; // Load it up with some bogus data ent = gEngfuncs.GetEntityByIndex( hitent ); - if ( !ent ) + if( !ent ) return; hit = *ent; @@ -302,7 +297,6 @@ void TraceModel( void ) gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); } - #endif */ @@ -311,9 +305,9 @@ void ParticleCallback( struct particle_s *particle, float frametime ) { int i; - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - particle->org[ i ] += particle->vel[ i ] * frametime; + particle->org[i] += particle->vel[i] * frametime; } } @@ -322,13 +316,13 @@ void Particles( void ) { static float lasttime; float curtime; - + curtime = gEngfuncs.GetClientTime(); - if ( ( curtime - lasttime ) < 2.0 ) + if( ( curtime - lasttime ) < 2.0 ) return; - if ( !color ) + if( !color ) { color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); } @@ -339,20 +333,20 @@ void Particles( void ) particle_t *p; int i, j; - for ( i = 0; i < 1000; i++ ) + for( i = 0; i < 1000; i++ ) { int r, g, b; p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); - if ( !p ) + if( !p ) break; - for ( j = 0; j < 3; j++ ) + for( j = 0; j < 3; j++ ) { - p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; - p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + p->org[j] = v_origin[j] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 ); + p->vel[j] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); } - if ( color ) + if( color ) { sscanf( color->string, "%i %i %i", &r, &g, &b ); } @@ -363,7 +357,7 @@ void Particles( void ) b = 0; } - p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); // p->die is set to current time so all you have to do is add an additional time to it @@ -373,13 +367,13 @@ void Particles( void ) */ /* -void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +void TempEntCallback( struct tempent_s *ent, float frametime, float currenttime ) { int i; - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + ent->entity.curstate.origin[i] += ent->entity.baseline.origin[i] * frametime; } } @@ -387,10 +381,10 @@ void TempEnts( void ) { static float lasttime; float curtime; - + curtime = gEngfuncs.GetClientTime(); - if ( ( curtime - lasttime ) < 10.0 ) + if( ( curtime - lasttime ) < 10.0 ) return; lasttime = curtime; @@ -403,27 +397,27 @@ void TempEnts( void ) mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); - for ( i = 0; i < 100; i++ ) + for( i = 0; i < 100; i++ ) { - for ( j = 0; j < 3; j++ ) + for( j = 0; j < 3; j++ ) { - origin[ j ] = v_origin[ j ]; - if ( j != 2 ) + origin[j] = v_origin[j]; + if( j != 2 ) { - origin[ j ] += 75; + origin[j] += 75; } } p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); - if ( !p ) + if( !p ) break; - for ( j = 0; j < 3; j++ ) + for( j = 0; j < 3; j++ ) { - p->entity.curstate.origin[ j ] = origin[ j ]; + p->entity.curstate.origin[j] = origin[j]; // Store velocity in baseline origin - p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + p->entity.baseline.origin[j] = gEngfuncs.pfnRandomFloat( -100, 100 ); } // p->die is set to current time so all you have to do is add an additional time to it @@ -433,9 +427,9 @@ void TempEnts( void ) */ #if defined( BEAM_TEST ) -// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Note can't index beam[0] in Beam callback, so don't use that index // Room for 1 beam ( 0 can't be used ) -static cl_entity_t beams[ 2 ]; +static cl_entity_t beams[2]; void BeamEndModel( void ) { @@ -445,21 +439,21 @@ void BeamEndModel( void ) // Load it up with some bogus data player = gEngfuncs.GetLocalPlayer(); - if ( !player ) + if( !player ) return; mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); - if ( !mod ) + if( !mod ) return; // Slot 1 - model = &beams[ 1 ]; + model = &beams[1]; *model = *player; model->player = 0; model->model = mod; model->curstate.modelindex = modelindex; - + // Move it out a bit model->origin[0] = player->origin[0] - 100; model->origin[1] = player->origin[1]; @@ -480,22 +474,22 @@ void Beams( void ) int index; BeamEndModel(); - - curtime = gEngfuncs.GetClientTime(); - float end[ 3 ]; - if ( ( curtime - lasttime ) < 10.0 ) + curtime = gEngfuncs.GetClientTime(); + float end[3]; + + if( ( curtime - lasttime ) < 10.0 ) return; mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); - if ( !mod ) + if( !mod ) return; lasttime = curtime; - end [ 0 ] = v_origin.x + 100; - end [ 1 ] = v_origin.y + 100; - end [ 2 ] = v_origin.z; + end[0] = v_origin.x + 100; + end[1] = v_origin.y + 100; + end[2] = v_origin.z; BEAM *p1; p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, @@ -519,7 +513,6 @@ void DLLEXPORT HUD_CreateEntities( void ) #if defined( TEST_IT ) MoveModel(); #endif - #if defined( TRACE_TEST ) TraceModel(); #endif @@ -530,11 +523,9 @@ void DLLEXPORT HUD_CreateEntities( void ) /* TempEnts(); */ - #if defined( BEAM_TEST ) Beams(); #endif - // Add in any game specific objects Game_AddObjects(); } @@ -552,19 +543,19 @@ void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct switch( event->event ) { case 5001: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options ) ); break; case 5011: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options ) ); break; case 5021: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options ) ); break; case 5031: - gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options ) ); break; case 5002: - gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options ), -100, 100 ); break; // Client side sound case 5004: @@ -610,19 +601,19 @@ void DLLEXPORT HUD_TempEntUpdate ( gEngfuncs.pEventAPI->EV_PushPMStates(); // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( -1 ); // !!!BUGBUG -- This needs to be time based - gTempEntFrame = (gTempEntFrame+1) & 31; + gTempEntFrame = ( gTempEntFrame + 1 ) & 31; pTemp = *ppTempEntActive; // !!! Don't simulate while paused.... This is sort of a hack, revisit. - if ( frametime <= 0 ) + if( frametime <= 0 ) { - while ( pTemp ) + while( pTemp ) { - if ( !(pTemp->flags & FTENT_NOMODEL ) ) + if( !( pTemp->flags & FTENT_NOMODEL ) ) { Callback_AddVisibleEntity( &pTemp->entity ); } @@ -637,7 +628,7 @@ void DLLEXPORT HUD_TempEntUpdate ( gravity = -frametime * cl_gravity; gravitySlow = gravity * 0.5; - while ( pTemp ) + while( pTemp ) { int active; @@ -645,25 +636,24 @@ void DLLEXPORT HUD_TempEntUpdate ( life = pTemp->die - client_time; pnext = pTemp->next; - if ( life < 0 ) + if( life < 0 ) { - if ( pTemp->flags & FTENT_FADEOUT ) + if( pTemp->flags & FTENT_FADEOUT ) { - if (pTemp->entity.curstate.rendermode == kRenderNormal) + if( pTemp->entity.curstate.rendermode == kRenderNormal) pTemp->entity.curstate.rendermode = kRenderTransTexture; pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); - if ( pTemp->entity.curstate.renderamt <= 0 ) + if( pTemp->entity.curstate.renderamt <= 0 ) active = 0; - } else active = 0; } - if ( !active ) // Kill it + if( !active ) // Kill it { pTemp->next = *ppTempEntFree; *ppTempEntFree = pTemp; - if ( !pprev ) // Deleting at head of list + if( !pprev ) // Deleting at head of list *ppTempEntActive = pnext; else pprev->next = pnext; @@ -671,14 +661,14 @@ void DLLEXPORT HUD_TempEntUpdate ( else { pprev = pTemp; - + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); - if ( pTemp->flags & FTENT_SPARKSHOWER ) + if( pTemp->flags & FTENT_SPARKSHOWER ) { // Adjust speed if it's time // Scale is next think time - if ( client_time > pTemp->entity.baseline.scale ) + if( client_time > pTemp->entity.baseline.scale ) { // Show Sparks gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); @@ -686,7 +676,7 @@ void DLLEXPORT HUD_TempEntUpdate ( // Reduce life pTemp->entity.baseline.framerate -= 0.1; - if ( pTemp->entity.baseline.framerate <= 0.0 ) + if( pTemp->entity.baseline.framerate <= 0.0 ) { pTemp->die = client_time; } @@ -700,7 +690,7 @@ void DLLEXPORT HUD_TempEntUpdate ( } } } - else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + else if( pTemp->flags & FTENT_PLYRATTACHMENT ) { cl_entity_t *pClient; @@ -708,16 +698,16 @@ void DLLEXPORT HUD_TempEntUpdate ( VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); } - else if ( pTemp->flags & FTENT_SINEWAVE ) + else if( pTemp->flags & FTENT_SINEWAVE ) { pTemp->x += pTemp->entity.baseline.origin[0] * frametime; pTemp->y += pTemp->entity.baseline.origin[1] * frametime; - pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); - pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * ( 10 * pTemp->entity.curstate.framerate ); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * ( 8 * pTemp->entity.curstate.framerate ); pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; } - else if ( pTemp->flags & FTENT_SPIRAL ) + else if( pTemp->flags & FTENT_SPIRAL ) { float s, c; s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); @@ -727,21 +717,20 @@ void DLLEXPORT HUD_TempEntUpdate ( pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)(size_t)pTemp ); pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; } - else { - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; } - if ( pTemp->flags & FTENT_SPRANIMATE ) + if( pTemp->flags & FTENT_SPRANIMATE ) { pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + if( pTemp->entity.curstate.frame >= pTemp->frameMax ) { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)( pTemp->entity.curstate.frame ); - if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + if( !( pTemp->flags & FTENT_SPRANIMATELOOP ) ) { // this animating sprite isn't set to loop, so destroy it. pTemp->die = client_time; @@ -750,21 +739,21 @@ void DLLEXPORT HUD_TempEntUpdate ( } } } - else if ( pTemp->flags & FTENT_SPRCYCLE ) + else if( pTemp->flags & FTENT_SPRCYCLE ) { pTemp->entity.curstate.frame += frametime * 10; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + if( pTemp->entity.curstate.frame >= pTemp->frameMax ) { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)( pTemp->entity.curstate.frame ); } } // Experiment #if 0 - if ( pTemp->flags & FTENT_SCALE ) - pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); + if( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * ( frametime / pTemp->entity.curstate.framerate ); #endif - if ( pTemp->flags & FTENT_ROTATE ) + if( pTemp->flags & FTENT_ROTATE ) { pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; @@ -773,98 +762,97 @@ void DLLEXPORT HUD_TempEntUpdate ( VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); } - if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + if( pTemp->flags & ( FTENT_COLLIDEALL | FTENT_COLLIDEWORLD ) ) { vec3_t traceNormal( 0.0f, 0.0f, 0.0f ); float traceFraction = 1; - if ( pTemp->flags & FTENT_COLLIDEALL ) + if( pTemp->flags & FTENT_COLLIDEALL ) { pmtrace_t pmtrace; physent_t *pe; - + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); - - if ( pmtrace.fraction != 1 ) + if( pmtrace.fraction != 1 ) { pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); - if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + if( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) { traceFraction = pmtrace.fraction; VectorCopy( pmtrace.plane.normal, traceNormal ); - if ( pTemp->hitcallback ) + if( pTemp->hitcallback ) { (*pTemp->hitcallback)( pTemp, &pmtrace ); } } } } - else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + else if( pTemp->flags & FTENT_COLLIDEWORLD ) { pmtrace_t pmtrace; - + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); - if ( pmtrace.fraction != 1 ) + if( pmtrace.fraction != 1 ) { traceFraction = pmtrace.fraction; VectorCopy( pmtrace.plane.normal, traceNormal ); - if ( pTemp->flags & FTENT_SPARKSHOWER ) + if( pTemp->flags & FTENT_SPARKSHOWER ) { // Chop spark speeds a bit more // VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); - if ( Length( pTemp->entity.baseline.origin ) < 10 ) + if( Length( pTemp->entity.baseline.origin ) < 10 ) { pTemp->entity.baseline.framerate = 0.0; } } - if ( pTemp->hitcallback ) + if( pTemp->hitcallback ) { (*pTemp->hitcallback)( pTemp, &pmtrace ); } } } - if ( traceFraction != 1 ) // Decent collision now, and damping works + if( traceFraction != 1 ) // Decent collision now, and damping works { float proj, damp; // Place at contact point - VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + VectorMA( pTemp->entity.prevstate.origin, traceFraction * frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); // Damp velocity damp = pTemp->bounceFactor; - if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + if( pTemp->flags & ( FTENT_GRAVITY | FTENT_SLOWGRAVITY ) ) { damp *= 0.5; - if ( traceNormal[2] > 0.9 ) // Hit floor? + if( traceNormal[2] > 0.9 ) // Hit floor? { - if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + if( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) { damp = 0; // Stop - pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->flags &= ~( FTENT_ROTATE | FTENT_GRAVITY | FTENT_SLOWGRAVITY | FTENT_COLLIDEWORLD | FTENT_SMOKETRAIL); pTemp->entity.angles[0] = 0; pTemp->entity.angles[2] = 0; } } } - if (pTemp->hitSound) + if( pTemp->hitSound ) { - Callback_TempEntPlaySound(pTemp, damp); + Callback_TempEntPlaySound( pTemp, damp ); } - if (pTemp->flags & FTENT_COLLIDEKILL) + if( pTemp->flags & FTENT_COLLIDEKILL ) { // die on impact pTemp->flags &= ~FTENT_FADEOUT; @@ -873,16 +861,16 @@ void DLLEXPORT HUD_TempEntUpdate ( else { // Reflect velocity - if ( damp != 0 ) + if( damp != 0 ) { proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); - VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + VectorMA( pTemp->entity.baseline.origin, -proj * 2, traceNormal, pTemp->entity.baseline.origin ); // Reflect rotation (fake) pTemp->entity.angles[1] = -pTemp->entity.angles[1]; } - if ( damp != 1 ) + if( damp != 1 ) { VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); @@ -892,11 +880,10 @@ void DLLEXPORT HUD_TempEntUpdate ( } } - - if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + if( ( pTemp->flags & FTENT_FLICKER ) && gTempEntFrame == pTemp->entity.curstate.effects ) { - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); - VectorCopy (pTemp->entity.origin, dl->origin); + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight(0); + VectorCopy( pTemp->entity.origin, dl->origin ); dl->radius = 60; dl->color.r = 255; dl->color.g = 120; @@ -904,30 +891,30 @@ void DLLEXPORT HUD_TempEntUpdate ( dl->die = client_time + 0.01; } - if ( pTemp->flags & FTENT_SMOKETRAIL ) + if( pTemp->flags & FTENT_SMOKETRAIL ) { - gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + gEngfuncs.pEfxAPI->R_RocketTrail( pTemp->entity.prevstate.origin, pTemp->entity.origin, 1 ); } - if ( pTemp->flags & FTENT_GRAVITY ) + if( pTemp->flags & FTENT_GRAVITY ) pTemp->entity.baseline.origin[2] += gravity; - else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + else if( pTemp->flags & FTENT_SLOWGRAVITY ) pTemp->entity.baseline.origin[2] += gravitySlow; - if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + if( pTemp->flags & FTENT_CLIENTCUSTOM ) { - if ( pTemp->callback ) + if( pTemp->callback ) { - ( *pTemp->callback )( pTemp, frametime, client_time ); + (*pTemp->callback)( pTemp, frametime, client_time ); } } // Cull to PVS (not frustum cull, just PVS) - if ( !(pTemp->flags & FTENT_NOMODEL ) ) + if( !( pTemp->flags & FTENT_NOMODEL ) ) { - if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + if( !Callback_AddVisibleEntity( &pTemp->entity ) ) { - if ( !(pTemp->flags & FTENT_PERSIST) ) + if( !( pTemp->flags & FTENT_PERSIST ) ) { pTemp->die = client_time; // If we can't draw it this frame, just dump it. pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die @@ -937,7 +924,6 @@ void DLLEXPORT HUD_TempEntUpdate ( } pTemp = pnext; } - finish: // Restore state info gEngfuncs.pEventAPI->EV_PopPMStates(); @@ -959,9 +945,9 @@ cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) #if defined( BEAM_TEST ) // None by default, you would return a valic pointer if you create a client side // beam and attach it to a client side entity. - if ( index > 0 && index <= 1 ) + if( index > 0 && index <= 1 ) { - return &beams[ index ]; + return &beams[index]; } else { @@ -971,4 +957,3 @@ cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) return NULL; #endif } - diff --git a/cl_dll/ev_common.cpp b/cl_dll/ev_common.cpp index e5826a49..ebba9cb2 100644 --- a/cl_dll/ev_common.cpp +++ b/cl_dll/ev_common.cpp @@ -13,6 +13,7 @@ * ****/ // shared event functions + #include "hud.h" #include "cl_util.h" #include "const.h" @@ -25,7 +26,7 @@ #include "event_api.h" #include "pm_shared.h" -#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) ) +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || ( g_iUser1 && ( gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) ) ) /* ================= GetEntity @@ -71,7 +72,7 @@ Is the entity's index in the player range? */ qboolean EV_IsPlayer( int idx ) { - if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + if( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) return true; return false; @@ -87,8 +88,8 @@ Is the entity == the local player qboolean EV_IsLocal( int idx ) { // check if we are in some way in first person spec mode - if ( IS_FIRSTPERSON_SPEC ) - return (g_iUser2 == idx); + if( IS_FIRSTPERSON_SPEC ) + return ( g_iUser2 == idx ); else return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; } @@ -110,15 +111,15 @@ void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) VectorClear( view_ofs ); view_ofs[2] = DEFAULT_VIEWHEIGHT; - if ( EV_IsPlayer( idx ) ) + if( EV_IsPlayer( idx ) ) { // in spec mode use entity viewheigh, not own - if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) + if( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) { // Grab predicted result for local player gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); } - else if ( args->ducking == 1 ) + else if( args->ducking == 1 ) { view_ofs[2] = VEC_DUCK_VIEW; } @@ -162,13 +163,13 @@ void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, VectorClear( view_ofs ); view_ofs[2] = DEFAULT_VIEWHEIGHT; - if ( EV_IsPlayer( idx ) ) + if( EV_IsPlayer( idx ) ) { - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); } - else if ( args->ducking == 1 ) + else if( args->ducking == 1 ) { view_ofs[2] = VEC_DUCK_VIEW; } @@ -177,10 +178,10 @@ void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, fR = gEngfuncs.pfnRandomFloat( 50, 70 ); fU = gEngfuncs.pfnRandomFloat( 100, 150 ); - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; - ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; } } @@ -195,11 +196,11 @@ void EV_MuzzleFlash( void ) { // Add muzzle flash to current weapon model cl_entity_t *ent = GetViewEntity(); - if ( !ent ) + if( !ent ) { return; } // Or in the muzzle flash ent->curstate.effects |= EF_MUZZLEFLASH; -} \ No newline at end of file +} diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index bd20da95..a011ae4f 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "hud.h" #include "cl_util.h" #include "const.h" @@ -37,7 +38,7 @@ extern engine_studio_api_t IEngineStudio; -static int tracerCount[ 32 ]; +static int tracerCount[32]; extern "C" char PM_FindTextureType( char *name ); @@ -48,27 +49,25 @@ extern cvar_t *cl_lw; extern "C" { - // HLDM -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); - +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); void EV_TrainPitchAdjust( struct event_args_s *args ); } @@ -100,96 +99,111 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v float fattn = ATTN_NORM; int entity; char *pTextureName; - char texname[ 64 ]; - char szbuffer[ 64 ]; + char texname[64]; + char szbuffer[64]; entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); // FIXME check if playtexture sounds movevar is set // - chTextureType = 0; // Player - if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + if( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) { // hit body chTextureType = CHAR_TEX_FLESH; } - else if ( entity == 0 ) + else if( entity == 0 ) { // get texture from entity or world (world is ent(0)) pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); - + if ( pTextureName ) { strcpy( texname, pTextureName ); pTextureName = texname; // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') + if( *pTextureName == '-' || *pTextureName == '+' ) { pTextureName += 2; } - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + if( *pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ' ) { pTextureName++; } - + // '}}' strcpy( szbuffer, pTextureName ); - szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0; - + szbuffer[CBTEXTURENAMEMAX - 1] = 0; + // get texture type - chTextureType = PM_FindTextureType( szbuffer ); + chTextureType = PM_FindTextureType( szbuffer ); } } switch (chTextureType) { default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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"; @@ -197,16 +211,18 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v break; case CHAR_TEX_GLASS: case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; + 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) + if( iBulletType == BULLET_PLAYER_CROWBAR ) return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; + fvol = 1.0; + fvolbar = 0.2; rgsz[0] = "weapons/bullet_hit1.wav"; rgsz[1] = "weapons/bullet_hit2.wav"; fattn = 1.0; @@ -215,21 +231,21 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v } // play material hit sound - gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong( 0, cnt - 1 )], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); return fvolbar; } char *EV_HLDM_DamageDecal( physent_t *pe ) { - static char decalname[ 32 ]; + static char decalname[32]; int idx; - if ( pe->classnumber == 1 ) + if( pe->classnumber == 1 ) { idx = gEngfuncs.pfnRandomLong( 0, 2 ); sprintf( decalname, "{break%i", idx + 1 ); } - else if ( pe->rendermode != kRenderNormal ) + else if( pe->rendermode != kRenderNormal ) { sprintf( decalname, "{bproof1" ); } @@ -248,28 +264,38 @@ void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); - iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); - if ( iRand < (0x7fff/2) )// not every bullet makes a sound. + iRand = gEngfuncs.pfnRandomLong( 0, 0x7FFF ); + if( iRand < ( 0x7fff / 2 ) )// not every bullet makes a sound. { - switch( iRand % 5) + switch( iRand % 5 ) { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; - case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + break; + case 2: + gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + break; + case 3: + gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + break; + case 4: + gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + break; } } pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); // Only decal brush models such as the world etc. - if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) + if( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) { - if ( CVAR_GET_FLOAT( "r_decals" ) ) + if( CVAR_GET_FLOAT( "r_decals" ) ) { - gEngfuncs.pEfxAPI->R_DecalShoot( - gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); } } @@ -281,7 +307,7 @@ void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - if ( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) + if( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) { switch( iBulletType ) { @@ -305,26 +331,26 @@ int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, flo int i; qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; - if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) + if( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq ) == 0 ) { vec3_t vecTracerSrc; - if ( player ) + if( player ) { vec3_t offset( 0, 0, -4 ); // adjust tracer position for player - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + vecTracerSrc[i] = vecSrc[i] + offset[i] + right[i] * 2 + forward[i] * 16; } } else { VectorCopy( vecSrc, vecTracerSrc ); } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal + + if( iTracerFreq != 1 ) // guns that always trace also always decal tracer = 1; switch( iBulletType ) @@ -342,7 +368,6 @@ int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, flo return tracer; } - /* ================ FireBullets @@ -356,44 +381,43 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int pmtrace_t tr; int iShot; int tracer; - - for ( iShot = 1; iShot <= cShots; iShot++ ) + + for( iShot = 1; iShot <= cShots; iShot++ ) { vec3_t vecDir, vecEnd; - float x, y, z; - //We randomize for the Shotgun. - if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) - { - do { - x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - for ( i = 0 ; i < 3; i++ ) + //We randomize for the Shotgun. + if( iBulletType == BULLET_PLAYER_BUCKSHOT ) + { + do{ + x = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 ); + y = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 ); + z = x * x + y * y; + }while( z > 1 ); + + for( i = 0 ; i < 3; i++ ) { - vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; - vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[i] + y * flSpreadY * up [i]; + vecEnd[i] = vecSrc[i] + flDistance * vecDir[i]; } }//But other guns already have their spread randomized in the synched spread. else { - - for ( i = 0 ; i < 3; i++ ) + for( i = 0 ; i < 3; i++ ) { - vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; - vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + vecDir[i] = vecDirShooting[i] + flSpreadX * right[i] + flSpreadY * up [i]; + vecEnd[i] = vecSrc[i] + flDistance * vecDir[i]; } } gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - + // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); - + // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); @@ -401,37 +425,29 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); // do damage, paint decals - if ( tr.fraction != 1.0 ) + if( tr.fraction != 1.0 ) { - switch(iBulletType) + switch( iBulletType ) { default: - case BULLET_PLAYER_9MM: - + case BULLET_PLAYER_9MM: EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); EV_HLDM_DecalGunshot( &tr, iBulletType ); - - break; - case BULLET_PLAYER_MP5: - - if ( !tracer ) + break; + case BULLET_PLAYER_MP5: + if( !tracer ) { EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); EV_HLDM_DecalGunshot( &tr, iBulletType ); } break; case BULLET_PLAYER_BUCKSHOT: - EV_HLDM_DecalGunshot( &tr, iBulletType ); - break; case BULLET_PLAYER_357: - EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); EV_HLDM_DecalGunshot( &tr, iBulletType ); - break; - } } @@ -455,7 +471,7 @@ void EV_FireGlock1( event_args_t *args ) int shell; vec3_t vecSrc, vecAiming; vec3_t up, right, forward; - + idx = args->entindex; VectorCopy( args->origin, origin ); VectorCopy( args->angles, angles ); @@ -464,9 +480,9 @@ void EV_FireGlock1( event_args_t *args ) empty = args->bparam1; AngleVectors( angles, forward, right, up ); - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/shell.mdl" );// brass shell - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { EV_MuzzleFlash(); gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); @@ -476,12 +492,12 @@ void EV_FireGlock1( event_args_t *args ) EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + EV_EjectBrass( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat( 0.92, 1.0 ), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); EV_GetGunPosition( args, vecSrc, origin ); - + VectorCopy( forward, vecAiming ); EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2 ); @@ -493,7 +509,7 @@ void EV_FireGlock2( event_args_t *args ) vec3_t origin; vec3_t angles; vec3_t velocity; - + vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; @@ -510,7 +526,7 @@ void EV_FireGlock2( event_args_t *args ) shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); @@ -521,16 +537,15 @@ void EV_FireGlock2( event_args_t *args ) EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat( 0.92, 1.0 ), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); EV_GetGunPosition( args, vecSrc, origin ); - + VectorCopy( forward, vecAiming ); - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); - + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); } //====================== // GLOCK END @@ -562,9 +577,9 @@ void EV_FireShotGunDouble( event_args_t *args ) AngleVectors( angles, forward, right, up ); - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + shell = gEngfuncs.pEventAPI->EV_FindModelIndex("models/shotgunshell.mdl");// brass shell - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); @@ -572,25 +587,25 @@ void EV_FireShotGunDouble( event_args_t *args ) V_PunchAxis( 0, -10.0 ); } - for ( j = 0; j < 2; j++ ) + for( j = 0; j < 2; j++ ) { EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + EV_EjectBrass( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); } - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat( 0.98, 1.0 ), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); EV_GetGunPosition( args, vecSrc, origin ); VectorCopy( forward, vecAiming ); - if ( gEngfuncs.GetMaxClients() > 1 ) + if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.17365, 0.04362 ); + EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.17365, 0.04362 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.08716 ); } } @@ -600,7 +615,7 @@ void EV_FireShotGunSingle( event_args_t *args ) vec3_t origin; vec3_t angles; vec3_t velocity; - + vec3_t ShellVelocity; vec3_t ShellOrigin; int shell; @@ -616,9 +631,9 @@ void EV_FireShotGunSingle( event_args_t *args ) AngleVectors( angles, forward, right, up ); - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + shell = gEngfuncs.pEventAPI->EV_FindModelIndex("models/shotgunshell.mdl");// brass shell - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); @@ -629,20 +644,20 @@ void EV_FireShotGunSingle( event_args_t *args ) EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHOTSHELL ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); EV_GetGunPosition( args, vecSrc, origin ); VectorCopy( forward, vecAiming ); - if ( gEngfuncs.GetMaxClients() > 1 ) + if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.04362 ); + EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.04362 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1], 0.08716, 0.08716 ); + EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.08716 ); } } //====================== @@ -673,20 +688,20 @@ void EV_FireMP5( event_args_t *args ) AngleVectors( angles, forward, right, up ); - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell - - if ( EV_IsLocal( idx ) ) + shell = gEngfuncs.pEventAPI->EV_FindModelIndex("models/shell.mdl");// brass shell + + if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong( 0, 2 ), 2 ); V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); } EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL ); switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) { @@ -701,13 +716,13 @@ void EV_FireMP5( event_args_t *args ) EV_GetGunPosition( args, vecSrc, origin ); VectorCopy( forward, vecAiming ); - if ( gEngfuncs.GetMaxClients() > 1 ) + if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); } } @@ -717,16 +732,16 @@ void EV_FireMP52( event_args_t *args ) { int idx; vec3_t origin; - + idx = args->entindex; VectorCopy( args->origin, origin ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 ); V_PunchAxis( 0, -10 ); } - + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) { case 0: @@ -763,7 +778,7 @@ void EV_FirePython( event_args_t *args ) AngleVectors( angles, forward, right, up ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { // Python uses different body in multiplayer versus single player int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; @@ -778,15 +793,15 @@ void EV_FirePython( event_args_t *args ) switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) { case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat( 0.8, 0.9 ), ATTN_NORM, 0, PITCH_NORM ); break; case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat( 0.8, 0.9 ), ATTN_NORM, 0, PITCH_NORM ); break; } EV_GetGunPosition( args, vecSrc, origin ); - + VectorCopy( forward, vecAiming ); EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); @@ -799,7 +814,7 @@ void EV_FirePython( event_args_t *args ) //====================== // GAUSS START //====================== -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch +#define SND_CHANGE_PITCH (1 << 7) // duplicated in protocol.h change sound pitch void EV_SpinGauss( event_args_t *args ) { @@ -854,10 +869,10 @@ void EV_FireGauss( event_args_t *args ) edict_t *pentIgnore; pmtrace_t tr, beam_tr; float flMaxFrac = 1.0; - int nTotal = 0; + int nTotal = 0; int fHasPunched = 0; int fFirstBeam = 1; - int nMaxHits = 10; + int nMaxHits = 10; physent_t *pEntity; int m_iBeam, m_iGlow, m_iBalls; vec3_t up, right, forward; @@ -867,35 +882,34 @@ void EV_FireGauss( event_args_t *args ) VectorCopy( args->angles, angles ); VectorCopy( args->velocity, velocity ); - if ( args->bparam2 ) + if( args->bparam2 ) { EV_StopPreviousGauss( idx ); return; } -// Con_Printf( "Firing gauss with %f\n", flDamage ); + //Con_Printf( "Firing gauss with %f\n", flDamage ); EV_GetGunPosition( args, vecSrc, origin ); m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); - + AngleVectors( angles, forward, right, up ); VectorMA( vecSrc, 8192, forward, vecDest ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { V_PunchAxis( 0, -2.0 ); gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); - if ( m_fPrimaryFire == false ) - g_flApplyVel = flDamage; - + if( m_fPrimaryFire == false ) + g_flApplyVel = flDamage; } - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * ( 1.0 / 400.0 ), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - while (flDamage > 10 && nMaxHits > 0) + while( flDamage > 10 && nMaxHits > 0 ) { nMaxHits--; @@ -905,19 +919,19 @@ void EV_FireGauss( event_args_t *args ) gEngfuncs.pEventAPI->EV_PushPMStates(); // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); gEngfuncs.pEventAPI->EV_PopPMStates(); - if ( tr.allsolid ) + if( tr.allsolid ) break; - if (fFirstBeam) + if( fFirstBeam ) { - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); @@ -959,10 +973,10 @@ void EV_FireGauss( event_args_t *args ) } pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); - if ( pEntity == NULL ) + if( pEntity == NULL ) break; - if ( pEntity->solid == SOLID_BSP ) + if( pEntity->solid == SOLID_BSP ) { float n; @@ -970,16 +984,16 @@ void EV_FireGauss( event_args_t *args ) n = -DotProduct( tr.plane.normal, forward ); - if (n < 0.5) // 60 degrees + if( n < 0.5 ) // 60 degrees { // ALERT( at_console, "reflect %f\n", n ); // reflect vec3_t r; - + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); flMaxFrac = flMaxFrac - tr.fraction; - + VectorCopy( r, forward ); VectorMA( tr.endpos, 8.0, forward, vecSrc ); @@ -994,13 +1008,12 @@ void EV_FireGauss( event_args_t *args ) 255, 100 ); // lose energy - if ( n == 0 ) + if( n == 0 ) { n = 0.1; } - - flDamage = flDamage * (1 - n); + flDamage = flDamage * ( 1 - n ); } else { @@ -1010,14 +1023,14 @@ void EV_FireGauss( event_args_t *args ) gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); // limit it to one hole punch - if (fHasPunched) + if( fHasPunched ) { break; } fHasPunched = 1; // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) + if( !m_fPrimaryFire ) { vec3_t start; @@ -1025,29 +1038,28 @@ void EV_FireGauss( event_args_t *args ) // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); - + // Now add in all of the players. gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); - if ( !beam_tr.allsolid ) + if( !beam_tr.allsolid ) { vec3_t delta; float n; // trace backwards to find exit point - gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); VectorSubtract( beam_tr.endpos, tr.endpos, delta ); - + n = Length( delta ); - if (n < flDamage) + if(n < flDamage) { - if (n == 0) + if(n == 0) n = 1; flDamage -= n; @@ -1060,20 +1072,20 @@ void EV_FireGauss( event_args_t *args ) } //////////////////////////////////// WHAT TO DO HERE - // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + // CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); - + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); - + // balls { vec3_t fwd; VectorSubtract( beam_tr.endpos, forward, fwd ); - gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)( flDamage * 0.3 ), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, 255, 40 ); } - + VectorAdd( beam_tr.endpos, forward, vecSrc ); } } @@ -1086,12 +1098,11 @@ void EV_FireGauss( event_args_t *args ) } else { - if ( m_fPrimaryFire ) + if( m_fPrimaryFire ) { // slug doesn't punch through ever with primary // fire, so leave a little glowy bit and make some balls gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); - { vec3_t fwd; VectorAdd( tr.endpos, tr.plane.normal, fwd ); @@ -1117,8 +1128,8 @@ void EV_FireGauss( event_args_t *args ) //====================== // CROWBAR START //====================== - -enum crowbar_e { +enum crowbar_e +{ CROWBAR_IDLE = 0, CROWBAR_DRAW, CROWBAR_HOLSTER, @@ -1145,20 +1156,23 @@ void EV_Crowbar( event_args_t *args ) VectorCopy( args->origin, origin ); //Play Swing sound - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); switch( (g_iSwing++) % 3 ) { case 0: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK1MISS, 1 ); break; + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); + break; case 1: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK2MISS, 1 ); break; + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK2MISS, 1 ); + break; case 2: - gEngfuncs.pEventAPI->EV_WeaponAnimation ( CROWBAR_ATTACK3MISS, 1 ); break; + gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK3MISS, 1 ); + break; } } } @@ -1169,7 +1183,8 @@ void EV_Crowbar( event_args_t *args ) //====================== // CROSSBOW START //====================== -enum crossbow_e { +enum crossbow_e +{ CROSSBOW_IDLE1 = 0, // full CROSSBOW_IDLE2, // empty CROSSBOW_FIDGET1, // full @@ -1189,7 +1204,7 @@ enum crossbow_e { // This function is used to correct the origin and angles // of the bolt, so it looks like it's stuck on the wall. //===================== -void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) +void EV_BoltCallback( struct tempent_s *ent, float frametime, float currenttime ) { ent->entity.origin = ent->entity.baseline.vuser1; ent->entity.angles = ent->entity.baseline.vuser2; @@ -1211,21 +1226,21 @@ void EV_FireCrossbow2( event_args_t *args ) VectorCopy( args->angles, angles ); VectorCopy( args->velocity, velocity ); - + AngleVectors( angles, forward, right, up ); EV_GetGunPosition( args, vecSrc, origin ); VectorMA( vecSrc, 8192, forward, vecEnd ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { - if ( args->iparam1 ) + if( args->iparam1 ) gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); - else if ( args->iparam2 ) + else if( args->iparam2 ) gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); } @@ -1236,30 +1251,32 @@ void EV_FireCrossbow2( event_args_t *args ) gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - + //We hit something - if ( tr.fraction < 1.0 ) + if( tr.fraction < 1.0 ) { physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); //Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ). - if ( pe->solid != SOLID_BSP ) + if( pe->solid != SOLID_BSP ) { - switch( gEngfuncs.pfnRandomLong(0,1) ) + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) { case 0: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; case 1: - gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; + gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; } } //Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though. - else if ( pe->rendermode == kRenderNormal ) + else if( pe->rendermode == kRenderNormal ) { - gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, PITCH_NORM ); - + gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, PITCH_NORM ); + //Not underwater, do some sparks... - if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) + if( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER ) gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); vec3_t vBoltAngles; @@ -1267,9 +1284,9 @@ void EV_FireCrossbow2( event_args_t *args ) VectorAngles( forward, vBoltAngles ); - TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); - - if ( bolt ) + TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0 ), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); + + if( bolt ) { bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function. bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit @@ -1290,14 +1307,14 @@ void EV_FireCrossbow( event_args_t *args ) idx = args->entindex; VectorCopy( args->origin, origin ); - - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) ); //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { - if ( args->iparam1 ) + if( args->iparam1 ) gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 ); else if ( args->iparam2 ) gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 ); @@ -1312,7 +1329,8 @@ void EV_FireCrossbow( event_args_t *args ) //====================== // RPG START //====================== -enum rpg_e { +enum rpg_e +{ RPG_IDLE = 0, RPG_FIDGET, RPG_RELOAD, // to reload @@ -1332,15 +1350,15 @@ void EV_FireRpg( event_args_t *args ) idx = args->entindex; VectorCopy( args->origin, origin ); - + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 ); - + V_PunchAxis( 0, -5.0 ); } } @@ -1351,7 +1369,8 @@ void EV_FireRpg( event_args_t *args ) //====================== // EGON END //====================== -enum egon_e { +enum egon_e +{ EGON_IDLE1 = 0, EGON_FIDGET1, EGON_ALTFIREON, @@ -1368,8 +1387,17 @@ enum egon_e { int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; -enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; -enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; +enum EGON_FIRESTATE +{ + FIRE_OFF, + FIRE_CHARGE +}; + +enum EGON_FIREMODE +{ + FIRE_NARROW, + FIRE_WIDE +}; #define EGON_PRIMARY_VOLUME 450 #define EGON_BEAM_SPRITE "sprites/xbeam1.spr" @@ -1378,7 +1406,7 @@ enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; #define EGON_SOUND_RUN "weapons/egon_run3.wav" #define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" -#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) +#define ARRAYSIZE(p) ( sizeof(p) /sizeof(p[0]) ) BEAM *pBeam; BEAM *pBeam2; @@ -1394,50 +1422,49 @@ void EV_EgonFire( event_args_t *args ) iFireMode = args->iparam2; int iStartup = args->bparam1; - - if ( iStartup ) + if( iStartup ) { - if ( iFireMode == FIRE_WIDE ) + if( iFireMode == FIRE_WIDE ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); else gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); } else { - if ( iFireMode == FIRE_WIDE ) + if( iFireMode == FIRE_WIDE ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); else gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); } //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); + if( EV_IsLocal( idx ) ) + gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[gEngfuncs.pfnRandomLong( 0, 3 )], 1 ); - if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. + if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. { vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; pmtrace_t tr; cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); - if ( pl ) + if( pl ) { VectorCopy( gHUD.m_vecAngles, angles ); - + AngleVectors( angles, forward, right, up ); EV_GetGunPosition( args, vecSrc, pl->origin ); VectorMA( vecSrc, 2048, forward, vecEnd ); - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); - + // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); @@ -1450,19 +1477,18 @@ void EV_EgonFire( event_args_t *args ) float g = 50.0f; float b = 125.0f; - if ( IEngineStudio.IsHardware() ) + if( IEngineStudio.IsHardware() ) { r /= 100.0f; g /= 100.0f; } - - - pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); - if ( pBeam ) + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); + + if( pBeam ) pBeam->flags |= ( FBEAM_SINENOISE ); - - pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); } } } @@ -1473,23 +1499,22 @@ void EV_EgonStop( event_args_t *args ) vec3_t origin; idx = args->entindex; - VectorCopy ( args->origin, origin ); + VectorCopy( args->origin, origin ); gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); - - if ( args->iparam1 ) + + if( args->iparam1 ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 ); - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { - if ( pBeam ) + if( pBeam ) { pBeam->die = 0.0; pBeam = NULL; } - - - if ( pBeam2 ) + + if( pBeam2 ) { pBeam2->die = 0.0; pBeam2 = NULL; @@ -1503,7 +1528,8 @@ void EV_EgonStop( event_args_t *args ) //====================== // HORNET START //====================== -enum hgun_e { +enum hgun_e +{ HGUN_IDLE1 = 0, HGUN_FIDGETSWAY, HGUN_FIDGETSHAKE, @@ -1523,17 +1549,23 @@ void EV_HornetGunFire( event_args_t *args ) iFireMode = args->iparam1; //Only play the weapon anims if I shot it. - if ( EV_IsLocal( idx ) ) + if( EV_IsLocal( idx ) ) { - V_PunchAxis( 0, gEngfuncs.pfnRandomLong ( 0, 2 ) ); - gEngfuncs.pEventAPI->EV_WeaponAnimation ( HGUN_SHOOT, 1 ); + V_PunchAxis( 0, gEngfuncs.pfnRandomLong( 0, 2 ) ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( HGUN_SHOOT, 1 ); } - switch ( gEngfuncs.pfnRandomLong ( 0 , 2 ) ) + switch( gEngfuncs.pfnRandomLong( 0 , 2 ) ) { - case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); break; - case 1: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); break; - case 2: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); break; + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 ); + break; + case 2: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 ); + break; } } //====================== @@ -1543,7 +1575,8 @@ void EV_HornetGunFire( event_args_t *args ) //====================== // TRIPMINE START //====================== -enum tripmine_e { +enum tripmine_e +{ TRIPMINE_IDLE1 = 0, TRIPMINE_IDLE2, TRIPMINE_ARM1, @@ -1567,9 +1600,9 @@ void EV_TripmineFire( event_args_t *args ) VectorCopy( args->origin, vecSrc ); VectorCopy( args->angles, angles ); - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) + AngleVectors( angles, forward, NULL, NULL ); + + if( !EV_IsLocal ( idx ) ) return; // Grab predicted result for local player @@ -1586,7 +1619,7 @@ void EV_TripmineFire( event_args_t *args ) gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); //Hit something solid - if ( tr.fraction < 1.0 ) + if( tr.fraction < 1.0 ) gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); gEngfuncs.pEventAPI->EV_PopPMStates(); @@ -1598,7 +1631,8 @@ void EV_TripmineFire( event_args_t *args ) //====================== // SQUEAK START //====================== -enum squeak_e { +enum squeak_e +{ SQUEAK_IDLE1 = 0, SQUEAK_FIDGETFIT, SQUEAK_FIDGETNIP, @@ -1607,8 +1641,8 @@ enum squeak_e { SQUEAK_THROW }; -#define VEC_HULL_MIN Vector(-16, -16, -36) -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) +#define VEC_HULL_MIN Vector( -16, -16, -36 ) +#define VEC_DUCK_HULL_MIN Vector( -16, -16, -18 ) void EV_SnarkFire( event_args_t *args ) { @@ -1620,26 +1654,26 @@ void EV_SnarkFire( event_args_t *args ) VectorCopy( args->origin, vecSrc ); VectorCopy( args->angles, angles ); - AngleVectors ( angles, forward, NULL, NULL ); - - if ( !EV_IsLocal ( idx ) ) + AngleVectors( angles, forward, NULL, NULL ); + + if( !EV_IsLocal ( idx ) ) return; - - if ( args->ducking ) + + if( args->ducking ) vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - + // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr ); //Find space to drop the thing. - if ( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( SQUEAK_THROW, 0 ); - + if( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 ) + gEngfuncs.pEventAPI->EV_WeaponAnimation( SQUEAK_THROW, 0 ); + gEngfuncs.pEventAPI->EV_PopPMStates(); } //====================== @@ -1656,35 +1690,47 @@ void EV_TrainPitchAdjust( event_args_t *args ) float m_flVolume; int pitch; int stop; - - char sz[ 256 ]; + + char sz[256]; idx = args->entindex; - + VectorCopy( args->origin, origin ); us_params = (unsigned short)args->iparam1; - stop = args->bparam1; + stop = args->bparam1; - m_flVolume = (float)(us_params & 0x003f)/40.0; - noise = (int)(((us_params) >> 12 ) & 0x0007); - pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); + m_flVolume = (float)( us_params & 0x003f ) / 40.0; + noise = (int)( ( ( us_params ) >> 12 ) & 0x0007 ); + pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); - switch ( noise ) + switch( noise ) { - case 1: strcpy( sz, "plats/ttrain1.wav"); break; - case 2: strcpy( sz, "plats/ttrain2.wav"); break; - case 3: strcpy( sz, "plats/ttrain3.wav"); break; - case 4: strcpy( sz, "plats/ttrain4.wav"); break; - case 5: strcpy( sz, "plats/ttrain6.wav"); break; - case 6: strcpy( sz, "plats/ttrain7.wav"); break; + case 1: + strcpy( sz, "plats/ttrain1.wav" ); + break; + case 2: + strcpy( sz, "plats/ttrain2.wav" ); + break; + case 3: + strcpy( sz, "plats/ttrain3.wav" ); + break; + case 4: + strcpy( sz, "plats/ttrain4.wav"); + break; + case 5: + strcpy( sz, "plats/ttrain6.wav"); + break; + case 6: + strcpy( sz, "plats/ttrain7.wav"); + break; default: // no sound strcpy( sz, "" ); return; } - if ( stop ) + if( stop ) { gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); } diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h index 57c99216..bff43b1e 100644 --- a/cl_dll/ev_hldm.h +++ b/cl_dll/ev_hldm.h @@ -21,9 +21,10 @@ typedef enum BULLET_MONSTER_9MM, BULLET_MONSTER_MP5, BULLET_MONSTER_12MM -} Bullet; +}Bullet; -enum glock_e { +enum glock_e +{ GLOCK_IDLE1 = 0, GLOCK_IDLE2, GLOCK_IDLE3, @@ -36,7 +37,8 @@ enum glock_e { GLOCK_ADD_SILENCER }; -enum shotgun_e { +enum shotgun_e +{ SHOTGUN_IDLE = 0, SHOTGUN_FIRE, SHOTGUN_FIRE2, @@ -61,7 +63,8 @@ enum mp5_e MP5_FIRE3 }; -enum python_e { +enum python_e +{ PYTHON_IDLE1 = 0, PYTHON_FIDGET, PYTHON_FIRE1, @@ -75,7 +78,8 @@ enum python_e { #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 { +enum gauss_e +{ GAUSS_IDLE = 0, GAUSS_IDLE2, GAUSS_FIDGET, @@ -91,5 +95,4 @@ void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); - #endif // EV_HLDMH diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h index 5c4677a2..c052805d 100644 --- a/cl_dll/eventscripts.h +++ b/cl_dll/eventscripts.h @@ -55,8 +55,8 @@ #define DMG_AIMED (1 << 28) // Does Hit location damage #define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls -#define DMG_CALTROP (1<<30) -#define DMG_HALLUC (1<<31) +#define DMG_CALTROP (1 << 30) +#define DMG_HALLUC (1 << 31) // Some of these are HL/TFC specific? void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index ac011a5c..8b8a8d0e 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -25,76 +25,71 @@ #include #include - - -DECLARE_MESSAGE(m_Flash, FlashBat) -DECLARE_MESSAGE(m_Flash, Flashlight) +DECLARE_MESSAGE( m_Flash, FlashBat ) +DECLARE_MESSAGE( m_Flash, Flashlight ) #define BAT_NAME "sprites/%d_Flashlight.spr" -int CHudFlashlight::Init(void) +int CHudFlashlight::Init( void ) { m_fFade = 0; m_fOn = 0; - HOOK_MESSAGE(Flashlight); - HOOK_MESSAGE(FlashBat); + HOOK_MESSAGE( Flashlight ); + HOOK_MESSAGE( FlashBat ); m_iFlags |= HUD_ACTIVE; - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); return 1; } -void CHudFlashlight::Reset(void) +void CHudFlashlight::Reset( void ) { m_fFade = 0; m_fOn = 0; } -int CHudFlashlight::VidInit(void) +int CHudFlashlight::VidInit( void ) { int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); - m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); - m_hSprite2 = gHUD.GetSprite(HUD_flash_full); - m_hBeam = gHUD.GetSprite(HUD_flash_beam); - m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); - m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); + m_hSprite1 = gHUD.GetSprite( HUD_flash_empty ); + m_hSprite2 = gHUD.GetSprite( HUD_flash_full ); + m_hBeam = gHUD.GetSprite( HUD_flash_beam ); + m_prc1 = &gHUD.GetSpriteRect( HUD_flash_empty ); + m_prc2 = &gHUD.GetSpriteRect( HUD_flash_full ); m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); m_iWidth = m_prc2->right - m_prc2->left; return 1; } -int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) +int CHudFlashlight::MsgFunc_FlashBat( const char *pszName, int iSize, void *pbuf ) { - - BEGIN_READ( pbuf, iSize ); int x = READ_BYTE(); m_iBat = x; - m_flBat = ((float)x)/100.0; + m_flBat = ( (float)x ) / 100.0; return 1; } -int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) +int CHudFlashlight::MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pbuf, iSize ); m_fOn = READ_BYTE(); int x = READ_BYTE(); m_iBat = x; - m_flBat = ((float)x)/100.0; + m_flBat = ( (float)x ) / 100.0; return 1; } -int CHudFlashlight::Draw(float flTime) +int CHudFlashlight::Draw( float flTime ) { static bool show = ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ); if( show != !( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) ) @@ -105,54 +100,54 @@ int CHudFlashlight::Draw(float flTime) gMobileEngfuncs->pfnTouchHideButtons( "flashlight", !show ); } } - if ( !show ) + if( !show ) return 1; int r, g, b, x, y, a; wrect_t rc; - if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + if( !( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) ) return 1; - if (m_fOn) + if( m_fOn ) a = 225; else a = MIN_ALPHA; - if (m_flBat < 0.20) - UnpackRGB(r,g,b, RGB_REDISH); + if( m_flBat < 0.20 ) + UnpackRGB( r,g,b, RGB_REDISH ); else - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r,g,b, RGB_YELLOWISH ); - ScaleColors(r, g, b, a); + ScaleColors( r, g, b, a ); - y = (m_prc1->bottom - m_prc2->top)/2; - x = ScreenWidth - m_iWidth - m_iWidth/2 ; + y = ( m_prc1->bottom - m_prc2->top ) / 2; + x = ScreenWidth - m_iWidth - m_iWidth / 2 ; // Draw the flashlight casing - SPR_Set(m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prc1); + SPR_Set( m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prc1 ); - if ( m_fOn ) - { // draw the flashlight beam - x = ScreenWidth - m_iWidth/2; + if( m_fOn ) + { + // draw the flashlight beam + x = ScreenWidth - m_iWidth / 2; SPR_Set( m_hBeam, r, g, b ); SPR_DrawAdditive( 0, x, y, m_prcBeam ); } // draw the flashlight energy level - x = ScreenWidth - m_iWidth - m_iWidth/2 ; - int iOffset = m_iWidth * (1.0 - m_flBat); - if (iOffset < m_iWidth) + x = ScreenWidth - m_iWidth - m_iWidth / 2; + int iOffset = m_iWidth * ( 1.0 - m_flBat ); + if( iOffset < m_iWidth ) { rc = *m_prc2; rc.left += iOffset; - SPR_Set(m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x + iOffset, y, &rc); + SPR_Set( m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x + iOffset, y, &rc ); } - return 1; } diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 4e5e5991..7ccaf1d3 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -26,28 +26,28 @@ #include "parsemsg.h" -DECLARE_MESSAGE(m_Geiger, Geiger ) +DECLARE_MESSAGE( m_Geiger, Geiger ) -int CHudGeiger::Init(void) +int CHudGeiger::Init( void ) { HOOK_MESSAGE( Geiger ); m_iGeigerRange = 0; m_iFlags = 0; - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); srand( (unsigned)time( NULL ) ); return 1; } -int CHudGeiger::VidInit(void) +int CHudGeiger::VidInit( void ) { return 1; } -int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) +int CHudGeiger::MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -55,101 +55,101 @@ int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) // update geiger data m_iGeigerRange = READ_BYTE(); m_iGeigerRange = m_iGeigerRange << 2; - + m_iFlags |= HUD_ACTIVE; return 1; } -int CHudGeiger::Draw (float flTime) +int CHudGeiger::Draw( float flTime ) { int pct; float flvol = 0.0f; int rg[3]; int i; - - if (m_iGeigerRange < 1000 && m_iGeigerRange > 0) + + if( m_iGeigerRange < 1000 && m_iGeigerRange > 0 ) { // peicewise linear is better than continuous formula for this - if (m_iGeigerRange > 800) + if( m_iGeigerRange > 800 ) { - pct = 0; //Con_Printf ( "range > 800\n"); + pct = 0; //Con_Printf( "range > 800\n" ); } - else if (m_iGeigerRange > 600) + else if( m_iGeigerRange > 600 ) { pct = 2; - flvol = 0.4; //Con_Printf ( "range > 600\n"); + flvol = 0.4; //Con_Printf( "range > 600\n" ); rg[0] = 1; rg[1] = 1; i = 2; } - else if (m_iGeigerRange > 500) + else if( m_iGeigerRange > 500 ) { pct = 4; - flvol = 0.5; //Con_Printf ( "range > 500\n"); + flvol = 0.5; //Con_Printf( "range > 500\n" ); rg[0] = 1; rg[1] = 2; i = 2; } - else if (m_iGeigerRange > 400) + else if( m_iGeigerRange > 400 ) { pct = 8; - flvol = 0.6; //Con_Printf ( "range > 400\n"); + flvol = 0.6; //Con_Printf( "range > 400\n" ); rg[0] = 1; rg[1] = 2; rg[2] = 3; i = 3; } - else if (m_iGeigerRange > 300) + else if( m_iGeigerRange > 300 ) { pct = 8; - flvol = 0.7; //Con_Printf ( "range > 300\n"); + flvol = 0.7; //Con_Printf( "range > 300\n" ); rg[0] = 2; rg[1] = 3; rg[2] = 4; i = 3; } - else if (m_iGeigerRange > 200) + else if( m_iGeigerRange > 200 ) { pct = 28; - flvol = 0.78; //Con_Printf ( "range > 200\n"); + flvol = 0.78; //Con_Printf( "range > 200\n" ); rg[0] = 2; rg[1] = 3; rg[2] = 4; i = 3; } - else if (m_iGeigerRange > 150) + else if( m_iGeigerRange > 150 ) { pct = 40; - flvol = 0.80; //Con_Printf ( "range > 150\n"); + flvol = 0.80; //Con_Printf( "range > 150\n" ); rg[0] = 3; rg[1] = 4; rg[2] = 5; i = 3; } - else if (m_iGeigerRange > 100) + else if( m_iGeigerRange > 100 ) { pct = 60; - flvol = 0.85; //Con_Printf ( "range > 100\n"); + flvol = 0.85; //Con_Printf( "range > 100\n" ); rg[0] = 3; rg[1] = 4; rg[2] = 5; i = 3; } - else if (m_iGeigerRange > 75) + else if( m_iGeigerRange > 75 ) { pct = 80; - flvol = 0.9; //Con_Printf ( "range > 75\n"); + flvol = 0.9; //Con_Printf( "range > 75\n" ); //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; rg[0] = 4; rg[1] = 5; rg[2] = 6; i = 3; } - else if (m_iGeigerRange > 50) + else if( m_iGeigerRange > 50 ) { pct = 90; - flvol = 0.95; //Con_Printf ( "range > 50\n"); + flvol = 0.95; //Con_Printf( "range > 50\n" ); rg[0] = 5; rg[1] = 6; i = 2; @@ -157,26 +157,25 @@ int CHudGeiger::Draw (float flTime) else { pct = 95; - flvol = 1.0; //Con_Printf ( "range < 50\n"); + flvol = 1.0; //Con_Printf( "range < 50\n" ); rg[0] = 5; rg[1] = 6; i = 2; } - flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); + flvol = ( flvol * ( (rand() & 127) ) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); - if ((rand() & 127) < pct || (rand() & 127) < pct) + if( ( rand() & 127 ) < pct || ( rand() & 127 ) < pct ) { - //S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100); + //S_StartDynamicSound( -1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100 ); char sz[256]; - + int j = rand() & 1; - if (i > 2) + if( i > 2 ) j += rand() & 1; - sprintf(sz, "player/geiger%d.wav", j + 1); - PlaySound(sz, flvol); - + sprintf( sz, "player/geiger%d.wav", j + 1 ); + PlaySound( sz, flvol ); } } diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index c73b0f5c..4a567665 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -29,15 +29,15 @@ #include "mobility_int.h" -DECLARE_MESSAGE(m_Health, Health ) -DECLARE_MESSAGE(m_Health, Damage ) +DECLARE_MESSAGE( m_Health, Health ) +DECLARE_MESSAGE( m_Health, Damage ) #define PAIN_NAME "sprites/%d_pain.spr" #define DAMAGE_NAME "sprites/%d_dmg.spr" int giDmgHeight, giDmgWidth; -int giDmgFlags[NUM_DMG_TYPES] = +int giDmgFlags[NUM_DMG_TYPES] = { DMG_POISON, DMG_ACID, @@ -53,10 +53,10 @@ int giDmgFlags[NUM_DMG_TYPES] = DMG_HALLUC }; -int CHudHealth::Init(void) +int CHudHealth::Init( void ) { - HOOK_MESSAGE(Health); - HOOK_MESSAGE(Damage); + HOOK_MESSAGE( Health ); + HOOK_MESSAGE( Damage ); m_iHealth = 100; m_fFade = 0; m_iFlags = 0; @@ -65,10 +65,9 @@ int CHudHealth::Init(void) giDmgHeight = 0; giDmgWidth = 0; - memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); + memset( m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES ); - - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); return 1; } @@ -77,28 +76,28 @@ void CHudHealth::Reset( void ) // make sure the pain compass is cleared when the player respawns m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - // force all the flashing damage icons to expire m_bitsDamage = 0; - for ( int i = 0; i < NUM_DMG_TYPES; i++ ) + for( int i = 0; i < NUM_DMG_TYPES; i++ ) { m_dmg[i].fExpire = 0; } } -int CHudHealth::VidInit(void) +int CHudHealth::VidInit( void ) { m_hSprite = 0; m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); - giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; - giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; + giDmgHeight = gHUD.GetSpriteRect( m_HUD_dmg_bio ).right - gHUD.GetSpriteRect( m_HUD_dmg_bio ).left; + giDmgWidth = gHUD.GetSpriteRect( m_HUD_dmg_bio ).bottom - gHUD.GetSpriteRect( m_HUD_dmg_bio ).top; + return 1; } -int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) +int CHudHealth::MsgFunc_Health( const char *pszName, int iSize, void *pbuf ) { // TODO: update local health data BEGIN_READ( pbuf, iSize ); @@ -107,7 +106,7 @@ int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) m_iFlags |= HUD_ACTIVE; // Only update the fade if we've changed health - if (x != m_iHealth) + if( x != m_iHealth ) { m_fFade = FADE_TIME; m_iHealth = x; @@ -116,8 +115,7 @@ int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) return 1; } - -int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +int CHudHealth::MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -127,47 +125,47 @@ int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) vec3_t vecFrom; - for ( int i = 0 ; i < 3 ; i++) + for ( int i = 0; i < 3; i++ ) vecFrom[i] = READ_COORD(); - UpdateTiles(gHUD.m_flTime, bitsDamage); + UpdateTiles( gHUD.m_flTime, bitsDamage ); // Actually took damage? - if ( damageTaken > 0 || armor > 0 ) + if( damageTaken > 0 || armor > 0 ) { - CalcDamageDirection(vecFrom); + CalcDamageDirection( vecFrom ); if( gMobileEngfuncs && damageTaken > 0 ) { - float time = damageTaken * 4.0f; + float time = damageTaken * 4.0f; - if( time > 200.0f ) time = 200.0f; - gMobileEngfuncs->pfnVibrate( time, 0 ); + if( time > 200.0f ) + time = 200.0f; + gMobileEngfuncs->pfnVibrate( time, 0 ); } } return 1; } - // Returns back a color from the // Green <-> Yellow <-> Red ramp void CHudHealth::GetPainColor( int &r, int &g, int &b ) { int iHealth = m_iHealth; - if (iHealth > 25) + if( iHealth > 25 ) iHealth -= 25; - else if ( iHealth < 0 ) + else if( iHealth < 0 ) iHealth = 0; #if 0 g = iHealth * 255 / 100; r = 255 - g; b = 0; #else - if (m_iHealth > 25) + if( m_iHealth > 25 ) { - UnpackRGB(r,g,b, RGB_YELLOWISH); + UnpackRGB( r, g, b, RGB_YELLOWISH ); } else { @@ -175,135 +173,131 @@ void CHudHealth::GetPainColor( int &r, int &g, int &b ) g = 0; b = 0; } -#endif +#endif } -int CHudHealth::Draw(float flTime) +int CHudHealth::Draw( float flTime ) { int r, g, b; int a = 0, x, y; int HealthWidth; - if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) + if( ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) || gEngfuncs.IsSpectateOnly() ) return 1; - if ( !m_hSprite ) - m_hSprite = LoadSprite(PAIN_NAME); - + if( !m_hSprite ) + m_hSprite = LoadSprite( PAIN_NAME ); + // Has health changed? Flash the health # - if (m_fFade) + if( m_fFade ) { - m_fFade -= (gHUD.m_flTimeDelta * 20); - if (m_fFade <= 0) + m_fFade -= ( gHUD.m_flTimeDelta * 20 ); + if( m_fFade <= 0 ) { a = MIN_ALPHA; m_fFade = 0; } // Fade the health number back to dim - - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - + a = MIN_ALPHA + ( m_fFade / FADE_TIME ) * 128; } else a = MIN_ALPHA; // If health is getting low, make it bright red - if (m_iHealth <= 15) + if( m_iHealth <= 15 ) a = 255; - + GetPainColor( r, g, b ); - ScaleColors(r, g, b, a ); + ScaleColors( r, g, b, a ); // Only draw health if we have the suit. - if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) + if( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) { - HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; + HealthWidth = gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).right - gHUD.GetSpriteRect( gHUD.m_HUD_number_0 ).left; + int CrossWidth = gHUD.GetSpriteRect( m_HUD_cross ).right - gHUD.GetSpriteRect( m_HUD_cross ).left; y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = CrossWidth /2; + x = CrossWidth / 2; - SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); - SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); + SPR_Set( gHUD.GetSprite( m_HUD_cross ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_cross ) ); x = CrossWidth + HealthWidth / 2; - x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b ); - x += HealthWidth/2; + x += HealthWidth / 2; int iHeight = gHUD.m_iFontHeight; - int iWidth = HealthWidth/10; - FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); + int iWidth = HealthWidth / 10; + FillRGBA( x, y, iWidth, iHeight, 255, 160, 0, a ); } - DrawDamage(flTime); - return DrawPain(flTime); + DrawDamage( flTime ); + return DrawPain( flTime ); } -void CHudHealth::CalcDamageDirection(vec3_t vecFrom) +void CHudHealth::CalcDamageDirection( vec3_t vecFrom ) { vec3_t forward, right, up; float side, front; vec3_t vecOrigin, vecAngles; - if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) + if( !vecFrom[0] && !vecFrom[1] && !vecFrom[2] ) { m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; return; } + memcpy( vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t) ); + memcpy( vecAngles, gHUD.m_vecAngles, sizeof(vec3_t) ); - memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); - memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); - - - VectorSubtract (vecFrom, vecOrigin, vecFrom); + VectorSubtract( vecFrom, vecOrigin, vecFrom ); float flDistToTarget = vecFrom.Length(); vecFrom = vecFrom.Normalize(); - AngleVectors (vecAngles, forward, right, up); + AngleVectors( vecAngles, forward, right, up ); - front = DotProduct (vecFrom, right); - side = DotProduct (vecFrom, forward); + front = DotProduct( vecFrom, right ); + side = DotProduct( vecFrom, forward ); - if (flDistToTarget <= 50) + if( flDistToTarget <= 50 ) { m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; } else { - if (side > 0) + if( side > 0 ) { - if (side > 0.3) - m_fAttackFront = max(m_fAttackFront, side); + if( side > 0.3 ) + m_fAttackFront = max( m_fAttackFront, side ); } else { - float f = fabs(side); - if (f > 0.3) - m_fAttackRear = max(m_fAttackRear, f); + float f = fabs( side ); + if( f > 0.3 ) + m_fAttackRear = max( m_fAttackRear, f ); } - if (front > 0) + if( front > 0 ) { - if (front > 0.3) - m_fAttackRight = max(m_fAttackRight, front); + if( front > 0.3 ) + m_fAttackRight = max( m_fAttackRight, front ); } else { - float f = fabs(front); - if (f > 0.3) - m_fAttackLeft = max(m_fAttackLeft, f); + float f = fabs( front ); + if( f > 0.3 ) + m_fAttackLeft = max( m_fAttackLeft, f ); } } } -int CHudHealth::DrawPain(float flTime) +int CHudHealth::DrawPain( float flTime ) { - if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) + if( !( m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight) ) return 1; int r, g, b; @@ -313,60 +307,62 @@ int CHudHealth::DrawPain(float flTime) a = 255; // max brightness until then float fFade = gHUD.m_flTimeDelta * 2; - - // SPR_Draw top - if (m_fAttackFront > 0.4) - { - GetPainColor(r,g,b); - shade = a * max( m_fAttackFront, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; - y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; - SPR_DrawAdditive(0, x, y, NULL); + // SPR_Draw top + if( m_fAttackFront > 0.4 ) + { + GetPainColor( r, g, b ); + shade = a * max( m_fAttackFront, 0.5 ); + ScaleColors( r, g, b, shade ); + SPR_Set( m_hSprite, r, g, b ); + + x = ScreenWidth / 2 - SPR_Width( m_hSprite, 0 ) / 2; + y = ScreenHeight / 2 - SPR_Height( m_hSprite, 0 ) * 3; + SPR_DrawAdditive( 0, x, y, NULL ); m_fAttackFront = max( 0, m_fAttackFront - fFade ); } else m_fAttackFront = 0; - if (m_fAttackRight > 0.4) + if( m_fAttackRight > 0.4 ) { - GetPainColor(r,g,b); + GetPainColor( r, g, b ); shade = a * max( m_fAttackRight, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); + ScaleColors( r, g, b, shade ); + SPR_Set( m_hSprite, r, g, b ); - x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; - y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; - SPR_DrawAdditive(1, x, y, NULL); + x = ScreenWidth / 2 + SPR_Width( m_hSprite, 1 ) * 2; + y = ScreenHeight / 2 - SPR_Height( m_hSprite,1 ) / 2; + SPR_DrawAdditive( 1, x, y, NULL ); m_fAttackRight = max( 0, m_fAttackRight - fFade ); - } else + } + else m_fAttackRight = 0; - if (m_fAttackRear > 0.4) + if( m_fAttackRear > 0.4 ) { - GetPainColor(r,g,b); + GetPainColor( r, g, b ); shade = a * max( m_fAttackRear, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); + ScaleColors( r, g, b, shade ); + SPR_Set( m_hSprite, r, g, b ); - x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; - y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; - SPR_DrawAdditive(2, x, y, NULL); + x = ScreenWidth / 2 - SPR_Width( m_hSprite, 2 ) / 2; + y = ScreenHeight / 2 + SPR_Height( m_hSprite, 2 ) * 2; + SPR_DrawAdditive( 2, x, y, NULL ); m_fAttackRear = max( 0, m_fAttackRear - fFade ); - } else + } + else m_fAttackRear = 0; - if (m_fAttackLeft > 0.4) + if( m_fAttackLeft > 0.4 ) { - GetPainColor(r,g,b); + GetPainColor( r, g, b ); shade = a * max( m_fAttackLeft, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); + ScaleColors( r, g, b, shade ); + SPR_Set( m_hSprite, r, g, b ); - x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; - y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; - SPR_DrawAdditive(3, x, y, NULL); + x = ScreenWidth / 2 - SPR_Width( m_hSprite, 3 ) * 3; + y = ScreenHeight / 2 - SPR_Height( m_hSprite,3 ) / 2; + SPR_DrawAdditive( 3, x, y, NULL ); m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); } else @@ -375,7 +371,7 @@ int CHudHealth::DrawPain(float flTime) return 1; } -int CHudHealth::DrawDamage(float flTime) +int CHudHealth::DrawDamage( float flTime ) { int i, r, g, b, a; DAMAGE_IMAGE *pdmg; @@ -383,14 +379,14 @@ int CHudHealth::DrawDamage(float flTime) if (!m_bitsDamage) return 1; - UnpackRGB(r,g,b, RGB_YELLOWISH); - - a = (int)( fabs(sin(flTime*2)) * 256.0); + UnpackRGB( r, g, b, RGB_YELLOWISH ); - ScaleColors(r, g, b, a); + a = (int)( fabs( sin( flTime * 2 ) ) * 256.0); + + ScaleColors( r, g, b, a ); // Draw all the items - for (i = 0; i < NUM_DMG_TYPES; i++) + for( i = 0; i < NUM_DMG_TYPES; i++ ) { if (m_bitsDamage & giDmgFlags[i]) { @@ -400,17 +396,16 @@ int CHudHealth::DrawDamage(float flTime) } } - // check for bits that should be expired - for ( i = 0; i < NUM_DMG_TYPES; i++ ) + for( i = 0; i < NUM_DMG_TYPES; i++ ) { - pdmg = &m_dmg[i]; - - if ( m_bitsDamage & giDmgFlags[i] ) + if( m_bitsDamage & giDmgFlags[i] ) { + pdmg = &m_dmg[i]; + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); - if ( pdmg->fExpire <= flTime // when the time has expired + if( pdmg->fExpire <= flTime // when the time has expired && a < 40 ) // and the flash is at the low point of the cycle { pdmg->fExpire = 0; @@ -419,10 +414,10 @@ int CHudHealth::DrawDamage(float flTime) pdmg->x = pdmg->y = 0; // move everyone above down - for (int j = 0; j < NUM_DMG_TYPES; j++) + for( int j = 0; j < NUM_DMG_TYPES; j++ ) { pdmg = &m_dmg[j]; - if ((pdmg->y) && (pdmg->y < y)) + if( ( pdmg->y ) && ( pdmg->y < y ) ) pdmg->y += giDmgHeight; } @@ -434,49 +429,47 @@ int CHudHealth::DrawDamage(float flTime) return 1; } - -void CHudHealth::UpdateTiles(float flTime, long bitsDamage) +void CHudHealth::UpdateTiles( float flTime, long bitsDamage ) { DAMAGE_IMAGE *pdmg; // Which types are new? long bitsOn = ~m_bitsDamage & bitsDamage; - - for (int i = 0; i < NUM_DMG_TYPES; i++) + + for( int i = 0; i < NUM_DMG_TYPES; i++ ) { pdmg = &m_dmg[i]; // Is this one already on? - if (m_bitsDamage & giDmgFlags[i]) + if( m_bitsDamage & giDmgFlags[i] ) { pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration - if (!pdmg->fBaseline) + if( !pdmg->fBaseline ) pdmg->fBaseline = flTime; } // Are we just turning it on? - if (bitsOn & giDmgFlags[i]) + if( bitsOn & giDmgFlags[i] ) { // put this one at the bottom - pdmg->x = giDmgWidth/8; + pdmg->x = giDmgWidth / 8; pdmg->y = ScreenHeight - giDmgHeight * 2; pdmg->fExpire=flTime + DMG_IMAGE_LIFE; - + // move everyone else up - for (int j = 0; j < NUM_DMG_TYPES; j++) + for( int j = 0; j < NUM_DMG_TYPES; j++ ) { - if (j == i) + if( j == i ) continue; pdmg = &m_dmg[j]; - if (pdmg->y) + if( pdmg->y ) pdmg->y -= giDmgHeight; - } pdmg = &m_dmg[i]; - } - } + } + } // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) m_bitsDamage |= bitsDamage; diff --git a/cl_dll/health.h b/cl_dll/health.h index 067db4b4..132b9cb4 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -23,6 +23,7 @@ #define DMG_IMAGE_NERVE 5 #define DMG_IMAGE_RAD 6 #define DMG_IMAGE_SHOCK 7 + //tf defines #define DMG_IMAGE_CALTROP 8 #define DMG_IMAGE_TRANQ 9 @@ -46,12 +47,10 @@ #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. - // time-based damage //mask off TF-specific stuff too #define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage - #define DMG_DROWN (1 << 14) // Drowning #define DMG_FIRSTTIMEBASED DMG_DROWN @@ -78,35 +77,33 @@ // TF Healing Additions for TakeHealth #define DMG_IGNORE_MAXHEALTH DMG_IGNITE + // TF Redefines since we never use the originals #define DMG_NAIL DMG_SLASH #define DMG_NOT_SELF DMG_FREEZE - #define DMG_TRANQ DMG_MORTAR #define DMG_CONCUSS DMG_SONIC - - typedef struct { float fExpire; float fBaseline; int x, y; -} DAMAGE_IMAGE; +}DAMAGE_IMAGE; // //----------------------------------------------------- // -class CHudHealth: public CHudBase +class CHudHealth : public CHudBase { public: virtual int Init( void ); virtual int VidInit( void ); - virtual int Draw(float fTime); + virtual int Draw( float fTime ); virtual void Reset( void ); - int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); - int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Health( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); int m_iHealth; int m_HUD_dmg_bio; int m_HUD_cross; @@ -119,9 +116,9 @@ private: HSPRITE m_hDamage; DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; - int m_bitsDamage; - int DrawPain(float fTime); - int DrawDamage(float fTime); - void CalcDamageDirection(vec3_t vecFrom); - void UpdateTiles(float fTime, long bits); -}; + int m_bitsDamage; + int DrawPain( float fTime ); + int DrawDamage( float fTime ); + void CalcDamageDirection( vec3_t vecFrom ); + void UpdateTiles( float fTime, long bits ); +}; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 17a2d1ab..655272d4 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -21,6 +21,7 @@ This file contains "stubs" of class member implementations so that we can predic add in the functionality you need. ========================== */ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -34,11 +35,11 @@ This file contains "stubs" of class member implementations so that we can predic const Vector g_vecZero = Vector( 0, 0, 0 ); int gmsgWeapPickup = 0; enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; +globalvars_t *gpGlobals; ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } +void EMIT_SOUND_DYN( edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch ) { } // CBaseEntity Stubs int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } @@ -47,17 +48,17 @@ CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } int CBaseEntity::Save( CSave &save ) { return 1; } int CBaseEntity::Restore( CRestore &restore ) { return 1; } void CBaseEntity::SetObjectCollisionBox( void ) { } -int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } void CBaseEntity :: MakeDormant( void ) { } int CBaseEntity :: IsDormant( void ) { return 0; } BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } -int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } void CBaseEntity::SUB_Remove( void ) { } // CBaseDelay Stubs -void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +void CBaseDelay::KeyValue( struct KeyValueData_s * ) { } int CBaseDelay::Restore( class CRestore & ) { return 1; } int CBaseDelay::Save( class CSave & ) { return 1; } @@ -67,7 +68,7 @@ int CBaseAnimating::Save( class CSave & ) { return 1; } // DEBUG Stubs edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } -void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } +void DBG_AssertFunction( BOOL fExpr, const char *szExpr, const char *szFile, int szLine, const char *szMessage) { } // UTIL_* Stubs void UTIL_PrecacheOther( const char *szClassname ) { } @@ -85,7 +86,7 @@ void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const c // CBaseToggle Stubs int CBaseToggle::Restore( class CRestore & ) { return 1; } int CBaseToggle::Save( class CSave & ) { return 1; } -void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } +void CBaseToggle::KeyValue( struct KeyValueData_s * ) { } // CGrenade Stubs void CGrenade::BounceSound( void ) { } @@ -93,12 +94,12 @@ void CGrenade::Explode( Vector, Vector ) { } void CGrenade::Explode( TraceResult *, int ) { } void CGrenade::Killed( entvars_t *, int ) { } void CGrenade::Spawn( void ) { } -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } +CGrenade *CGrenade::ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } void UTIL_Remove( CBaseEntity *pEntity ){ } -struct skilldata_t gSkillData; +struct skilldata_t gSkillData; void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} @@ -108,140 +109,139 @@ void CBeam::PointEntInit( const Vector &start, int endIndex ) { } CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } - -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } -void CBaseMonster :: Eat ( float flFullDuration ) { } -BOOL CBaseMonster :: FShouldEat ( void ) { return TRUE; } -void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } -void CBaseMonster :: BarnacleVictimReleased ( void ) { } -void CBaseMonster :: Listen ( void ) { } -float CBaseMonster :: FLSoundVolume ( CSound *pSound ) { return 0.0; } -BOOL CBaseMonster :: FValidateHintType ( short sHint ) { return FALSE; } -void CBaseMonster :: Look ( int iDistance ) { } -int CBaseMonster :: ISoundMask ( void ) { return 0; } -CSound* CBaseMonster :: PBestSound ( void ) { return NULL; } -CSound* CBaseMonster :: PBestScent ( void ) { return NULL; } -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } -void CBaseMonster :: MonsterThink ( void ) { } -void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } -int CBaseMonster :: IgnoreConditions ( void ) { return 0; } -void CBaseMonster :: RouteClear ( void ) { } -void CBaseMonster :: RouteNew ( void ) { } -BOOL CBaseMonster :: FRouteClear ( void ) { return FALSE; } -BOOL CBaseMonster :: FRefreshRoute ( void ) { return 0; } +CBaseEntity* CBaseMonster::CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } +void CBaseMonster::Eat( float flFullDuration ) { } +BOOL CBaseMonster::FShouldEat( void ) { return TRUE; } +void CBaseMonster::BarnacleVictimBitten( entvars_t *pevBarnacle ) { } +void CBaseMonster::BarnacleVictimReleased( void ) { } +void CBaseMonster::Listen( void ) { } +float CBaseMonster::FLSoundVolume( CSound *pSound ) { return 0.0; } +BOOL CBaseMonster::FValidateHintType( short sHint ) { return FALSE; } +void CBaseMonster::Look( int iDistance ) { } +int CBaseMonster::ISoundMask( void ) { return 0; } +CSound *CBaseMonster::PBestSound( void ) { return NULL; } +CSound *CBaseMonster::PBestScent( void ) { return NULL; } +float CBaseAnimating::StudioFrameAdvance( float flInterval ) { return 0.0; } +void CBaseMonster::MonsterThink( void ) { } +void CBaseMonster::MonsterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } +int CBaseMonster::IgnoreConditions( void ) { return 0; } +void CBaseMonster::RouteClear( void ) { } +void CBaseMonster::RouteNew( void ) { } +BOOL CBaseMonster::FRouteClear( void ) { return FALSE; } +BOOL CBaseMonster::FRefreshRoute( void ) { return 0; } BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) { return FALSE; } BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) { return FALSE; } BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } int ShouldSimplify( int routeType ) { return TRUE; } -void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) { } -BOOL CBaseMonster :: FBecomeProne ( void ) { return TRUE; } -BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } -BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; } -void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) { } -BOOL CBaseMonster :: FCanCheckAttacks ( void ) { return FALSE; } -int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) { return 0; } -void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } -BOOL CBaseMonster :: PopEnemy( ) { return FALSE; } -void CBaseMonster :: SetActivity ( Activity NewActivity ) { } -void CBaseMonster :: SetSequenceByName ( char *szSequence ) { } -int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } -float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } -void CBaseMonster :: AdvanceRoute ( float distance ) { } -int CBaseMonster :: RouteClassify( int iMoveFlag ) { return 0; } -BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } -void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) { } -BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } -void CBaseMonster :: Move ( float flInterval ) { } -BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } +void CBaseMonster::RouteSimplify( CBaseEntity *pTargetEnt ) { } +BOOL CBaseMonster::FBecomeProne( void ) { return TRUE; } +BOOL CBaseMonster::CheckRangeAttack1( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster::CheckRangeAttack2( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster::CheckMeleeAttack1( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster::CheckMeleeAttack2( float flDot, float flDist ) { return FALSE; } +void CBaseMonster::CheckAttacks( CBaseEntity *pTarget, float flDist ) { } +BOOL CBaseMonster::FCanCheckAttacks( void ) { return FALSE; } +int CBaseMonster::CheckEnemy( CBaseEntity *pEnemy ) { return 0; } +void CBaseMonster::PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } +BOOL CBaseMonster::PopEnemy() { return FALSE; } +void CBaseMonster::SetActivity( Activity NewActivity ) { } +void CBaseMonster::SetSequenceByName( char *szSequence ) { } +int CBaseMonster::CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } +float CBaseMonster::OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } +void CBaseMonster::AdvanceRoute( float distance ) { } +int CBaseMonster::RouteClassify( int iMoveFlag ) { return 0; } +BOOL CBaseMonster::BuildRoute( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } +void CBaseMonster::InsertWaypoint( Vector vecLocation, int afMoveFlags ) { } +BOOL CBaseMonster::FTriangulate( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } +void CBaseMonster::Move( float flInterval ) { } +BOOL CBaseMonster::ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { } -void CBaseMonster :: MonsterInit ( void ) { } -void CBaseMonster :: MonsterInitThink ( void ) { } -void CBaseMonster :: StartMonster ( void ) { } -void CBaseMonster :: MovementComplete( void ) { } +void CBaseMonster::MonsterInit( void ) { } +void CBaseMonster::MonsterInitThink( void ) { } +void CBaseMonster::StartMonster( void ) { } +void CBaseMonster::MovementComplete( void ) { } int CBaseMonster::TaskIsRunning( void ) { return 0; } -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } -BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } -BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } -float CBaseMonster::FlYawDiff ( void ) { return 0.0; } -float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } -float CBaseMonster::VecToYaw ( Vector vecDir ) { return 0.0; } -int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } -void CBaseMonster :: SetEyePosition ( void ) { } -int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } -void CBaseAnimating :: ResetSequenceInfo ( ) { } -BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } -void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { } -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } -void CBaseAnimating :: InitBoneControllers ( void ) { } -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } -int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } -Vector CBaseMonster :: GetGunPosition( void ) { return g_vecZero; } -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } -BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { return TRUE; } -int CBaseMonster :: FindHintNode ( void ) { return NO_NODE; } +int CBaseMonster::IRelationship( CBaseEntity *pTarget ) { return 0; } +BOOL CBaseMonster::FindCover( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +BOOL CBaseMonster::BuildNearestRoute( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +CBaseEntity *CBaseMonster::BestVisibleEnemy( void ) { return NULL; } +BOOL CBaseMonster::FInViewCone( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster::FInViewCone( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity::FVisible( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity::FVisible( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster::MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::FlYawDiff( void ) { return 0.0; } +float CBaseMonster::ChangeYaw( int yawSpeed ) { return 0; } +float CBaseMonster::VecToYaw( Vector vecDir ) { return 0.0; } +int CBaseAnimating::LookupActivity( int activity ) { return 0; } +int CBaseAnimating::LookupActivityHeaviest( int activity ) { return 0; } +void CBaseMonster::SetEyePosition( void ) { } +int CBaseAnimating::LookupSequence( const char *label ) { return 0; } +void CBaseAnimating::ResetSequenceInfo() { } +BOOL CBaseAnimating::GetSequenceFlags() { return FALSE; } +void CBaseAnimating::DispatchAnimEvents( float flInterval ) { } +void CBaseMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) { } +float CBaseAnimating::SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating::InitBoneControllers ( void ) { } +float CBaseAnimating::SetBlending( int iBlender, float flValue ) { return 0; } +void CBaseAnimating::GetBonePosition( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating::GetAttachment( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating::FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating::GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating::SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating::GetBodygroup( int iGroup ) { return 0; } +Vector CBaseMonster::GetGunPosition( void ) { return g_vecZero; } +void CBaseEntity::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseEntity::FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } +void CBaseEntity::TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster::MakeDamageBloodDecal( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +BOOL CBaseMonster::FGetNodeRoute( Vector vecDest ) { return TRUE; } +int CBaseMonster::FindHintNode( void ) { return NO_NODE; } void CBaseMonster::ReportAIState( void ) { } -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } -BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } -int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } -BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } -Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } -BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; } -BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; } +void CBaseMonster::KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster::FCheckAITrigger( void ) { return FALSE; } +int CBaseMonster::CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } +BOOL CBaseMonster::FindLateralCover( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } +Vector CBaseMonster::ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } +BOOL CBaseMonster::FacingIdeal( void ) { return FALSE; } +BOOL CBaseMonster::FCanActiveIdle( void ) { return FALSE; } void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } void CBaseMonster::SentenceStop( void ) { } void CBaseMonster::CorpseFallThink( void ) { } -void CBaseMonster :: MonsterInitDead( void ) { } -BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; } -BOOL CBaseMonster :: GetEnemy ( void ) { return FALSE; } -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::MonsterInitDead( void ) { } +BOOL CBaseMonster::BBoxFlat( void ) { return TRUE; } +BOOL CBaseMonster::GetEnemy( void ) { return FALSE; } +void CBaseMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +CBaseEntity* CBaseMonster::DropItem( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } +BOOL CBaseMonster::ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster::RadiusDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } void CBaseMonster::FadeMonster( void ) { } -void CBaseMonster :: GibMonster( void ) { } -BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } -BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } -Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } -MONSTERSTATE CBaseMonster :: GetIdealState ( void ) { return MONSTERSTATE_ALERT; } -Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { return NULL; } -Schedule_t *CBaseMonster :: GetSchedule ( void ) { return NULL; } -void CBaseMonster :: RunTask ( Task_t *pTask ) { } -void CBaseMonster :: StartTask ( Task_t *pTask ) { } +void CBaseMonster::GibMonster( void ) { } +BOOL CBaseMonster::HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster::HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster::GetDeathActivity( void ) { return ACT_DIE_HEADSHOT; } +MONSTERSTATE CBaseMonster::GetIdealState( void ) { return MONSTERSTATE_ALERT; } +Schedule_t* CBaseMonster::GetScheduleOfType( int Type ) { return NULL; } +Schedule_t *CBaseMonster::GetSchedule( void ) { return NULL; } +void CBaseMonster::RunTask( Task_t *pTask ) { } +void CBaseMonster::StartTask( Task_t *pTask ) { } Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { return NULL;} void CBaseMonster::BecomeDead( void ) {} -void CBaseMonster :: RunAI ( void ) {} -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBaseMonster::RunAI( void ) {} +void CBaseMonster::Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster::TakeHealth(float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } int CBaseMonster::Restore( class CRestore & ) { return 1; } int CBaseMonster::Save( class CSave & ) { return 1; } -int TrainSpeed(int iSpeed, int iMax) { return 0; } -void CBasePlayer :: DeathSound( void ) { } -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +int TrainSpeed( int iSpeed, int iMax ) { return 0; } +void CBasePlayer::DeathSound( void ) { } +int CBasePlayer::TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } void CBasePlayer::PackDeadPlayerItems( void ) { } void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } @@ -250,77 +250,77 @@ BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } void CBasePlayer::PlayerDeathThink(void) { } void CBasePlayer::StartDeathCam( void ) { } void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } -void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::PlayerUse( void ) { } void CBasePlayer::Jump() { } -void CBasePlayer::Duck( ) { } -int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer::Duck() { } +int CBasePlayer::Classify( void ) { return 0; } void CBasePlayer::PreThink(void) { } void CBasePlayer::CheckTimeBasedDamage() { } -void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::UpdateGeigerCounter( void ) { } void CBasePlayer::CheckSuitUpdate() { } void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } -void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::UpdatePlayerSound ( void ) { } void CBasePlayer::PostThink() { } -void CBasePlayer :: Precache( void ) { } +void CBasePlayer::Precache( void ) { } int CBasePlayer::Save( CSave &save ) { return 0; } -void CBasePlayer::RenewItems(void) { } +void CBasePlayer::RenewItems( void ) { } int CBasePlayer::Restore( CRestore &restore ) { return 0; } void CBasePlayer::SelectNextItem( int iItem ) { } BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } void CBasePlayer::SelectPrevItem( int iItem ) { } CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } -BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } -void CBasePlayer :: FlashlightTurnOn( void ) { } -void CBasePlayer :: FlashlightTurnOff( void ) { } -void CBasePlayer :: ForceClientDllUpdate( void ) { } -void CBasePlayer::ImpulseCommands( ) { } +BOOL CBasePlayer::FlashlightIsOn( void ) { return FALSE; } +void CBasePlayer::FlashlightTurnOn( void ) { } +void CBasePlayer::FlashlightTurnOff( void ) { } +void CBasePlayer::ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands() { } void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } void CBasePlayer::ItemPreFrame() { } void CBasePlayer::ItemPostFrame() { } int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } -int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +int CBasePlayer::GetAmmoIndex( const char *psz ) { return -1; } void CBasePlayer::SendAmmoUpdate(void) { } -void CBasePlayer :: UpdateClientData( void ) { } -BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } -void CBasePlayer :: BarnacleVictimReleased ( void ) { } -int CBasePlayer :: Illumination( void ) { return 0; } -void CBasePlayer :: EnableControl(BOOL fControl) { } -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } -void CBasePlayer :: ResetAutoaim( ) { } -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } -int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } -void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +void CBasePlayer::UpdateClientData( void ) { } +BOOL CBasePlayer::FBecomeProne( void ) { return TRUE; } +void CBasePlayer::BarnacleVictimBitten( entvars_t *pevBarnacle ) { } +void CBasePlayer::BarnacleVictimReleased( void ) { } +int CBasePlayer::Illumination( void ) { return 0; } +void CBasePlayer::EnableControl( BOOL fControl ) { } +Vector CBasePlayer::GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer::AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer::ResetAutoaim() { } +void CBasePlayer::SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer::GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem( char *pszItemName ) { } BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } -Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer::GetGunPosition( void ) { return g_vecZero; } const char *CBasePlayer::TeamID( void ) { return ""; } -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +int CBasePlayer::GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } -void ClearMultiDamage(void) { } -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void ClearMultiDamage( void ) { } +void ApplyMultiDamage( entvars_t *pevInflictor, entvars_t *pevAttacker ) { } void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +void SpawnBlood( Vector vecSpot, int bloodColor, float flDamage ) { } int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void EjectBrass( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } int CBasePlayerItem::Restore( class CRestore & ) { return 1; } int CBasePlayerItem::Save( class CSave & ) { return 1; } int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } int CBasePlayerWeapon::Save( class CSave & ) { return 1; } -void CBasePlayerItem :: SetObjectCollisionBox( void ) { } -void CBasePlayerItem :: FallInit( void ) { } -void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::SetObjectCollisionBox( void ) { } +void CBasePlayerItem::FallInit( void ) { } +void CBasePlayerItem::FallThink( void ) { } void CBasePlayerItem::Materialize( void ) { } void CBasePlayerItem::AttemptToMaterialize( void ) { } -void CBasePlayerItem :: CheckRespawn ( void ) { } -CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::CheckRespawn( void ) { } +CBaseEntity *CBasePlayerItem::Respawn( void ) { return NULL; } void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } void CBasePlayerItem::DestroyItem( void ) { } int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } @@ -331,17 +331,17 @@ void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } -BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +BOOL CBasePlayerWeapon::AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon::AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon::IsUseable( void ) { return TRUE; } int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } void CBasePlayerAmmo::Spawn( void ) { } CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } void CBasePlayerAmmo::Materialize( void ) { } -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) { } int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } void CBasePlayerWeapon::RetireWeapon( void ) { } -void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} \ No newline at end of file +void CSoundEnt::InsertSound( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} +void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index 7e9c730b..c79279dd 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "../hud.h" #include "../cl_util.h" #include "event_api.h" @@ -38,8 +39,6 @@ void EV_HornetGunFire( struct event_args_s *args ); void EV_TripmineFire( struct event_args_s *args ); void EV_SnarkFire( struct event_args_s *args ); - - void EV_TrainPitchAdjust( struct event_args_s *args ); } @@ -58,23 +57,23 @@ That was what we were going to do, but we ran out of time...oh well. */ void Game_HookEvents( void ) { - gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); - gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); - gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); - gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); - gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); - gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); - gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); - gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); - gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); - gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); - gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); - gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); - gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); - gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); - gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); - gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); - gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); - gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); - gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); + gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); + gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); + gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); + gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); + gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); + gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); + gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); + gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); + gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); + gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); + gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); + gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); + gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); + gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); + gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); + gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); + gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); + gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); } diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp index e61db884..b51ee693 100644 --- a/cl_dll/hl/hl_objects.cpp +++ b/cl_dll/hl/hl_objects.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "../hud.h" #include "../cl_util.h" #include "../demo.h" @@ -30,7 +31,7 @@ extern BEAM *pBeam; extern BEAM *pBeam2; void HUD_GetLastOrg( float *org ); -void UpdateBeams ( void ) +void UpdateBeams( void ) { vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; vec3_t view_ofs; @@ -47,32 +48,32 @@ void UpdateBeams ( void ) AngleVectors( angles, forward, right, up ); VectorCopy( origin, vecSrc ); - + VectorMA( vecSrc, 2048, forward, vecEnd ); gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - + // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); - + // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); gEngfuncs.pEventAPI->EV_PopPMStates(); - if ( pBeam ) + if( pBeam ) { pBeam->target = tr.endpos; - pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. } - - if ( pBeam2 ) + + if( pBeam2 ) { pBeam2->target = tr.endpos; - pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. } } @@ -85,6 +86,6 @@ Add game specific, client-side objects here */ void Game_AddObjects( void ) { - if ( pBeam && pBeam2 ) + if( pBeam && pBeam2 ) UpdateBeams(); } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 193c9d49..c712b76f 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -35,19 +36,19 @@ extern globalvars_t *gpGlobals; extern int g_iUser1; // Pool of client side entities/entvars_t -static entvars_t ev[ 32 ]; -static int num_ents = 0; +static entvars_t ev[32]; +static int num_ents = 0; // The entity we'll use to represent the local client -static CBasePlayer player; +static CBasePlayer player; // Local version of game .dll global variables ( time, etc. ) -static globalvars_t Globals; +static globalvars_t Globals; -static CBasePlayerWeapon *g_pWpns[ 32 ]; +static CBasePlayerWeapon *g_pWpns[32]; float g_flApplyVel = 0.0; -int g_irunninggausspred = 0; +int g_irunninggausspred = 0; vec3_t previousorigin; @@ -67,7 +68,6 @@ CSatchel g_Satchel; CTripmine g_Tripmine; CSqueak g_Snark; - /* ====================== AlertMessage @@ -77,12 +77,12 @@ Print debug messages to console */ void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) { - va_list argptr; - static char string[1024]; - - va_start (argptr, szFmt); - vsprintf (string, szFmt,argptr); - va_end (argptr); + va_list argptr; + static char string[1024]; + + va_start( argptr, szFmt ); + vsprintf( string, szFmt, argptr ); + va_end( argptr ); gEngfuncs.Con_Printf( "cl: " ); gEngfuncs.Con_Printf( string ); @@ -90,12 +90,13 @@ void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) //Returns if it's multiplayer. //Mostly used by the client side weapons. -bool bIsMultiplayer ( void ) +bool bIsMultiplayer( void ) { return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; } + //Just loads a v_ model. -void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) +void LoadVModel( char *szViewModel, CBasePlayer *m_pPlayer ) { gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); } @@ -110,50 +111,49 @@ we set up the m_pPlayer field. */ void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) { - memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); - pEntity->pev = &ev[ num_ents++ ]; + memset( &ev[num_ents], 0, sizeof(entvars_t) ); + pEntity->pev = &ev[num_ents++]; pEntity->Precache(); pEntity->Spawn(); - if ( pWeaponOwner ) + if( pWeaponOwner ) { ItemInfo info; - - ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; - - ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); - g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; + ( (CBasePlayerWeapon *)pEntity )->m_pPlayer = pWeaponOwner; + + ( (CBasePlayerWeapon *)pEntity )->GetItemInfo( &info ); + + g_pWpns[info.iId] = (CBasePlayerWeapon *)pEntity; } } /* ===================== -CBaseEntity :: Killed +CBaseEntity::Killed If weapons code "kills" an entity, just set its effects to EF_NODRAW ===================== */ -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +void CBaseEntity::Killed( entvars_t *pevAttacker, int iGib ) { pev->effects |= EF_NODRAW; } /* ===================== -CBasePlayerWeapon :: DefaultReload +CBasePlayerWeapon::DefaultReload ===================== */ -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) +BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) { - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) return FALSE; - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + int j = min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); - if (j == 0) + if( j == 0 ) return FALSE; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; @@ -169,32 +169,32 @@ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, /* ===================== -CBasePlayerWeapon :: CanDeploy +CBasePlayerWeapon::CanDeploy ===================== */ -BOOL CBasePlayerWeapon :: CanDeploy( void ) +BOOL CBasePlayerWeapon::CanDeploy( void ) { BOOL bHasAmmo = 0; - if ( !pszAmmo1() ) + if( !pszAmmo1() ) { // this weapon doesn't use ammo, can always deploy. return TRUE; } - if ( pszAmmo1() ) + if( pszAmmo1() ) { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); + bHasAmmo |= ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0 ); } - if ( pszAmmo2() ) + if( pszAmmo2() ) { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); + bHasAmmo |= ( m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0 ); } - if (m_iClip > 0) + if( m_iClip > 0 ) { bHasAmmo |= 1; } - if (!bHasAmmo) + if( !bHasAmmo ) { return FALSE; } @@ -204,17 +204,17 @@ BOOL CBasePlayerWeapon :: CanDeploy( void ) /* ===================== -CBasePlayerWeapon :: DefaultDeploy +CBasePlayerWeapon::DefaultDeploy ===================== */ -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) { - if ( !CanDeploy() ) + if( !CanDeploy() ) return FALSE; gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); - + SendWeaponAnim( iAnim, skiplocal, body ); g_irunninggausspred = false; @@ -225,13 +225,13 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, /* ===================== -CBasePlayerWeapon :: PlayEmptySound +CBasePlayerWeapon::PlayEmptySound ===================== */ -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +BOOL CBasePlayerWeapon::PlayEmptySound( void ) { - if (m_iPlayEmptySound) + if( m_iPlayEmptySound ) { HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); m_iPlayEmptySound = 0; @@ -242,11 +242,11 @@ BOOL CBasePlayerWeapon :: PlayEmptySound( void ) /* ===================== -CBasePlayerWeapon :: ResetEmptySound +CBasePlayerWeapon::ResetEmptySound ===================== */ -void CBasePlayerWeapon :: ResetEmptySound( void ) +void CBasePlayerWeapon::ResetEmptySound( void ) { m_iPlayEmptySound = 1; } @@ -275,7 +275,7 @@ Animate weapon model void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) { m_pPlayer->pev->weaponanim = iAnim; - + HUD_SendWeaponAnim( iAnim, body, 0 ); } @@ -290,16 +290,16 @@ Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecD { float x, y, z; - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + for( ULONG iShot = 1; iShot <= cShots; iShot++ ) { - if ( pevAttacker == NULL ) + if( pevAttacker == NULL ) { // get circular gaussian spread 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); + 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 ); } else { @@ -308,11 +308,10 @@ Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecD 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; - } - + } } - return Vector ( x * vecSpread.x, y * vecSpread.y, 0.0 ); + return Vector( x * vecSpread.x, y * vecSpread.y, 0.0 ); } /* @@ -324,24 +323,24 @@ Handles weapon firing, reloading, etc. */ void CBasePlayerWeapon::ItemPostFrame( void ) { - if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= 0.0 ) ) { #if 0 // FIXME, need ammo on client to make this work right // complete the reload. - int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + 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; -#else +#else m_iClip += 10; #endif m_fInReload = FALSE; } - if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) + if( ( m_pPlayer->pev->button & IN_ATTACK2 ) && ( m_flNextSecondaryAttack <= 0.0 ) ) { - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + if( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { m_fFireOnEmpty = TRUE; } @@ -349,28 +348,27 @@ void CBasePlayerWeapon::ItemPostFrame( void ) SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } - else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) + else if( ( m_pPlayer->pev->button & IN_ATTACK ) && ( m_flNextPrimaryAttack <= 0.0 ) ) { - if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + if( ( m_iClip == 0 && pszAmmo1() ) || ( iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { m_fFireOnEmpty = TRUE; } PrimaryAttack(); } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + 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) ) ) + else if( !( m_pPlayer->pev->button & ( IN_ATTACK | IN_ATTACK2 ) ) ) { // no fire buttons down - m_fFireOnEmpty = FALSE; // 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 < 0.0 ) + if( m_iClip == 0 && !( iFlags() & ITEM_FLAG_NOAUTORELOAD ) && m_flNextPrimaryAttack < 0.0 ) { Reload(); return; @@ -379,9 +377,9 @@ void CBasePlayerWeapon::ItemPostFrame( void ) WeaponIdle( ); return; } - + // catch all - if ( ShouldWeaponIdle() ) + if( ShouldWeaponIdle() ) { WeaponIdle(); } @@ -394,29 +392,28 @@ CBasePlayer::SelectItem Switch weapons ===================== */ -void CBasePlayer::SelectItem(const char *pstr) +void CBasePlayer::SelectItem( const char *pstr ) { - if (!pstr) + if( !pstr ) return; CBasePlayerItem *pItem = NULL; - if (!pItem) + if( !pItem ) return; - - if (pItem == m_pActiveItem) + if( pItem == m_pActiveItem ) return; - if (m_pActiveItem) - m_pActiveItem->Holster( ); - + if( m_pActiveItem ) + m_pActiveItem->Holster(); + m_pLastItem = m_pActiveItem; m_pActiveItem = pItem; - if (m_pActiveItem) + if( m_pActiveItem ) { - m_pActiveItem->Deploy( ); + m_pActiveItem->Deploy(); } } @@ -426,21 +423,21 @@ CBasePlayer::SelectLastItem ===================== */ -void CBasePlayer::SelectLastItem(void) +void CBasePlayer::SelectLastItem( void ) { - if (!m_pLastItem) + if( !m_pLastItem ) { return; } - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + if( m_pActiveItem && !m_pActiveItem->CanHolster() ) { return; } - if (m_pActiveItem) - m_pActiveItem->Holster( ); - + if( m_pActiveItem ) + m_pActiveItem->Holster(); + CBasePlayerItem *pTemp = m_pActiveItem; m_pActiveItem = m_pLastItem; m_pLastItem = pTemp; @@ -456,9 +453,9 @@ CBasePlayer::Killed void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) { // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - + if( m_pActiveItem ) + m_pActiveItem->Holster(); + g_irunninggausspred = false; } @@ -470,7 +467,7 @@ CBasePlayer::Spawn */ void CBasePlayer::Spawn( void ) { - if (m_pActiveItem) + if( m_pActiveItem ) m_pActiveItem->Deploy( ); g_irunninggausspred = false; @@ -485,7 +482,7 @@ Don't actually trace, but act like the trace didn't hit anything. */ void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) { - memset( ptr, 0, sizeof( *ptr ) ); + memset( ptr, 0, sizeof(*ptr) ); ptr->flFraction = 1.0; } @@ -501,10 +498,10 @@ void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life int i; vec3_t mmin, mmax; - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; - mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + mmin[i] = player->pev->origin[i] + mins[i]; + mmax[i] = player->pev->origin[i] + maxs[i]; } gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); @@ -523,7 +520,7 @@ void UTIL_ParticleBoxes( void ) physent_t *pe; cl_entity_t *player; vec3_t mins, maxs; - + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); // Store off the old count @@ -533,13 +530,13 @@ void UTIL_ParticleBoxes( void ) // Now add in all of the players. gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); - for ( idx = 1; idx < 100; idx++ ) + for( idx = 1; idx < 100; idx++ ) { pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); - if ( !pe ) + if( !pe ) break; - if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + if( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) { mins = pe->origin + pe->mins; maxs = pe->origin + pe->maxs; @@ -575,16 +572,15 @@ void CBasePlayerWeapon::PrintState( void ) COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time ); COM_Log( "c:\\hl.log", "%i ", m_iClip ); } int RandomLong( int a, int b ) { - return gEngfuncs.pfnRandomLong(a, b); + return gEngfuncs.pfnRandomLong( a, b ); } - /* ===================== HUD_InitClientWeapons @@ -595,7 +591,7 @@ Set up weapons, player and functions needed to run weapons code client-side. void HUD_InitClientWeapons( void ) { static int initialized = 0; - if ( initialized ) + if( initialized ) return; initialized = 1; @@ -607,40 +603,40 @@ void HUD_InitClientWeapons( void ) gpGlobals->time = gEngfuncs.GetClientTime(); // Fake functions - g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; - g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; - g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; - g_engfuncs.pfnNameForFunction = stub_NameForFunction; - g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; // Handled locally - g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; - g_engfuncs.pfnAlertMessage = AlertMessage; + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; // Pass through to engine - g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; - g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; - g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; // Allocate a slot for the local player - HUD_PrepEntity( &player , NULL ); + HUD_PrepEntity( &player, NULL ); // Allocate slot(s) for each weapon that we are going to be predicting - HUD_PrepEntity( &g_Glock , &player ); - HUD_PrepEntity( &g_Crowbar , &player ); - HUD_PrepEntity( &g_Python , &player ); - HUD_PrepEntity( &g_Mp5 , &player ); - HUD_PrepEntity( &g_Crossbow , &player ); - HUD_PrepEntity( &g_Shotgun , &player ); - HUD_PrepEntity( &g_Rpg , &player ); - HUD_PrepEntity( &g_Gauss , &player ); - HUD_PrepEntity( &g_Egon , &player ); - HUD_PrepEntity( &g_HGun , &player ); - HUD_PrepEntity( &g_HandGren , &player ); - HUD_PrepEntity( &g_Satchel , &player ); - HUD_PrepEntity( &g_Tripmine , &player ); - HUD_PrepEntity( &g_Snark , &player ); + HUD_PrepEntity( &g_Glock, &player ); + HUD_PrepEntity( &g_Crowbar, &player ); + HUD_PrepEntity( &g_Python, &player ); + HUD_PrepEntity( &g_Mp5, &player ); + HUD_PrepEntity( &g_Crossbow, &player ); + HUD_PrepEntity( &g_Shotgun, &player ); + HUD_PrepEntity( &g_Rpg, &player ); + HUD_PrepEntity( &g_Gauss, &player ); + HUD_PrepEntity( &g_Egon, &player ); + HUD_PrepEntity( &g_HGun, &player ); + HUD_PrepEntity( &g_HandGren, &player ); + HUD_PrepEntity( &g_Satchel, &player ); + HUD_PrepEntity( &g_Tripmine, &player ); + HUD_PrepEntity( &g_Snark, &player ); } /* @@ -653,9 +649,9 @@ Retruns the last position that we stored for egon beam endpoint. void HUD_GetLastOrg( float *org ) { int i; - + // Return last origin - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { org[i] = previousorigin[i]; } @@ -671,11 +667,11 @@ Remember our exact predicted origin so we can draw the egon to the right positio void HUD_SetLastOrg( void ) { int i; - + // Offset final origin by view_offset - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; + previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[i]; } } @@ -695,69 +691,56 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm weapon_data_t nulldata, *pfrom, *pto; static int lasthealth; - memset( &nulldata, 0, sizeof( nulldata ) ); + memset( &nulldata, 0, sizeof(nulldata) ); - HUD_InitClientWeapons(); + HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? - switch ( from->client.m_iId ) + switch( from->client.m_iId ) { case WEAPON_CROWBAR: pWeapon = &g_Crowbar; break; - case WEAPON_GLOCK: pWeapon = &g_Glock; break; - case WEAPON_PYTHON: pWeapon = &g_Python; break; - case WEAPON_MP5: pWeapon = &g_Mp5; break; - case WEAPON_CROSSBOW: pWeapon = &g_Crossbow; break; - case WEAPON_SHOTGUN: pWeapon = &g_Shotgun; break; - case WEAPON_RPG: pWeapon = &g_Rpg; break; - case WEAPON_GAUSS: pWeapon = &g_Gauss; break; - case WEAPON_EGON: pWeapon = &g_Egon; break; - case WEAPON_HORNETGUN: pWeapon = &g_HGun; break; - case WEAPON_HANDGRENADE: pWeapon = &g_HandGren; break; - case WEAPON_SATCHEL: pWeapon = &g_Satchel; break; - case WEAPON_TRIPMINE: pWeapon = &g_Tripmine; break; - case WEAPON_SNARK: pWeapon = &g_Snark; break; @@ -770,14 +753,13 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function - if ( g_runfuncs ) + if( g_runfuncs ) { - if ( to->client.health <= 0 && lasthealth > 0 ) + if( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); - } - else if ( to->client.health > 0 && lasthealth <= 0 ) + else if( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } @@ -786,37 +768,37 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm } // We are not predicting the current weapon, just bow out here. - if ( !pWeapon ) + if( !pWeapon ) return; - for ( i = 0; i < 32; i++ ) + for( i = 0; i < 32; i++ ) { - pCurrent = g_pWpns[ i ]; - if ( !pCurrent ) + pCurrent = g_pWpns[i]; + if( !pCurrent ) { continue; } - pfrom = &from->weapondata[ i ]; - - pCurrent->m_fInReload = pfrom->m_fInReload; - pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; -// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; - pCurrent->m_iClip = pfrom->m_iClip; + pfrom = &from->weapondata[i]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; + //pCurrent->m_flPumpTime = pfrom->m_flPumpTime; + pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; - pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; - pCurrent->pev->fuser1 = pfrom->fuser1; - pCurrent->m_flStartThrow = pfrom->fuser2; - pCurrent->m_flReleaseThrow = pfrom->fuser3; - pCurrent->m_chargeReady = pfrom->iuser1; - pCurrent->m_fInAttack = pfrom->iuser2; - pCurrent->m_fireState = pfrom->iuser3; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + pCurrent->pev->fuser1 = pfrom->fuser1; + pCurrent->m_flStartThrow = pfrom->fuser2; + pCurrent->m_flReleaseThrow = pfrom->fuser3; + pCurrent->m_chargeReady = pfrom->iuser1; + pCurrent->m_fInAttack = pfrom->iuser2; + pCurrent->m_fireState = pfrom->iuser3; - pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; - pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; - player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; - player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; + pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2]; + pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0]; + player.m_rgAmmo[pCurrent->m_iPrimaryAmmoType] = (int)from->client.vuser4[1]; + player.m_rgAmmo[pCurrent->m_iSecondaryAmmoType] = (int)from->client.vuser4[2]; } // For random weapon events, use this seed to seed random # generator @@ -826,13 +808,13 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed - buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame - + buttonsChanged = ( player.m_afButtonLast ^ cmd->buttons ); // These buttons have changed this frame + // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" - player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + player.m_afButtonReleased = buttonsChanged & ( ~cmd->buttons ); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; @@ -842,7 +824,7 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; - player.pev->maxspeed = from->client.maxspeed; + player.pev->maxspeed = from->client.maxspeed; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; @@ -851,62 +833,61 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm player.m_flAmmoStartCharge = from->client.fuser3; //Stores all our ammo info, so the client side weapons can use them. - player.ammo_9mm = (int)from->client.vuser1[0]; - player.ammo_357 = (int)from->client.vuser1[1]; - player.ammo_argrens = (int)from->client.vuser1[2]; - player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... - player.ammo_buckshot = (int)from->client.ammo_shells; - player.ammo_uranium = (int)from->client.ammo_cells; - player.ammo_hornets = (int)from->client.vuser2[0]; - player.ammo_rockets = (int)from->client.ammo_rockets; + player.ammo_9mm = (int)from->client.vuser1[0]; + player.ammo_357 = (int)from->client.vuser1[1]; + player.ammo_argrens = (int)from->client.vuser1[2]; + player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... + player.ammo_buckshot = (int)from->client.ammo_shells; + player.ammo_uranium = (int)from->client.ammo_cells; + player.ammo_hornets = (int)from->client.vuser2[0]; + player.ammo_rockets = (int)from->client.ammo_rockets; - // Point to current weapon object - if ( from->client.m_iId ) + if( from->client.m_iId ) { - player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + player.m_pActiveItem = g_pWpns[from->client.m_iId]; } - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + if( player.m_pActiveItem->m_iId == WEAPON_RPG ) { - ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; - ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; + ( (CRpg *)player.m_pActiveItem )->m_fSpotActive = (int)from->client.vuser2[1]; + ( (CRpg *)player.m_pActiveItem )->m_cActiveRockets = (int)from->client.vuser2[2]; } - + // Don't go firing anything if we have died. // Or if we don't have a weapon model deployed - if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && + if( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) { - if ( player.m_flNextAttack <= 0 ) + if( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } } // Assume that we are not going to switch weapons - to->client.m_iId = from->client.m_iId; + to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) - if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + if( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? - if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + if( from->weapondata[cmd->weaponselect].m_iId == cmd->weaponselect ) { - CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; - if ( pNew && ( pNew != pWeapon ) ) + CBasePlayerWeapon *pNew = g_pWpns[cmd->weaponselect]; + if( pNew && ( pNew != pWeapon ) ) { // Put away old weapon - if (player.m_pActiveItem) - player.m_pActiveItem->Holster( ); - + if( player.m_pActiveItem ) + player.m_pActiveItem->Holster(); + player.m_pLastItem = player.m_pActiveItem; player.m_pActiveItem = pNew; // Deploy new weapon - if (player.m_pActiveItem) + if( player.m_pActiveItem ) { - player.m_pActiveItem->Deploy( ); + player.m_pActiveItem->Deploy(); } // Update weapon id so we can predict things correctly. @@ -916,121 +897,121 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm } // Copy in results of prediction code - to->client.viewmodel = player.pev->viewmodel; - to->client.fov = player.pev->fov; - to->client.weaponanim = player.pev->weaponanim; - to->client.m_flNextAttack = player.m_flNextAttack; - to->client.fuser2 = player.m_flNextAmmoBurn; - to->client.fuser3 = player.m_flAmmoStartCharge; - to->client.maxspeed = player.pev->maxspeed; + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + to->client.fuser2 = player.m_flNextAmmoBurn; + to->client.fuser3 = player.m_flAmmoStartCharge; + to->client.maxspeed = player.pev->maxspeed; //HL Weapons - to->client.vuser1[0] = player.ammo_9mm; - to->client.vuser1[1] = player.ammo_357; - to->client.vuser1[2] = player.ammo_argrens; + to->client.vuser1[0] = player.ammo_9mm; + to->client.vuser1[1] = player.ammo_357; + to->client.vuser1[2] = player.ammo_argrens; - to->client.ammo_nails = player.ammo_bolts; - to->client.ammo_shells = player.ammo_buckshot; - to->client.ammo_cells = player.ammo_uranium; - to->client.vuser2[0] = player.ammo_hornets; - to->client.ammo_rockets = player.ammo_rockets; + to->client.ammo_nails = player.ammo_bolts; + to->client.ammo_shells = player.ammo_buckshot; + to->client.ammo_cells = player.ammo_uranium; + to->client.vuser2[0] = player.ammo_hornets; + to->client.ammo_rockets = player.ammo_rockets; - if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + if( player.m_pActiveItem->m_iId == WEAPON_RPG ) { - from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; - from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; + from->client.vuser2[1] = ( (CRpg *)player.m_pActiveItem)->m_fSpotActive; + from->client.vuser2[2] = ( (CRpg *)player.m_pActiveItem)->m_cActiveRockets; } // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) - if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) + if( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) { int body = 2; //Pop the model to body 0. - if ( pWeapon == &g_Tripmine ) + if( pWeapon == &g_Tripmine ) body = 0; //Show laser sight/scope combo - if ( pWeapon == &g_Python && bIsMultiplayer() ) + if( pWeapon == &g_Python && bIsMultiplayer() ) body = 1; - + // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } - for ( i = 0; i < 32; i++ ) + for( i = 0; i < 32; i++ ) { - pCurrent = g_pWpns[ i ]; + pCurrent = g_pWpns[i]; - pto = &to->weapondata[ i ]; + pto = &to->weapondata[i]; - if ( !pCurrent ) + if( !pCurrent ) { - memset( pto, 0, sizeof( weapon_data_t ) ); + memset( pto, 0, sizeof(weapon_data_t) ); continue; } - - pto->m_fInReload = pCurrent->m_fInReload; - pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; -// pto->m_flPumpTime = pCurrent->m_flPumpTime; - pto->m_iClip = pCurrent->m_iClip; - pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; - pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; - pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; - pto->fuser1 = pCurrent->pev->fuser1; - pto->fuser2 = pCurrent->m_flStartThrow; - pto->fuser3 = pCurrent->m_flReleaseThrow; - pto->iuser1 = pCurrent->m_chargeReady; - pto->iuser2 = pCurrent->m_fInAttack; - pto->iuser3 = pCurrent->m_fireState; + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; + //pto->m_flPumpTime = pCurrent->m_flPumpTime; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; + pto->fuser1 = pCurrent->pev->fuser1; + pto->fuser2 = pCurrent->m_flStartThrow; + pto->fuser3 = pCurrent->m_flReleaseThrow; + pto->iuser1 = pCurrent->m_chargeReady; + pto->iuser2 = pCurrent->m_fInAttack; + pto->iuser3 = pCurrent->m_fireState; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) - pto->m_flNextReload -= cmd->msec / 1000.0; - pto->m_fNextAimBonus -= cmd->msec / 1000.0; - pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; - pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; - pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; - pto->fuser1 -= cmd->msec / 1000.0; + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + pto->fuser1 -= cmd->msec / 1000.0; - to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; - to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; - to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; - to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; + to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; + to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; + to->client.vuser4[1] = player.m_rgAmmo[pCurrent->m_iPrimaryAmmoType]; + to->client.vuser4[2] = player.m_rgAmmo[pCurrent->m_iSecondaryAmmoType]; -/* if ( pto->m_flPumpTime != -9999 ) +/* if( pto->m_flPumpTime != -9999 ) { pto->m_flPumpTime -= cmd->msec / 1000.0; - if ( pto->m_flPumpTime < -0.001 ) + if( pto->m_flPumpTime < -0.001 ) pto->m_flPumpTime = -0.001; }*/ - if ( pto->m_fNextAimBonus < -1.0 ) + if( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } - if ( pto->m_flNextPrimaryAttack < -1.0 ) + if( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } - if ( pto->m_flNextSecondaryAttack < -0.001 ) + if( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } - if ( pto->m_flTimeWeaponIdle < -0.001 ) + if( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } - if ( pto->m_flNextReload < -0.001 ) + if( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } - if ( pto->fuser1 < -0.001 ) + if( pto->fuser1 < -0.001 ) { pto->fuser1 = -0.001; } @@ -1038,19 +1019,19 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; - if ( to->client.m_flNextAttack < -0.001 ) + if( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } to->client.fuser2 -= cmd->msec / 1000.0; - if ( to->client.fuser2 < -0.001 ) + if( to->client.fuser2 < -0.001 ) { to->client.fuser2 = -0.001; } - + to->client.fuser3 -= cmd->msec / 1000.0; - if ( to->client.fuser3 < -0.001 ) + if( to->client.fuser3 < -0.001 ) { to->client.fuser3 = -0.001; } @@ -1078,7 +1059,7 @@ void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s g_runfuncs = runfuncs; #if defined( CLIENT_WEAPONS ) - if ( cl_lw && cl_lw->value ) + if( cl_lw && cl_lw->value ) { HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); } @@ -1088,14 +1069,14 @@ void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s to->client.fov = g_lastFOV; } - if ( g_irunninggausspred == 1 ) + if( g_irunninggausspred == 1 ) { Vector forward; gEngfuncs.pfnAngleVectors( v_angles, forward, NULL, NULL ); to->client.velocity = to->client.velocity - forward * g_flApplyVel * 5; g_irunninggausspred = false; } - + // All games can use FOV state g_lastFOV = to->client.fov; } diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 8fdc3992..0f3b45bc 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -25,71 +25,69 @@ #include "parsemsg.h" #include "hud_servers.h" - #include "demo.h" #include "demo_api.h" cvar_t *hud_textmode; float g_hud_text_color[3]; - -extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); +extern client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ); extern cvar_t *sensitivity; cvar_t *cl_lw = NULL; -void ShutdownInput (void); +void ShutdownInput( void ); -//DECLARE_MESSAGE(m_Logo, Logo) -int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +//DECLARE_MESSAGE( m_Logo, Logo ) +int __MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) { - return gHUD.MsgFunc_Logo(pszName, iSize, pbuf ); + return gHUD.MsgFunc_Logo( pszName, iSize, pbuf ); } -//DECLARE_MESSAGE(m_Logo, Logo) -int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) +//DECLARE_MESSAGE( m_Logo, Logo ) +int __MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf ) { - return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); + return gHUD.MsgFunc_ResetHUD( pszName, iSize, pbuf ); } -int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) { gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); return 1; } -int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) { gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); return 1; } -int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); } -int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); } -int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +int __MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); } // TFFree Command Menu -void __CmdFunc_OpenCommandMenu(void) +void __CmdFunc_OpenCommandMenu( void ) { } // TFC "special" command -void __CmdFunc_InputPlayerSpecial(void) +void __CmdFunc_InputPlayerSpecial( void ) { } -void __CmdFunc_CloseCommandMenu(void) +void __CmdFunc_CloseCommandMenu( void ) { } @@ -102,59 +100,58 @@ void __CmdFunc_ToggleServerBrowser( void ) } // TFFree Command Menu Message Handlers -int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_ValClass( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_TeamNames( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_Feign( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_Detpack( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_VGUIMenu( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) { return 0; } - -int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ) { return 0; } -int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) +int __MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ) { return 0; } // This is called every time the DLL is loaded -void CHud :: Init( void ) +void CHud::Init( void ) { HOOK_MESSAGE( Logo ); HOOK_MESSAGE( ResetHUD ); @@ -201,7 +198,7 @@ void CHud :: Init( void ) m_pSpriteList = NULL; // Clear any old HUD list - if ( m_pHudList ) + if( m_pHudList ) { HUDLIST *pList; while ( m_pHudList ) @@ -235,22 +232,21 @@ void CHud :: Init( void ) m_Menu.Init(); - - MsgFunc_ResetHUD(0, 0, NULL ); + MsgFunc_ResetHUD( 0, 0, NULL ); } // CHud destructor // cleans up memory allocated for m_rg* arrays -CHud :: ~CHud() +CHud::~CHud() { - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; + delete[] m_rghSprites; + delete[] m_rgrcRects; + delete[] m_rgszSpriteNames; - if ( m_pHudList ) + if( m_pHudList ) { HUDLIST *pList; - while ( m_pHudList ) + while( m_pHudList ) { pList = m_pHudList; m_pHudList = m_pHudList->pNext; @@ -258,59 +254,57 @@ CHud :: ~CHud() } m_pHudList = NULL; } - - } // GetSpriteIndex() // searches through the sprite list loaded from hud.txt for a name matching SpriteName // returns an index into the gHUD.m_rghSprites[] array // returns 0 if sprite not found -int CHud :: GetSpriteIndex( const char *SpriteName ) +int CHud::GetSpriteIndex( const char *SpriteName ) { // look through the loaded sprite name list for SpriteName - for ( int i = 0; i < m_iSpriteCount; i++ ) + for( int i = 0; i < m_iSpriteCount; i++ ) { - if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) + if( strncmp( SpriteName, m_rgszSpriteNames + ( i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) return i; } return -1; // invalid sprite } -void CHud :: VidInit( void ) +void CHud::VidInit( void ) { int j; m_scrinfo.iSize = sizeof(m_scrinfo); - GetScreenInfo(&m_scrinfo); + GetScreenInfo( &m_scrinfo ); // ---------- // Load Sprites // --------- -// m_hsprFont = LoadSprite("sprites/%d_font.spr"); - + //m_hsprFont = LoadSprite("sprites/%d_font.spr"); + m_hsprLogo = 0; m_hsprCursor = 0; - if (ScreenWidth < 640) + if( ScreenWidth < 640 ) m_iRes = 320; else m_iRes = 640; // Only load this once - if ( !m_pSpriteList ) + if( !m_pSpriteList ) { // we need to load the hud.txt, and all sprites within - m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); + m_pSpriteList = SPR_GetList( "sprites/hud.txt", &m_iSpriteCountAllRes ); - if (m_pSpriteList) + if( m_pSpriteList ) { // count the number of sprites of the appropriate res m_iSpriteCount = 0; client_sprite_t *p = m_pSpriteList; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + for( j = 0; j < m_iSpriteCountAllRes; j++ ) { - if ( p->iRes == m_iRes ) + if( p->iRes == m_iRes ) m_iSpriteCount++; p++; } @@ -322,13 +316,13 @@ void CHud :: VidInit( void ) p = m_pSpriteList; int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + for( j = 0; j < m_iSpriteCountAllRes; j++ ) { - if ( p->iRes == m_iRes ) + if( p->iRes == m_iRes ) { char sz[256]; - sprintf(sz, "sprites/%s.spr", p->szSprite); - m_rghSprites[index] = SPR_Load(sz); + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load( sz ); m_rgrcRects[index] = p->rc; strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); @@ -347,16 +341,16 @@ void CHud :: VidInit( void ) // count the number of sprites of the appropriate res m_iSpriteCount = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + for( j = 0; j < m_iSpriteCountAllRes; j++ ) { - if ( p->iRes == m_iRes ) + if( p->iRes == m_iRes ) m_iSpriteCount++; p++; } - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; + delete[] m_rghSprites; + delete[] m_rgrcRects; + delete[] m_rgszSpriteNames; // allocated memory for sprite handle arrays m_rghSprites = new HSPRITE[m_iSpriteCount]; @@ -365,13 +359,13 @@ void CHud :: VidInit( void ) p = m_pSpriteList; int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + for( j = 0; j < m_iSpriteCountAllRes; j++ ) { - if ( p->iRes == m_iRes ) + if( p->iRes == m_iRes ) { char sz[256]; sprintf( sz, "sprites/%s.spr", p->szSprite ); - m_rghSprites[index] = SPR_Load(sz); + m_rghSprites[index] = SPR_Load( sz ); m_rgrcRects[index] = p->rc; strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); @@ -404,10 +398,9 @@ void CHud :: VidInit( void ) m_StatusIcons.VidInit(); m_Scoreboard.VidInit(); m_MOTD.VidInit(); - } -int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +int CHud::MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -425,29 +418,28 @@ COM_FileBase ============ */ // Extracts the base name of a file (no path, no extension, assumes '/' as path separator) -void COM_FileBase ( const char *in, char *out) +void COM_FileBase ( const char *in, char *out ) { int len, start, end; len = strlen( in ); - + // scan backward for '.' end = len - 1; - while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + while( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) end--; - - if ( in[end] != '.' ) // no '.', copy to end - end = len-1; + + if( in[end] != '.' ) // no '.', copy to end + end = len - 1; else end--; // Found ',', copy to left of '.' - // Scan backward for '/' - start = len-1; - while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start = len - 1; + while( start >= 0 && in[start] != '/' && in[start] != '\\' ) start--; - if ( in[start] != '/' && in[start] != '\\' ) + if( in[start] != '/' && in[start] != '\\' ) start = 0; else start++; @@ -457,6 +449,7 @@ void COM_FileBase ( const char *in, char *out) // Copy partial string strncpy( out, &in[start], len ); + // Terminate it out[len] = 0; } @@ -470,13 +463,13 @@ HUD_IsGame int HUD_IsGame( const char *game ) { const char *gamedir; - char gd[ 1024 ]; + char gd[1024]; gamedir = gEngfuncs.pfnGetGameDirectory(); - if ( gamedir && gamedir[0] ) + if( gamedir && gamedir[0] ) { COM_FileBase( gamedir, gd ); - if ( !stricmp( gd, game ) ) + if( !stricmp( gd, game ) ) return 1; } return 0; @@ -491,27 +484,27 @@ Returns last FOV */ float HUD_GetFOV( void ) { - if ( gEngfuncs.pDemoAPI->IsRecording() ) + if( gEngfuncs.pDemoAPI->IsRecording() ) { // Write it int i = 0; - unsigned char buf[ 100 ]; + unsigned char buf[100]; // Active - *( float * )&buf[ i ] = g_lastFOV; - i += sizeof( float ); + *(float *)&buf[i] = g_lastFOV; + i += sizeof(float); Demo_WriteBuffer( TYPE_ZOOM, i, buf ); } - if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + if( gEngfuncs.pDemoAPI->IsPlayingback() ) { g_lastFOV = g_demozoom; } return g_lastFOV; } -int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +int CHud::MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -519,12 +512,12 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) int def_fov = CVAR_GET_FLOAT( "default_fov" ); //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). - if ( cl_lw && cl_lw->value ) + if( cl_lw && cl_lw->value ) return 1; g_lastFOV = newfov; - if ( newfov == 0 ) + if( newfov == 0 ) { m_iFOV = def_fov; } @@ -536,7 +529,7 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) // the clients fov is actually set in the client data update section of the hud // Set a new sensitivity - if ( m_iFOV == def_fov ) + if( m_iFOV == def_fov ) { // reset to saved sensitivity m_flMouseSensitivity = 0; @@ -550,24 +543,23 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) return 1; } - -void CHud::AddHudElem(CHudBase *phudelem) +void CHud::AddHudElem( CHudBase *phudelem ) { HUDLIST *pdl, *ptemp; -//phudelem->Think(); + //phudelem->Think(); - if (!phudelem) + if( !phudelem ) return; - pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); - if (!pdl) + pdl = (HUDLIST *)malloc( sizeof(HUDLIST) ); + if( !pdl ) return; - memset(pdl, 0, sizeof(HUDLIST)); + memset( pdl, 0, sizeof(HUDLIST) ); pdl->p = phudelem; - if (!m_pHudList) + if( !m_pHudList ) { m_pHudList = pdl; return; @@ -575,7 +567,7 @@ void CHud::AddHudElem(CHudBase *phudelem) ptemp = m_pHudList; - while (ptemp->pNext) + while( ptemp->pNext ) ptemp = ptemp->pNext; ptemp->pNext = pdl; @@ -585,5 +577,3 @@ float CHud::GetSensitivity( void ) { return m_flMouseSensitivity; } - - diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 73423c0d..ec236003 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -20,7 +20,6 @@ // CHud handles the message, calculation, and drawing the HUD // - #define RGB_YELLOWISH 0x00FFA000 //255,160,0 #define RGB_REDISH 0x00FF1010 //255,160,0 #define RGB_GREENISH 0x0000A000 //0,160,0 @@ -36,7 +35,8 @@ #define HUDELEM_ACTIVE 1 -typedef struct { +typedef struct +{ int x, y; } POSITION; @@ -47,13 +47,13 @@ enum MAX_TEAM_NAME = 16 }; -typedef struct { - unsigned char r,g,b,a; +typedef struct +{ + unsigned char r, g, b, a; } RGBA; typedef struct cvar_s cvar_t; - #define HUD_ACTIVE 1 #define HUD_INTERMISSION 2 @@ -71,42 +71,39 @@ public: int m_type; int m_iFlags; // active, moving, virtual ~CHudBase() {} - virtual int Init( void ) {return 0;} - virtual int VidInit( void ) {return 0;} - virtual int Draw(float flTime) {return 0;} - virtual void Think(void) {return;} - virtual void Reset(void) {return;} + virtual int Init( void ) { return 0; } + virtual int VidInit( void ) { return 0; } + virtual int Draw( float flTime ) { return 0; } + virtual void Think( void ) { return; } + virtual void Reset( void ) { return; } virtual void InitHUDData( void ) {} // called every time a server is connected to - }; -struct HUDLIST { +struct HUDLIST +{ CHudBase *p; HUDLIST *pNext; }; - - // //----------------------------------------------------- #include "hud_spectator.h" - // //----------------------------------------------------- // -class CHudAmmo: public CHudBase +class CHudAmmo : public CHudBase { public: int Init( void ); int VidInit( void ); - int Draw(float flTime); - void Think(void); - void Reset(void); - int DrawWList(float flTime); - int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); - int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); - int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); + int Draw( float flTime ); + void Think( void ); + void Reset( void ); + int DrawWList( float flTime ); + int MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_WeaponList( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_AmmoX( const char *pszName, int iSize, void *pbuf ); int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); @@ -131,16 +128,14 @@ private: float m_fFade; RGBA m_rgba; WEAPON *m_pWeapon; - int m_HUD_bucket0; + int m_HUD_bucket0; int m_HUD_selection; - }; // //----------------------------------------------------- // - -class CHudAmmoSecondary: public CHudBase +class CHudAmmoSecondary : public CHudBase { public: int Init( void ); @@ -176,29 +171,27 @@ class CHudGeiger: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); + int Draw( float flTime ); + int MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf ); private: int m_iGeigerRange; - }; // //----------------------------------------------------- // -class CHudTrain: public CHudBase +class CHudTrain : public CHudBase { public: int Init( void ); int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); + int Draw( float flTime ); + int MsgFunc_Train( const char *pszName, int iSize, void *pbuf ); private: HSPRITE m_hSprite; int m_iPos; - }; // @@ -206,7 +199,6 @@ private: // // REMOVED: Vgui has replaced this. // - class CHudMOTD : public CHudBase { public: @@ -223,14 +215,13 @@ public: protected: static int MOTD_DISPLAY_TIME; - char m_szMOTD[ MAX_MOTD_LENGTH ]; - + char m_szMOTD[MAX_MOTD_LENGTH]; + int m_iLines; int m_iMaxLength; }; - -class CHudScoreboard: public CHudBase +class CHudScoreboard : public CHudBase { public: int Init( void ); @@ -257,7 +248,6 @@ public: void GetAllPlayersInfo( void ); }; - // //----------------------------------------------------- // @@ -274,7 +264,8 @@ public: int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); protected: - enum { + enum + { MAX_STATUSTEXT_LENGTH = 128, MAX_STATUSBAR_VALUES = 8, MAX_STATUSBAR_LINES = 2 @@ -296,7 +287,7 @@ protected: // REMOVED: Vgui has replaced this. // /* -class CHudScoreboard: public CHudBase +class CHudScoreboard : public CHudBase { public: int Init( void ); @@ -319,13 +310,13 @@ public: int m_iShowscoresHeld; void GetAllPlayersInfo( void ); + private: struct cvar_s *cl_showpacketloss; - }; */ -struct extra_player_info_t +struct extra_player_info_t { short frags; short deaths; @@ -334,7 +325,7 @@ struct extra_player_info_t char teamname[MAX_TEAM_NAME]; }; -struct team_info_t +struct team_info_t { char name[MAX_TEAM_NAME]; short frags; @@ -348,11 +339,10 @@ struct team_info_t int teamnumber; }; -extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -extern team_info_t g_TeamInfo[MAX_TEAMS+1]; -extern int g_IsSpectator[MAX_PLAYERS+1]; - +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS + 1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS + 1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS + 1]; +extern int g_IsSpectator[MAX_PLAYERS + 1]; // //----------------------------------------------------- @@ -404,10 +394,9 @@ public: int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); -friend class CHudSpectator; + friend class CHudSpectator; private: - struct cvar_s * m_HUD_saytext; struct cvar_s * m_HUD_saytext_time; }; @@ -415,25 +404,24 @@ private: // //----------------------------------------------------- // -class CHudBattery: public CHudBase +class CHudBattery : public CHudBase { public: int Init( void ); int VidInit( void ); - int Draw(float flTime); - int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); + int Draw( float flTime ); + int MsgFunc_Battery( const char *pszName, int iSize, void *pbuf ); private: HSPRITE m_hSprite1; HSPRITE m_hSprite2; wrect_t *m_prc1; wrect_t *m_prc2; - int m_iBat; + int m_iBat; float m_fFade; - int m_iHeight; // width of the battery innards + int m_iHeight; // width of the battery innards }; - // //----------------------------------------------------- // @@ -442,11 +430,11 @@ class CHudFlashlight: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw(float flTime); + int Draw( float flTime ); void Reset( void ); - int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); - int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); - + int MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_FlashBat( const char *pszName, int iSize, void *pbuf ); + private: HSPRITE m_hSprite1; HSPRITE m_hSprite2; @@ -455,10 +443,10 @@ private: wrect_t *m_prc2; wrect_t *m_prcBeam; float m_flBat; - int m_iBat; - int m_fOn; + int m_iBat; + int m_fOn; float m_fFade; - int m_iWidth; // width of the battery innards + int m_iWidth; // width of the battery innards }; // @@ -486,31 +474,31 @@ struct message_parms_t //----------------------------------------------------- // -class CHudTextMessage: public CHudBase +class CHudTextMessage : public CHudBase { public: int Init( void ); static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); static char *BufferedLocaliseTextString( const char *msg ); char *LookupString( const char *msg_name, int *msg_dest = NULL ); - int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); + int MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ); }; // //----------------------------------------------------- // -class CHudMessage: public CHudBase +class CHudMessage : public CHudBase { public: int Init( void ); int VidInit( void ); - int Draw(float flTime); - int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); - int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); + int Draw( float flTime ); + int MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ); float FadeBlend( float fadein, float fadeout, float hold, float localTime ); - int XPosition( float x, int width, int lineWidth ); + int XPosition( float x, int width, int lineWidth ); int YPosition( float y, int height ); void MessageAdd( const char *pName, float time ); @@ -536,16 +524,17 @@ private: // #define MAX_SPRITE_NAME_LENGTH 24 -class CHudStatusIcons: public CHudBase +class CHudStatusIcons : public CHudBase { public: int Init( void ); int VidInit( void ); void Reset( void ); - int Draw(float flTime); - int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf); + int Draw( float flTime ); + int MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ); - enum { + enum + { MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, MAX_ICONSPRITES = 4 }; @@ -556,7 +545,6 @@ public: void DisableIcon( char *pszIconName ); private: - typedef struct { char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; @@ -566,13 +554,11 @@ private: } icon_sprite_t; icon_sprite_t m_IconList[MAX_ICONSPRITES]; - }; // //----------------------------------------------------- // - class CHud { private: @@ -586,7 +572,6 @@ private: int m_iConcussionEffect; public: - HSPRITE m_hsprCursor; float m_flTime; // the current client time float m_fOldTime; // the time at which the HUD was last redrawn @@ -602,13 +587,13 @@ public: cvar_t *m_pCvarDraw; int m_iFontHeight; - int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); - int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b ); + int DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b ); + int DrawHudString( int x, int y, int iMaxX, char *szString, int r, int g, int b ); int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); - int GetNumWidth(int iNumber, int iFlags); + int GetNumWidth( int iNumber, int iFlags ); int DrawHudStringLen( char *szIt ); - void DrawDarkRectangle( int x, int y, int wide, int tall); + void DrawDarkRectangle( int x, int y, int wide, int tall ); private: // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. @@ -621,7 +606,7 @@ private: public: HSPRITE GetSprite( int index ) { - return (index < 0) ? 0 : m_rghSprites[index]; + return ( index < 0 ) ? 0 : m_rghSprites[index]; } wrect_t& GetSpriteRect( int index ) @@ -659,13 +644,13 @@ public: ~CHud(); // destructor, frees allocated memory // user messages - int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf); - int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf ); void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); // Screen information @@ -680,10 +665,9 @@ public: int m_iNoConsolePrint; - void AddHudElem(CHudBase *p); + void AddHudElem( CHudBase *p ); float GetSensitivity(); - }; extern CHud gHUD; @@ -693,4 +677,3 @@ extern int g_iTeamNumber; extern int g_iUser1; extern int g_iUser2; extern int g_iUser3; - diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h index 9b7e189a..a7a05e7e 100644 --- a/cl_dll/hud_iface.h +++ b/cl_dll/hud_iface.h @@ -11,9 +11,8 @@ #include "exportdef.h" -typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); #include "wrect.h" #include "../engine/cdll_int.h" extern cl_enginefunc_t gEngfuncs; - #endif diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index 4051b401..47f8bc92 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -28,16 +28,16 @@ extern BEAM *pBeam2; /// USER-DEFINED SERVER MESSAGE HANDLERS -int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) +int CHud::MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf ) { ASSERT( iSize == 0 ); // clear all hud data HUDLIST *pList = m_pHudList; - while ( pList ) + while( pList ) { - if ( pList->p ) + if( pList->p ) pList->p->Reset(); pList = pList->pNext; } @@ -51,21 +51,21 @@ int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) return 1; } -void CAM_ToFirstPerson(void); +void CAM_ToFirstPerson( void ); -void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) +void CHud::MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) { CAM_ToFirstPerson(); } -void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) +void CHud::MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) { // prepare all hud data HUDLIST *pList = m_pHudList; - while (pList) + while( pList ) { - if ( pList->p ) + if( pList->p ) pList->p->InitHUDData(); pList = pList->pNext; } @@ -74,8 +74,7 @@ void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) pBeam = pBeam2 = NULL; } - -int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +int CHud::MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); m_Teamplay = READ_BYTE(); @@ -83,38 +82,36 @@ int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) return 1; } - -int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +int CHud::MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ) { int armor, blood; Vector from; int i; float count; - + BEGIN_READ( pbuf, iSize ); armor = READ_BYTE(); blood = READ_BYTE(); - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++) from[i] = READ_COORD(); - count = (blood * 0.5) + (armor * 0.5); + count = ( blood * 0.5 ) + ( armor * 0.5 ); - if (count < 10) + if( count < 10 ) count = 10; // TODO: kick viewangles, show damage visually - return 1; } -int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) +int CHud::MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); m_iConcussionEffect = READ_BYTE(); - if (m_iConcussionEffect) - this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0); + if( m_iConcussionEffect ) + this->m_StatusIcons.EnableIcon( "dmg_concuss", 255, 160, 0 ); else - this->m_StatusIcons.DisableIcon("dmg_concuss"); + this->m_StatusIcons.DisableIcon( "dmg_concuss" ); return 1; } diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index bacd4026..aed98455 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -20,17 +20,15 @@ #include "cl_util.h" //#include "triangleapi.h" - #define MAX_LOGO_FRAMES 56 -int grgLogoFrame[MAX_LOGO_FRAMES] = +int grgLogoFrame[MAX_LOGO_FRAMES] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 }; - extern int g_iVisibleMouse; float HUD_GetFOV( void ); @@ -38,20 +36,20 @@ float HUD_GetFOV( void ); extern cvar_t *sensitivity; // Think -void CHud::Think(void) +void CHud::Think( void ) { int newfov; HUDLIST *pList = m_pHudList; - while (pList) + while( pList ) { - if (pList->p->m_iFlags & HUD_ACTIVE) + if( pList->p->m_iFlags & HUD_ACTIVE ) pList->p->Think(); pList = pList->pNext; } newfov = HUD_GetFOV(); - if ( newfov == 0 ) + if( newfov == 0 ) { m_iFOV = default_fov->value; } @@ -61,22 +59,22 @@ void CHud::Think(void) } // the clients fov is actually set in the client data update section of the hud - // Set a new sensitivity - if ( m_iFOV == default_fov->value ) - { + if( m_iFOV == default_fov->value ) + { // reset to saved sensitivity m_flMouseSensitivity = 0; } else - { + { // set a new sensitivity that is proportional to the change from the FOV default m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); } // think about default fov - if ( m_iFOV == 0 ) - { // only let players adjust up in fov, and only if they are not overriden by something else + if( m_iFOV == 0 ) + { + // only let players adjust up in fov, and only if they are not overriden by something else m_iFOV = max( default_fov->value, 90 ); } } @@ -84,21 +82,20 @@ void CHud::Think(void) // Redraw // step through the local data, placing the appropriate graphics & text as appropriate // returns 1 if they've changed, 0 otherwise -int CHud :: Redraw( float flTime, int intermission ) +int CHud::Redraw( float flTime, int intermission ) { m_fOldTime = m_flTime; // save time of previous redraw m_flTime = flTime; m_flTimeDelta = (double)m_flTime - m_fOldTime; static float m_flShotTime = 0; - + // Clock was reset, reset delta - if ( m_flTimeDelta < 0 ) + if( m_flTimeDelta < 0 ) m_flTimeDelta = 0; - - if (m_flShotTime && m_flShotTime < flTime) + if( m_flShotTime && m_flShotTime < flTime ) { - gEngfuncs.pfnClientCmd("snapshot\n"); + gEngfuncs.pfnClientCmd( "snapshot\n" ); m_flShotTime = 0; } @@ -106,21 +103,22 @@ int CHud :: Redraw( float flTime, int intermission ) // if no redrawing is necessary // return 0; - - if ( m_pCvarDraw->value ) + + if( m_pCvarDraw->value ) { HUDLIST *pList = m_pHudList; - while (pList) + while( pList ) { - if ( !intermission ) + if( !intermission ) { - if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) - pList->p->Draw(flTime); + if ( ( pList->p->m_iFlags & HUD_ACTIVE ) && !( m_iHideHUDDisplay & HIDEHUD_ALL ) ) + pList->p->Draw( flTime ); } else - { // it's an intermission, so only draw hud elements that are set to draw during intermissions - if ( pList->p->m_iFlags & HUD_INTERMISSION ) + { + // it's an intermission, so only draw hud elements that are set to draw during intermissions + if( pList->p->m_iFlags & HUD_INTERMISSION ) pList->p->Draw( flTime ); } @@ -129,43 +127,43 @@ int CHud :: Redraw( float flTime, int intermission ) } // are we in demo mode? do we need to draw the logo in the top corner? - if (m_iLogo) + if( m_iLogo ) { int x, y, i; - if (m_hsprLogo == 0) - m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + if( m_hsprLogo == 0 ) + m_hsprLogo = LoadSprite( "sprites/%d_logo.spr" ); - SPR_Set(m_hsprLogo, 250, 250, 250 ); - - x = SPR_Width(m_hsprLogo, 0); + SPR_Set( m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width( m_hsprLogo, 0 ); x = ScreenWidth - x; - y = SPR_Height(m_hsprLogo, 0)/2; + y = SPR_Height( m_hsprLogo, 0 ) / 2; // Draw the logo at 20 fps - int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + int iFrame = (int)( flTime * 20 ) % MAX_LOGO_FRAMES; i = grgLogoFrame[iFrame] - 1; - SPR_DrawAdditive(i, x, y, NULL); + SPR_DrawAdditive( i, x, y, NULL ); } /* - if ( g_iVisibleMouse ) + if( g_iVisibleMouse ) { void IN_GetMousePos( int *mx, int *my ); int mx, my; IN_GetMousePos( &mx, &my ); - - if (m_hsprCursor == 0) + + if( m_hsprCursor == 0 ) { char sz[256]; sprintf( sz, "sprites/cursor.spr" ); m_hsprCursor = SPR_Load( sz ); } - SPR_Set(m_hsprCursor, 250, 250, 250 ); - + SPR_Set( m_hsprCursor, 250, 250, 250 ); + // Draw the logo at 20 fps SPR_DrawAdditive( 0, mx, my, NULL ); } @@ -177,9 +175,9 @@ int CHud :: Redraw( float flTime, int intermission ) void ScaleColors( int &r, int &g, int &b, int a ) { float x = (float)a / 255; - r = (int)(r * x); - g = (int)(g * x); - b = (int)(b * x); + r = (int)( r * x ); + g = (int)( g * x ); + b = (int)( b * x ); } const unsigned char colors[8][3] = @@ -194,11 +192,11 @@ const unsigned char colors[8][3] = {240, 180, 24} }; -int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) { if( hud_textmode->value == 2 ) { - gEngfuncs.pfnDrawSetTextColor( r/255.0, g/255.0, b/255.0 ); + gEngfuncs.pfnDrawSetTextColor( r / 255.0, g / 255.0, b / 255.0 ); return gEngfuncs.pfnDrawConsoleString( xpos, ypos, (char*) szIt ); } @@ -206,18 +204,18 @@ int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int TextMessageDrawChar( 0, 0, 0, 0, 0, 0 ); // draw the string until we hit the null character or a newline character - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) { - int w = gHUD.m_scrinfo.charWidths[ 'M' ]; - if ( xpos + w > iMaxX ) + int w = gHUD.m_scrinfo.charWidths['M']; + if( xpos + w > iMaxX ) return xpos; - if( (*szIt == '^') && (*(szIt + 1) >= '0') && (*(szIt + 1) <= '7') ) + if( ( *szIt == '^' ) && ( *( szIt + 1 ) >= '0') && ( *( szIt + 1 ) <= '7') ) { szIt++; - r = colors[ *szIt - '0' ][0]; - g = colors[ *szIt - '0' ][1]; - b = colors[ *szIt - '0' ][2]; - if( !*(++szIt)) + r = colors[*szIt - '0'][0]; + g = colors[*szIt - '0'][1]; + b = colors[*szIt - '0'][2]; + if( !*(++szIt) ) return xpos; } int c = (unsigned int)(unsigned char)*szIt; @@ -228,67 +226,65 @@ int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int return xpos; } -int CHud :: DrawHudStringLen( char *szIt ) +int CHud::DrawHudStringLen( char *szIt ) { int l = 0; - for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) { - l += gHUD.m_scrinfo.charWidths[ (unsigned char)*szIt ]; + l += gHUD.m_scrinfo.charWidths[(unsigned char)*szIt]; } return l; } - -int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) +int CHud::DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) { char szString[32]; sprintf( szString, "%d", iNumber ); return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); - } // draws a string from right to left (right-aligned) -int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +int CHud::DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) { // find the end of the string for( char *szIt = szString; *szIt != 0; szIt++ ) - xpos -= gHUD.m_scrinfo.charWidths[ (unsigned char) *szIt ]; + xpos -= gHUD.m_scrinfo.charWidths[(unsigned char)*szIt]; if( xpos < iMinX ) xpos = iMinX; DrawHudString( xpos, ypos, gHUD.m_scrinfo.iWidth, szString, r, g, b ); return xpos; } -int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) +int CHud::DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b ) { - int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; + int iWidth = GetSpriteRect( m_HUD_number_0 ).right - GetSpriteRect( m_HUD_number_0 ).left; int k; - if (iNumber > 0) + if( iNumber > 0 ) { // SPR_Draw 100's - if (iNumber >= 100) + if( iNumber >= 100 ) { - k = iNumber/100; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + k = iNumber / 100; + SPR_Set( GetSprite( m_HUD_number_0 + k ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect( m_HUD_number_0 + k ) ); x += iWidth; } - else if (iFlags & (DHN_3DIGITS)) + else if( iFlags & ( DHN_3DIGITS ) ) { //SPR_DrawAdditive( 0, x, y, &rc ); x += iWidth; } // SPR_Draw 10's - if (iNumber >= 10) + if( iNumber >= 10 ) { - k = (iNumber % 100)/10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + k = ( iNumber % 100 ) / 10; + SPR_Set( GetSprite( m_HUD_number_0 + k ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect( m_HUD_number_0 + k ) ); x += iWidth; } - else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + else if( iFlags & ( DHN_3DIGITS | DHN_2DIGITS ) ) { //SPR_DrawAdditive( 0, x, y, &rc ); x += iWidth; @@ -296,70 +292,66 @@ int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, // SPR_Draw ones k = iNumber % 10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + SPR_Set( GetSprite( m_HUD_number_0 + k ), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect( m_HUD_number_0 + k ) ); x += iWidth; - } - else if (iFlags & DHN_DRAWZERO) + } + else if( iFlags & DHN_DRAWZERO ) { - SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); + SPR_Set( GetSprite( m_HUD_number_0 ), r, g, b ); // SPR_Draw 100's - if (iFlags & (DHN_3DIGITS)) + if( iFlags & ( DHN_3DIGITS ) ) { //SPR_DrawAdditive( 0, x, y, &rc ); x += iWidth; } - if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + if( iFlags & ( DHN_3DIGITS | DHN_2DIGITS ) ) { //SPR_DrawAdditive( 0, x, y, &rc ); x += iWidth; } // SPR_Draw ones - - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect( m_HUD_number_0 ) ); x += iWidth; } return x; } - int CHud::GetNumWidth( int iNumber, int iFlags ) { - if (iFlags & (DHN_3DIGITS)) + if( iFlags & ( DHN_3DIGITS ) ) return 3; - if (iFlags & (DHN_2DIGITS)) + if( iFlags & ( DHN_2DIGITS ) ) return 2; - if (iNumber <= 0) + if( iNumber <= 0 ) { - if (iFlags & (DHN_DRAWZERO)) + if( iFlags & ( DHN_DRAWZERO ) ) return 1; else return 0; } - if (iNumber < 10) + if( iNumber < 10 ) return 1; - if (iNumber < 100) + if( iNumber < 100 ) return 2; return 3; - } - void CHud::DrawDarkRectangle( int x, int y, int wide, int tall ) { //gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); gEngfuncs.pfnFillRGBABlend( x, y, wide, tall, 0, 0, 0, 255 * 0.6 ); - FillRGBA( x+1, y, wide-1, 1, 255, 140, 0, 255 ); - FillRGBA( x, y, 1, tall-1, 255, 140, 0, 255 ); - FillRGBA( x+wide-1, y+1, 1, tall-1, 255, 140, 0, 255 ); - FillRGBA( x, y+tall-1, wide-1, 1, 255, 140, 0, 255 ); + FillRGBA( x + 1, y, wide - 1, 1, 255, 140, 0, 255 ); + FillRGBA( x, y, 1, tall - 1, 255, 140, 0, 255 ); + FillRGBA( x + wide - 1, y + 1, 1, tall - 1, 255, 140, 0, 255 ); + FillRGBA( x, y + tall - 1, wide - 1, 1, 255, 140, 0, 255 ); } diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp index 7a5a1475..3cdab827 100644 --- a/cl_dll/hud_servers.cpp +++ b/cl_dll/hud_servers.cpp @@ -39,7 +39,7 @@ Callback from engine */ void NET_CALLBACK ListResponse( struct net_response_s *response ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->ListResponse( response ); } @@ -54,7 +54,7 @@ Callback from engine */ void NET_CALLBACK ServerResponse( struct net_response_s *response ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->ServerResponse( response ); } @@ -69,7 +69,7 @@ Callback from engine */ void NET_CALLBACK PingResponse( struct net_response_s *response ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->PingResponse( response ); } @@ -84,11 +84,12 @@ Callback from engine */ void NET_CALLBACK RulesResponse( struct net_response_s *response ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->RulesResponse( response ); } } + /* =================== PlayersResponse @@ -98,11 +99,12 @@ Callback from engine */ void NET_CALLBACK PlayersResponse( struct net_response_s *response ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->PlayersResponse( response ); } } + /* =================== ListResponse @@ -115,20 +117,20 @@ void CHudServers::ListResponse( struct net_response_s *response ) request_t *p; int c = 0; - if ( !( response->error == NET_SUCCESS ) ) + if( !( response->error == NET_SUCCESS ) ) return; - if ( response->type != NETAPI_REQUEST_SERVERLIST ) + if( response->type != NETAPI_REQUEST_SERVERLIST ) return; - if ( response->response ) + if( response->response ) { list = ( request_t * ) response->response; while ( list ) { c++; - //if ( c < 40 ) + //if( c < 40 ) { // Copy from parsed stuff p = new request_t; @@ -161,23 +163,23 @@ void CHudServers::ServerResponse( struct net_response_s *response ) request_t *p; server_t *browser; int len; - char sz[ 32 ]; + char sz[32]; // Remove from active list p = FindRequest( response->context, m_pActiveList ); - if ( p ) + if( p ) { RemoveServerFromList( &m_pActiveList, p ); m_nActiveQueries--; } - - if ( response->error != NET_SUCCESS ) + + if( response->error != NET_SUCCESS ) return; - + switch ( response->type ) { case NETAPI_REQUEST_DETAILS: - if ( response->response ) + if( response->response ) { szresponse = (char *)response->response; len = strlen( szresponse ) + 100 + 1; @@ -185,13 +187,13 @@ void CHudServers::ServerResponse( struct net_response_s *response ) browser = new server_t; browser->remote_address = response->remote_address; - browser->info = new char[ len ]; + browser->info = new char[len]; browser->ping = (int)( 1000.0 * response->ping ); strcpy( browser->info, szresponse ); NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); NET_API->SetValueForKey( browser->info, "ping", sz, len ); - + AddServer( &m_pServers, browser ); } break; @@ -208,12 +210,12 @@ PingResponse */ void CHudServers::PingResponse( struct net_response_s *response ) { - char sz[ 32 ]; + char sz[32]; - if ( response->error != NET_SUCCESS ) + if( response->error != NET_SUCCESS ) return; - switch ( response->type ) + switch( response->type ) { case NETAPI_REQUEST_PING: sprintf( sz, "%.2f", 1000.0 * response->ping ); @@ -235,13 +237,13 @@ void CHudServers::RulesResponse( struct net_response_s *response ) { char *szresponse; - if ( response->error != NET_SUCCESS ) + if( response->error != NET_SUCCESS ) return; - switch ( response->type ) + switch( response->type ) { case NETAPI_REQUEST_RULES: - if ( response->response ) + if( response->response ) { szresponse = (char *)response->response; @@ -263,13 +265,13 @@ void CHudServers::PlayersResponse( struct net_response_s *response ) { char *szresponse; - if ( response->error != NET_SUCCESS ) + if( response->error != NET_SUCCESS ) return; - - switch ( response->type ) + + switch( response->type ) { case NETAPI_REQUEST_PLAYERS: - if ( response->response ) + if( response->response ) { szresponse = (char *)response->response; @@ -288,24 +290,24 @@ CompareServers Return 1 if p1 is "less than" p2, 0 otherwise =================== */ -int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) { const char *n1, *n2; - if ( p1->ping < p2->ping ) + if( p1->ping < p2->ping ) return 1; - if ( p1->ping == p2->ping ) + if( p1->ping == p2->ping ) { // Pings equal, sort by second key: hostname - if ( p1->info && p2->info ) + if( p1->info && p2->info ) { n1 = NET_API->ValueForKey( p1->info, "hostname" ); n2 = NET_API->ValueForKey( p2->info, "hostname" ); - if ( n1 && n2 ) + if( n1 && n2 ) { - if ( stricmp( n1, n2 ) < 0 ) + if( stricmp( n1, n2 ) < 0 ) return 1; } } @@ -322,9 +324,9 @@ AddServer */ void CHudServers::AddServer( server_t **ppList, server_t *p ) { -server_t *list; + server_t *list; - if ( !ppList || ! p ) + if( !ppList || ! p ) return; m_nServerCount++; @@ -333,7 +335,7 @@ server_t *list; list = *ppList; // Head of list? - if ( !list ) + if( !list ) { p->next = NULL; *ppList = p; @@ -341,17 +343,17 @@ server_t *list; } // Put on head of list - if ( CompareServers( p, list ) ) + if( CompareServers( p, list ) ) { p->next = *ppList; *ppList = p; } else { - while ( list->next ) + while( list->next ) { // Insert before list next - if ( CompareServers( p, list->next ) ) + if( CompareServers( p, list->next ) ) { p->next = list->next->next; list->next = p; @@ -377,15 +379,15 @@ void CHudServers::Think( double time ) { m_fElapsed += time; - if ( !m_nRequesting ) + if( !m_nRequesting ) return; - if ( !m_nQuerying ) + if( !m_nQuerying ) return; QueryThink(); - if ( ServerListSize() > 0 ) + if( ServerListSize() > 0 ) return; m_dStarted = 0.0; @@ -405,25 +407,25 @@ void CHudServers::QueryThink( void ) { request_t *p; - if ( !m_nRequesting || m_nDone ) + if( !m_nRequesting || m_nDone ) return; - if ( !m_nQuerying ) + if( !m_nQuerying ) return; - if ( m_nActiveQueries > MAX_QUERIES ) + if( m_nActiveQueries > MAX_QUERIES ) return; // Nothing left - if ( !m_pServerList ) + if( !m_pServerList ) return; - while ( 1 ) + while( 1 ) { p = m_pServerList; // No more in list? - if ( !p ) + if( !p ) break; // Move to next @@ -443,7 +445,7 @@ void CHudServers::QueryThink( void ) m_pActiveList = p; // Too many active? - if ( m_nActiveQueries > MAX_QUERIES ) + if( m_nActiveQueries > MAX_QUERIES ) break; } } @@ -455,20 +457,20 @@ ServerListSize # of servers in active query and in pending to be queried lists ================== */ -int CHudServers::ServerListSize( void ) +int CHudServers::ServerListSize( void ) { int c = 0; request_t *p; p = m_pServerList; - while ( p ) + while( p ) { c++; p = p->next; } p = m_pActiveList; - while ( p ) + while( p ) { c++; p = p->next; @@ -488,9 +490,9 @@ CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList { request_t *p; p = pList; - while ( p ) + while( p ) { - if ( context == p->context ) + if( context == p->context ) return p; p = p->next; @@ -510,14 +512,14 @@ void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) request_t *p, *n; request_t *newlist = NULL; - if ( !ppList ) + if( !ppList ) return; p = *ppList; - while ( p ) + while( p ) { n = p->next; - if ( p != item ) + if( p != item ) { p->next = newlist; newlist = p; @@ -537,11 +539,11 @@ void CHudServers::ClearRequestList( request_t **ppList ) { request_t *p, *n; - if ( !ppList ) + if( !ppList ) return; p = *ppList; - while ( p ) + while( p ) { n = p->next; delete p; @@ -560,11 +562,11 @@ void CHudServers::ClearServerList( server_t **ppList ) { server_t *p, *n; - if ( !ppList ) + if( !ppList ) return; p = *ppList; - while ( p ) + while( p ) { n = p->next; delete[] p->info; @@ -585,11 +587,11 @@ int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const ch fv1 = atof( sz1 ); fv2 = atof( sz2 ); - if ( fv1 && fv2 ) + if( fv1 && fv2 ) { - if ( fv1 > fv2 ) + if( fv1 > fv2 ) return iSortOrder; - else if ( fv1 < fv2 ) + else if( fv1 < fv2 ) return -iSortOrder; else return 0; @@ -601,7 +603,7 @@ int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const ch int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) { - if (!p1 || !p2) // No meaningful comparison + if(!p1 || !p2) // No meaningful comparison return 0; int iSortOrder = 1; @@ -613,8 +615,8 @@ int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::serv return retval; } -static char g_fieldname[ 256 ]; -int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +static char g_fieldname[256]; +int __cdecl FnServerCompare( const void *elem1, const void *elem2 ) { CHudServers::server_t *list1, *list2; @@ -628,7 +630,7 @@ void CHudServers::SortServers( const char *fieldname ) { server_t *p; // Create a list - if ( !m_pServers ) + if( !m_pServers ) return; strcpy( g_fieldname, fieldname ); @@ -637,7 +639,7 @@ void CHudServers::SortServers( const char *fieldname ) int c = 0; p = m_pServers; - while ( p ) + while( p ) { c++; p = p->next; @@ -645,21 +647,21 @@ void CHudServers::SortServers( const char *fieldname ) server_t **pSortArray; - pSortArray = new server_t *[ c ]; - memset( pSortArray, 0, c * sizeof( server_t * ) ); + pSortArray = new server_t *[c]; + memset( pSortArray, 0, c * sizeof(server_t*) ); // Now copy the list into the pSortArray: p = m_pServers; i = 0; - while ( p ) + while( p ) { - pSortArray[ i++ ] = p; + pSortArray[i++] = p; p = p->next; } // Now do that actual sorting. size_t nCount = c; - size_t nSize = sizeof( server_t * ); + size_t nSize = sizeof(server_t*); qsort( pSortArray, @@ -670,11 +672,11 @@ void CHudServers::SortServers( const char *fieldname ) // Now rebuild the list. m_pServers = pSortArray[0]; - for ( i = 0; i < c - 1; i++ ) + for( i = 0; i < c - 1; i++ ) { - pSortArray[ i ]->next = pSortArray[ i + 1 ]; + pSortArray[i]->next = pSortArray[i + 1]; } - pSortArray[ c - 1 ]->next = NULL; + pSortArray[c - 1]->next = NULL; // Clean Up. delete[] pSortArray; @@ -693,9 +695,9 @@ CHudServers::server_t *CHudServers::GetServer( int server ) server_t *p; p = m_pServers; - while ( p ) + while( p ) { - if ( c == server ) + if( c == server ) return p; c++; @@ -714,7 +716,7 @@ Return info ( key/value ) string for particular server char *CHudServers::GetServerInfo( int server ) { server_t *p = GetServer( server ); - if ( p ) + if( p ) { return p->info; } @@ -731,8 +733,8 @@ Kill all pending requests in engine void CHudServers::CancelRequest( void ) { m_nRequesting = 0; - m_nQuerying = 0; - m_nDone = 1; + m_nQuerying = 0; + m_nDone = 1; NET_API->CancelAllRequests(); } @@ -747,16 +749,16 @@ Loads the master server addresses from file and into the passed in array int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) { int i; - char szMaster[ 256 ]; + char szMaster[256]; char szMasterFile[256]; char *pbuffer = NULL; char *pstart = NULL ; netadr_t adr; char szAdr[64]; - int nPort; - int nCount = 0; + int nPort; + int nCount = 0; bool bIgnore; - int nDefaultPort; + int nDefaultPort; // Assume default master and master file strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string @@ -764,30 +766,30 @@ int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr // See if there is a command line override i = gEngfuncs.CheckParm( "-comm", &pstart ); - if ( i && pstart ) + if( i && pstart ) { - strcpy (szMasterFile, pstart ); + strcpy( szMasterFile, pstart ); } // Read them in from proper file pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc - if ( !pbuffer ) + if( !pbuffer ) { goto finish_master; } pstart = pbuffer; - while ( nCount < maxservers ) + while( nCount < maxservers ) { pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if ( strlen(m_szToken) <= 0) + if( strlen( m_szToken ) <= 0) break; bIgnore = true; - if ( !stricmp( m_szToken, "Master" ) ) + if( !stricmp( m_szToken, "Master" ) ) { nDefaultPort = PORT_MASTER; bIgnore = FALSE; @@ -795,74 +797,72 @@ int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr // Now parse all addresses between { } pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if ( strlen(m_szToken) <= 0 ) + if( strlen( m_szToken ) <= 0 ) break; - if ( stricmp ( m_szToken, "{" ) ) + if( stricmp( m_szToken, "{" ) ) break; // Parse addresses until we get to "}" - while ( nCount < maxservers ) + while( nCount < maxservers ) { char base[256]; // Now parse all addresses between { } pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if (strlen(m_szToken) <= 0) + if( strlen( m_szToken ) <= 0 ) break; - if ( !stricmp ( m_szToken, "}" ) ) + if( !stricmp ( m_szToken, "}" ) ) break; - + sprintf( base, "%s", m_szToken ); pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - if (strlen(m_szToken) <= 0) + if( strlen( m_szToken ) <= 0 ) break; - if ( stricmp( m_szToken, ":" ) ) + if( stricmp( m_szToken, ":" ) ) break; pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); - - if (strlen(m_szToken) <= 0) + + if( strlen( m_szToken ) <= 0 ) break; - nPort = atoi ( m_szToken ); - if ( !nPort ) + nPort = atoi( m_szToken ); + if( !nPort ) nPort = nDefaultPort; sprintf( szAdr, "%s:%i", base, nPort ); // Can we resolve it any better - if ( !NET_API->StringToAdr( szAdr, &adr ) ) + if( !NET_API->StringToAdr( szAdr, &adr ) ) bIgnore = true; - if ( !bIgnore ) + if( !bIgnore ) { - padr[ nCount++ ] = adr; + padr[nCount++] = adr; } } } - finish_master: - if ( !nCount ) + if( !nCount ) { sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string // Convert to netadr_t - if ( NET_API->StringToAdr ( szMaster, &adr ) ) + if( NET_API->StringToAdr( szMaster, &adr ) ) { - - padr[ nCount++ ] = adr; + padr[nCount++] = adr; } } *count = nCount; - if ( pbuffer ) + if( pbuffer ) { gEngfuncs.COM_FreeFile( pbuffer ); } @@ -879,14 +879,14 @@ Request list of game servers from master */ void CHudServers::RequestList( void ) { - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; int count = 0; netadr_t adr; - if ( !LoadMasterAddresses( 1, &count, &adr ) ) + if( !LoadMasterAddresses( 1, &count, &adr ) ) { gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); return; @@ -910,14 +910,14 @@ void CHudServers::RequestList( void ) void CHudServers::RequestBroadcastList( int clearpending ) { - m_nRequesting = 1; - m_nDone = 0; - m_dStarted = m_fElapsed; + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; - netadr_t adr; - memset( &adr, 0, sizeof( adr ) ); + netadr_t adr; + memset( &adr, 0, sizeof(adr) ); - if ( clearpending ) + if( clearpending ) { ClearRequestList( &m_pActiveList ); ClearRequestList( &m_pServerList ); @@ -932,7 +932,7 @@ void CHudServers::RequestBroadcastList( int clearpending ) // Make sure networking system has started. NET_API->InitNetworking(); - if ( clearpending ) + if( clearpending ) { // Kill off left overs if any NET_API->CancelAllRequests(); @@ -952,9 +952,9 @@ void CHudServers::RequestBroadcastList( int clearpending ) void CHudServers::ServerPing( int server ) { server_t *p; - + p = GetServer( server ); - if ( !p ) + if( !p ) return; // Make sure networking system has started. @@ -967,9 +967,9 @@ void CHudServers::ServerPing( int server ) void CHudServers::ServerRules( int server ) { server_t *p; - + p = GetServer( server ); - if ( !p ) + if( !p ) return; // Make sure networking system has started. @@ -982,9 +982,9 @@ void CHudServers::ServerRules( int server ) void CHudServers::ServerPlayers( int server ) { server_t *p; - + p = GetServer( server ); - if ( !p ) + if( !p ) return; // Make sure networking system has started. @@ -999,7 +999,6 @@ int CHudServers::isQuerying() return m_nRequesting ? 1 : 0; } - /* =================== GetServerCount @@ -1021,16 +1020,15 @@ CHudServers CHudServers::CHudServers( void ) { m_nRequesting = 0; - m_dStarted = 0.0; - m_nDone = 0; + m_dStarted = 0.0; + m_nDone = 0; m_pServerList = NULL; - m_pServers = NULL; + m_pServers = NULL; m_pActiveList = NULL; - m_nQuerying = 0; + m_nQuerying = 0; m_nActiveQueries = 0; - - m_fElapsed = 0.0; + m_fElapsed = 0.0; m_pPingRequest = NULL; m_pRulesRequest = NULL; @@ -1051,20 +1049,19 @@ CHudServers::~CHudServers( void ) m_nServerCount = 0; - if ( m_pPingRequest ) + if( m_pPingRequest ) { delete m_pPingRequest; m_pPingRequest = NULL; - } - - if ( m_pRulesRequest ) + + if( m_pRulesRequest ) { delete m_pRulesRequest; m_pRulesRequest = NULL; } - if ( m_pPlayersRequest ) + if( m_pPlayersRequest ) { delete m_pPlayersRequest; m_pPlayersRequest = NULL; @@ -1083,18 +1080,18 @@ ServersGetCount =================== */ -int ServersGetCount( void ) +int ServersGetCount( void ) { - if ( g_pServers ) + if( g_pServers ) { return g_pServers->GetServerCount(); } return 0; } -int ServersIsQuerying( void ) +int ServersIsQuerying( void ) { - if ( g_pServers ) + if( g_pServers ) { return g_pServers->isQuerying(); } @@ -1109,17 +1106,17 @@ ServersGetInfo */ const char *ServersGetInfo( int server ) { - if ( g_pServers ) + if( g_pServers ) { return g_pServers->GetServerInfo( server ); } - + return NULL; } void SortServers( const char *fieldname ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->SortServers( fieldname ); } @@ -1133,7 +1130,7 @@ ServersShutdown */ void ServersShutdown( void ) { - if ( g_pServers ) + if( g_pServers ) { delete g_pServers; g_pServers = NULL; @@ -1150,7 +1147,7 @@ void ServersInit( void ) { // Kill any previous instance ServersShutdown(); - + g_pServers = new CHudServers(); } @@ -1162,7 +1159,7 @@ ServersThink */ void ServersThink( double time ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->Think( time ); } @@ -1176,7 +1173,7 @@ ServersCancel */ void ServersCancel( void ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->CancelRequest(); } @@ -1191,7 +1188,7 @@ ServersList */ void ServersList( void ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->RequestList(); } @@ -1199,7 +1196,7 @@ void ServersList( void ) void BroadcastServersList( int clearpending ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->RequestBroadcastList( clearpending ); } @@ -1207,7 +1204,7 @@ void BroadcastServersList( int clearpending ) void ServerPing( int server ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->ServerPing( server ); } @@ -1215,7 +1212,7 @@ void ServerPing( int server ) void ServerRules( int server ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->ServerRules( server ); } @@ -1223,8 +1220,8 @@ void ServerRules( int server ) void ServerPlayers( int server ) { - if ( g_pServers ) + if( g_pServers ) { g_pServers->ServerPlayers( server ); } -} \ No newline at end of file +} diff --git a/cl_dll/hud_servers.h b/cl_dll/hud_servers.h index 01e94425..33fb72a5 100644 --- a/cl_dll/hud_servers.h +++ b/cl_dll/hud_servers.h @@ -33,9 +33,8 @@ void ServerPing( int server ); void ServerRules( int server ); void ServerPlayers( int server ); -int ServersGetCount( void ); +int ServersGetCount( void ); const char *ServersGetInfo( int server ); -int ServersIsQuerying( void ); +int ServersIsQuerying( void ); void SortServers( const char *fieldname ); - -#endif // HUD_SERVERSH \ No newline at end of file +#endif // HUD_SERVERSH diff --git a/cl_dll/hud_servers_priv.h b/cl_dll/hud_servers_priv.h index 73692f46..d26b3655 100644 --- a/cl_dll/hud_servers_priv.h +++ b/cl_dll/hud_servers_priv.h @@ -17,16 +17,16 @@ public: typedef struct request_s { struct request_s *next; - netadr_t remote_address; - int context; + netadr_t remote_address; + int context; } request_t; typedef struct server_s { - struct server_s *next; - netadr_t remote_address; - char *info; - int ping; + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; } server_t; CHudServers(); @@ -34,9 +34,9 @@ public: void Think( double time ); void QueryThink( void ); - int isQuerying( void ); + int isQuerying( void ); - int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); void RequestList( void ); void RequestBroadcastList( int clearpending ); @@ -47,7 +47,7 @@ public: void CancelRequest( void ); - int CompareServers( server_t *p1, server_t *p2 ); + int CompareServers( server_t *p1, server_t *p2 ); void ClearServerList( server_t **ppList ); void ClearRequestList( request_t **ppList ); @@ -58,9 +58,9 @@ public: request_t *FindRequest( int context, request_t *pList ); - int ServerListSize( void ); + int ServerListSize( void ); char *GetServerInfo( int server ); - int GetServerCount( void ); + int GetServerCount( void ); void SortServers( const char *fieldname ); void ListResponse( struct net_response_s *response ); @@ -73,26 +73,25 @@ private: server_t *GetServer( int server ); // - char m_szToken[ 1024 ]; - int m_nRequesting; - int m_nDone; + char m_szToken[1024]; + int m_nRequesting; + int m_nDone; - double m_dStarted; + double m_dStarted; request_t *m_pServerList; request_t *m_pActiveList; - server_t *m_pServers; + server_t *m_pServers; - int m_nServerCount; + int m_nServerCount; - int m_nActiveQueries; - int m_nQuerying; - double m_fElapsed; + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; - request_t *m_pPingRequest; - request_t *m_pRulesRequest; - request_t *m_pPlayersRequest; + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; }; - -#endif // HUD_SERVERS_PRIVH \ No newline at end of file +#endif // HUD_SERVERS_PRIVH diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 019c71e9..91e8fa37 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -24,17 +24,15 @@ #include "studio_util.h" #include "screenfade.h" - #pragma warning(disable: 4244) extern "C" int iJumpSpectator; extern "C" float vJumpOrigin[3]; extern "C" float vJumpAngles[3]; - -extern void V_GetInEyePos(int entity, float * origin, float * angles ); +extern void V_GetInEyePos( int entity, float * origin, float * angles ); extern void V_ResetChaseCam(); -extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); +extern void V_GetChasePos( int target, float * cl_angles, float * origin, float * angles ); extern void VectorAngles( const float *forward, float *angles ); extern "C" void NormalizeAngles( float *angles ); extern float * GetClientColor( int clientIndex ); @@ -44,53 +42,50 @@ extern vec3_t v_angles; // last view angle extern vec3_t v_cl_angles; // last client/mouse angle extern vec3_t v_sim_org; // last sim origin -void SpectatorMode(void) +void SpectatorMode( void ) { - - - if ( gEngfuncs.Cmd_Argc() <= 1 ) + if( gEngfuncs.Cmd_Argc() <= 1 ) { gEngfuncs.Con_Printf( "usage: spec_mode
[]\n" ); return; } // SetModes() will decide if command is executed on server or local - if ( gEngfuncs.Cmd_Argc() == 2 ) - gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), -1 ); + if( gEngfuncs.Cmd_Argc() == 2 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv( 1 ) ), -1 ); else if ( gEngfuncs.Cmd_Argc() == 3 ) - gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv( 1 ) ), atoi( gEngfuncs.Cmd_Argv( 2 ) ) ); } -void SpectatorSpray(void) +void SpectatorSpray( void ) { vec3_t forward; char string[128]; - if ( !gEngfuncs.IsSpectateOnly() ) + if( !gEngfuncs.IsSpectateOnly() ) return; - AngleVectors(v_angles,forward,NULL,NULL); - VectorScale(forward, 128, forward); - VectorAdd(forward, v_origin, forward); + AngleVectors( v_angles, forward, NULL, NULL ); + VectorScale( forward, 128, forward ); + VectorAdd( forward, v_origin, forward ); pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - if ( trace->fraction != 1.0 ) + if( trace->fraction != 1.0 ) { - sprintf(string, "drc_spray %.2f %.2f %.2f %i", + sprintf( string, "drc_spray %.2f %.2f %.2f %i", trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); - gEngfuncs.pfnServerCmd(string); + gEngfuncs.pfnServerCmd( string ); } - } -void SpectatorHelp(void) +void SpectatorHelp( void ) { { char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); - - if ( text ) + + if( text ) { - while ( *text ) + while( *text ) { - if ( *text != 13 ) + if( *text != 13 ) gEngfuncs.Con_Printf( "%c", *text ); text++; } @@ -100,12 +95,11 @@ void SpectatorHelp(void) void SpectatorMenu( void ) { - if ( gEngfuncs.Cmd_Argc() <= 1 ) + if( gEngfuncs.Cmd_Argc() <= 1 ) { gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); return; } - } void ToggleScores( void ) @@ -117,45 +111,43 @@ void ToggleScores( void ) //----------------------------------------------------------------------------- int CHudSpectator::Init() { - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); m_iFlags |= HUD_ACTIVE; m_flNextObserverInput = 0.0f; - m_zoomDelta = 0.0f; + m_zoomDelta = 0.0f; m_moveDelta = 0.0f; - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); - iJumpSpectator = 0; + m_chatEnabled = ( gHUD.m_SayText.m_HUD_saytext->value != 0 ); + iJumpSpectator = 0; - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + memset( &m_OverviewData, 0, sizeof(m_OverviewData) ); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities) ); m_lastPrimaryObject = m_lastSecondaryObject = 0; - gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); - gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); - gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); - gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); - gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); + gEngfuncs.pfnAddCommand( "spec_mode", SpectatorMode ); + gEngfuncs.pfnAddCommand( "spec_decal", SpectatorSpray ); + gEngfuncs.pfnAddCommand( "spec_help", SpectatorHelp ); + gEngfuncs.pfnAddCommand( "spec_menu", SpectatorMenu ); + gEngfuncs.pfnAddCommand( "togglescores", ToggleScores ); - m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); - m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); - m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); - m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); - m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); + m_drawnames = gEngfuncs.pfnRegisterVariable( "spec_drawnames", "1", 0 ); + m_drawcone = gEngfuncs.pfnRegisterVariable( "spec_drawcone", "1", 0 ); + m_drawstatus = gEngfuncs.pfnRegisterVariable( "spec_drawstatus", "1", 0 ); + m_autoDirector = gEngfuncs.pfnRegisterVariable( "spec_autodirector", "1", 0 ); + m_pip = gEngfuncs.pfnRegisterVariable( "spec_pip", "1", 0 ); - if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip) + if( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip ) { - gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); + gEngfuncs.Con_Printf( "ERROR! Couldn't register all spectator variables.\n" ); return 0; } return 1; } - //----------------------------------------------------------------------------- // UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed //----------------------------------------------------------------------------- - void UTIL_StringToVector( float * pVector, const char *pString ) { char *pstr, *pfront, tempString[128]; @@ -163,179 +155,175 @@ void UTIL_StringToVector( float * pVector, const char *pString ) strcpy( tempString, pString ); pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) + + for( j = 0; j < 3; j++ ) { pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) + + while( *pstr && *pstr != ' ' ) pstr++; - if (!*pstr) + if( !( *pstr ) ) break; pstr++; pfront = pstr; } - if (j < 2) + if( j < 2 ) { - for (j = j+1;j < 3; j++) + for( j = j + 1;j < 3; j++ ) pVector[j] = 0; } } -int UTIL_FindEntityInMap(char * name, float * origin, float * angle) +int UTIL_FindEntityInMap( char * name, float * origin, float * angle ) { - int n,found = 0; + int n, found = 0; char keyname[256]; char token[2048]; cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model - if ( !pEnt ) return 0; + if( !pEnt ) + return 0; - if ( !pEnt->model ) return 0; + if( !pEnt->model ) + return 0; char * data = pEnt->model->entities; - while (data) + while( data ) { - data = gEngfuncs.COM_ParseFile(data, token); - - if ( (token[0] == '}') || (token[0]==0) ) + data = gEngfuncs.COM_ParseFile( data, token ); + + if( ( token[0] == '}' ) || ( token[0] == 0 ) ) break; - if (!data) + if( !data ) { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + gEngfuncs.Con_DPrintf( "UTIL_FindEntityInMap: EOF without closing brace\n" ); return 0; } - if (token[0] != '{') + if( token[0] != '{' ) { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); + gEngfuncs.Con_DPrintf( "UTIL_FindEntityInMap: expected {\n" ); return 0; } - // we parse the first { now parse entities properties - - while ( 1 ) + // we parse the first { now parse entities properties + while( 1 ) { // parse key - data = gEngfuncs.COM_ParseFile(data, token); - if (token[0] == '}') + data = gEngfuncs.COM_ParseFile( data, token ); + if( token[0] == '}' ) break; // finish parsing this entity - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + if( !data ) + { + gEngfuncs.Con_DPrintf( "UTIL_FindEntityInMap: EOF without closing brace\n" ); return 0; - }; - - strcpy (keyname, token); + } + + strcpy( keyname, token ); // another hack to fix keynames with trailing spaces - n = strlen(keyname); - while (n && keyname[n-1] == ' ') + n = strlen( keyname ); + while( n && keyname[n - 1] == ' ' ) { - keyname[n-1] = 0; + keyname[n - 1] = 0; n--; } - + // parse value - data = gEngfuncs.COM_ParseFile(data, token); - if (!data) - { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); - return 0; - }; - - if (token[0] == '}') + data = gEngfuncs.COM_ParseFile( data, token ); + if( !data ) { - gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); + gEngfuncs.Con_DPrintf( "UTIL_FindEntityInMap: EOF without closing brace\n" ); + return 0; + } + + if( token[0] == '}' ) + { + gEngfuncs.Con_DPrintf( "UTIL_FindEntityInMap: closing brace without data" ); return 0; } - if (!strcmp(keyname,"classname")) + if( !strcmp( keyname, "classname" ) ) { - if (!strcmp(token, name )) + if( !strcmp( token, name ) ) { found = 1; // thats our entity } - }; + } if( !strcmp( keyname, "angle" ) ) { float y = atof( token ); - - if (y >= 0) + + if( y >= 0 ) { angle[0] = 0.0f; angle[1] = y; } - else if ((int)y == -1) + else if( (int)y == -1 ) { angle[0] = -90.0f; - angle[1] = 0.0f;; + angle[1] = 0.0f;; } else { angle[0] = 90.0f; - angle[1] = 0.0f; + angle[1] = 0.0f; } - angle[2] = 0.0f; + angle[2] = 0.0f; } if( !strcmp( keyname, "angles" ) ) { - UTIL_StringToVector(angle, token); + UTIL_StringToVector( angle, token ); } - - if (!strcmp(keyname,"origin")) - { - UTIL_StringToVector(origin, token); - }; - + if( !strcmp( keyname, "origin" ) ) + { + UTIL_StringToVector( origin, token ); + } } // while (1) - if (found) + if( found ) return 1; - } return 0; // we search all entities, but didn't found the correct - } //----------------------------------------------------------------------------- // SetSpectatorStartPosition(): // Get valid map position and 'beam' spectator to this position //----------------------------------------------------------------------------- - void CHudSpectator::SetSpectatorStartPosition() { // search for info_player start - if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) + if( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) iJumpSpectator = 1; - else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) + else if( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) iJumpSpectator = 1; - else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) + else if( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) iJumpSpectator = 1; - else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) + else if( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) iJumpSpectator = 1; else { // jump to 0,0,0 if no better position was found - VectorCopy(vec3_origin, m_cameraOrigin); - VectorCopy(vec3_origin, m_cameraAngles); + VectorCopy( vec3_origin, m_cameraOrigin ); + VectorCopy( vec3_origin, m_cameraAngles ); } - - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); + + VectorCopy( m_cameraOrigin, vJumpOrigin ); + VectorCopy( m_cameraAngles, vJumpAngles ); iJumpSpectator = 1; // jump anyway } @@ -345,15 +333,15 @@ void CHudSpectator::SetSpectatorStartPosition() //----------------------------------------------------------------------------- int CHudSpectator::VidInit() { - m_hsprPlayer = SPR_Load("sprites/iplayer.spr"); - m_hsprPlayerBlue = SPR_Load("sprites/iplayerblue.spr"); - m_hsprPlayerRed = SPR_Load("sprites/iplayerred.spr"); - m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); - m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); - m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); - m_hsprCamera = SPR_Load("sprites/camera.spr"); - m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); - + m_hsprPlayer = SPR_Load( "sprites/iplayer.spr" ); + m_hsprPlayerBlue = SPR_Load( "sprites/iplayerblue.spr" ); + m_hsprPlayerRed = SPR_Load( "sprites/iplayerred.spr" ); + m_hsprPlayerDead = SPR_Load( "sprites/iplayerdead.spr" ); + m_hsprUnkownMap = SPR_Load( "sprites/tile.spr" ); + m_hsprBeam = SPR_Load( "sprites/laserbeam.spr" ); + m_hsprCamera = SPR_Load( "sprites/camera.spr" ); + m_hCrosshair = SPR_Load( "sprites/crosshairs.spr" ); + return 1; } @@ -362,7 +350,7 @@ int CHudSpectator::VidInit() // Input : flTime - // intermission - //----------------------------------------------------------------------------- -int CHudSpectator::Draw(float flTime) +int CHudSpectator::Draw( float flTime ) { int lx; @@ -370,215 +358,192 @@ int CHudSpectator::Draw(float flTime) float * color; // draw only in spectator mode - if ( !g_iUser1 ) + if( !g_iUser1 ) return 0; // if user pressed zoom, aplly changes - if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) + if( ( m_zoomDelta != 0.0f ) && ( g_iUser1 == OBS_MAP_FREE ) ) { m_mapZoom += m_zoomDelta; - if ( m_mapZoom > 3.0f ) + if( m_mapZoom > 3.0f ) m_mapZoom = 3.0f; - if ( m_mapZoom < 0.5f ) + if( m_mapZoom < 0.5f ) m_mapZoom = 0.5f; } // if user moves in map mode, change map origin - if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) + if( ( m_moveDelta != 0.0f ) && ( g_iUser1 != OBS_ROAMING ) ) { - vec3_t right; - AngleVectors(v_angles, NULL, right, NULL); - VectorNormalize(right); - VectorScale(right, m_moveDelta, right ); + vec3_t right; + AngleVectors( v_angles, NULL, right, NULL ); + VectorNormalize( right ); + VectorScale( right, m_moveDelta, right ); VectorAdd( m_mapOrigin, right, m_mapOrigin ) - } - + // Only draw the icon names only if map mode is in Main Mode - if ( g_iUser1 < OBS_MAP_FREE ) + if( g_iUser1 < OBS_MAP_FREE ) return 1; - - if ( !m_drawnames->value ) + + if( !m_drawnames->value ) return 1; - + // make sure we have player info //gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); - - // loop through all the players and draw additional infos to their sprites on the map - for (int i = 0; i < MAX_PLAYERS; i++) + for( int i = 0; i < MAX_PLAYERS; i++ ) { - - if ( m_vPlayerPos[i][2]<0 ) // marked as invisible ? + if( m_vPlayerPos[i][2] < 0 ) // marked as invisible ? continue; - + // check if name would be in inset window - if ( m_pip->value != INSET_OFF ) + if( m_pip->value != INSET_OFF ) { - if ( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && + if( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && m_vPlayerPos[i][1] > YRES( m_OverviewData.insetWindowY ) && m_vPlayerPos[i][0] < XRES( m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth ) && - m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) - ) continue; + m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) ) + continue; } - color = GetClientColor( i+1 ); + color = GetClientColor( i + 1 ); // draw the players name and health underneath - sprintf(string, "%s", g_PlayerInfoList[i+1].name ); - - lx = strlen(string)*3; // 3 is avg. character length :) + sprintf( string, "%s", g_PlayerInfoList[i + 1].name ); + + lx = strlen( string ) * 3; // 3 is avg. character length :) DrawSetTextColor( color[0], color[1], color[2] ); - DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); - + DrawConsoleString( m_vPlayerPos[i][0] - lx,m_vPlayerPos[i][1], string ); } return 1; } - void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) { - float value; - char * string; + float value; + char *string; BEGIN_READ( pbuf, iSize ); int cmd = READ_BYTE(); - - switch ( cmd ) // director command byte - { - case DRC_CMD_START : - // now we have to do some things clientside, since the proxy doesn't know our mod - g_iPlayerClass = 0; - g_iTeamNumber = 0; - // fake a InitHUD & ResetHUD message - gHUD.MsgFunc_InitHUD(NULL,0, NULL); - gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); + switch( cmd ) // director command byte + { + case DRC_CMD_START: + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + // fake a InitHUD & ResetHUD message + gHUD.MsgFunc_InitHUD( NULL, 0, NULL ); + gHUD.MsgFunc_ResetHUD( NULL, 0, NULL ); + break; + case DRC_CMD_EVENT: + m_lastPrimaryObject = READ_WORD(); + m_lastSecondaryObject = READ_WORD(); + m_iObserverFlags = READ_LONG(); - break; + if( m_autoDirector->value ) + { + if( ( g_iUser2 != m_lastPrimaryObject) || ( g_iUser3 != m_lastSecondaryObject ) ) + V_ResetChaseCam(); - case DRC_CMD_EVENT : - m_lastPrimaryObject = READ_WORD(); - m_lastSecondaryObject = READ_WORD(); - m_iObserverFlags = READ_LONG(); - - if ( m_autoDirector->value ) - { - if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) - V_ResetChaseCam(); + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } - g_iUser2 = m_lastPrimaryObject; - g_iUser3 = m_lastSecondaryObject; - } + // gEngfuncs.Con_Printf( "Director Camera: %i %i\n", firstObject, secondObject ); + break; + case DRC_CMD_MODE: + if( m_autoDirector->value ) + { + SetModes( READ_BYTE(), -1 ); + } + break; + case DRC_CMD_CAMERA: + if( m_autoDirector->value ) + { + vJumpOrigin[0] = READ_COORD(); // position + vJumpOrigin[1] = READ_COORD(); + vJumpOrigin[2] = READ_COORD(); - // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); - break; + vJumpAngles[0] = READ_COORD(); // view angle + vJumpAngles[1] = READ_COORD(); + vJumpAngles[2] = READ_COORD(); - case DRC_CMD_MODE : - if ( m_autoDirector->value ) - { - SetModes( READ_BYTE(), -1 ); - } - break; - - case DRC_CMD_CAMERA : - if ( m_autoDirector->value ) - { - vJumpOrigin[0] = READ_COORD(); // position - vJumpOrigin[1] = READ_COORD(); - vJumpOrigin[2] = READ_COORD(); - - vJumpAngles[0] = READ_COORD(); // view angle - vJumpAngles[1] = READ_COORD(); - vJumpAngles[2] = READ_COORD(); - - gEngfuncs.SetViewAngles( vJumpAngles ); - - iJumpSpectator = 1; - } - break; + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; case DRC_CMD_MESSAGE: - { - client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + { + client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + + msg->effect = READ_BYTE(); // effect + + UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color + msg->r2 = msg->r1; + msg->g2 = msg->g1; + msg->b2 = msg->b1; + msg->a2 = msg->a1 = 0xFF; // not transparent + + msg->x = READ_FLOAT(); // x pos + msg->y = READ_FLOAT(); // y pos - msg->effect = READ_BYTE(); // effect + msg->fadein = READ_FLOAT(); // fadein + msg->fadeout = READ_FLOAT(); // fadeout + msg->holdtime = READ_FLOAT(); // holdtime + msg->fxtime = READ_FLOAT(); // fxtime; - UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color - msg->r2 = msg->r1; - msg->g2 = msg->g1; - msg->b2 = msg->b1; - msg->a2 = msg->a1 = 0xFF; // not transparent - - msg->x = READ_FLOAT(); // x pos - msg->y = READ_FLOAT(); // y pos - - msg->fadein = READ_FLOAT(); // fadein - msg->fadeout = READ_FLOAT(); // fadeout - msg->holdtime = READ_FLOAT(); // holdtime - msg->fxtime = READ_FLOAT(); // fxtime; + strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); + m_HUDMessageText[m_lastHudMessage][127] = 0; // text - strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); - m_HUDMessageText[m_lastHudMessage][127]=0; // text - - msg->pMessage = m_HUDMessageText[m_lastHudMessage]; - msg->pName = "HUD_MESSAGE"; - - gHUD.m_Message.MessageAdd( msg ); - - m_lastHudMessage++; - m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; - - } - - break; - - case DRC_CMD_SOUND : - string = READ_STRING(); - value = READ_FLOAT(); - - // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); - gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); - - break; - - case DRC_CMD_TIMESCALE : - value = READ_FLOAT(); - break; + msg->pMessage = m_HUDMessageText[m_lastHudMessage]; + msg->pName = "HUD_MESSAGE"; + gHUD.m_Message.MessageAdd( msg ); + m_lastHudMessage++; + m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; + } + break; + case DRC_CMD_SOUND: + string = READ_STRING(); + value = READ_FLOAT(); + // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); + gEngfuncs.pEventAPI->EV_PlaySound( 0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + break; + case DRC_CMD_TIMESCALE: + value = READ_FLOAT(); + break; case DRC_CMD_STATUS: - READ_LONG(); // total number of spectator slots - m_iSpectatorNumber = READ_LONG(); // total number of spectator - READ_WORD(); // total number of relay proxies - - break; - + READ_LONG(); // total number of spectator slots + m_iSpectatorNumber = READ_LONG(); // total number of spectator + READ_WORD(); // total number of relay proxies + break; case DRC_CMD_BANNER: - // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga - break; - - case DRC_CMD_FADE: - break; - + // gEngfuncs.Con_DPrintf( "GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga + break; + case DRC_CMD_FADE: + break; case DRC_CMD_STUFFTEXT: - ClientCmd( READ_STRING() ); - break; - - default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + ClientCmd( READ_STRING() ); + break; + default: + gEngfuncs.Con_DPrintf( "CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); } } -void CHudSpectator::FindNextPlayer(bool bReverse) +void CHudSpectator::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. @@ -587,23 +552,23 @@ void CHudSpectator::FindNextPlayer(bool bReverse) cl_entity_t * pEnt = NULL; // if we are NOT in HLTV mode, spectator targets are set on server - if ( !gEngfuncs.IsSpectateOnly() ) + if( !gEngfuncs.IsSpectateOnly() ) { char cmdstring[32]; // forward command to server - sprintf(cmdstring,"follownext %i",bReverse?1:0); - gEngfuncs.pfnServerCmd(cmdstring); + sprintf( cmdstring, "follownext %i", bReverse ? 1 : 0 ); + gEngfuncs.pfnServerCmd( cmdstring ); return; } - - if ( g_iUser2 ) + + if( g_iUser2 ) iStart = g_iUser2; else iStart = 1; g_iUser2 = 0; - int iCurrent = iStart; + int iCurrent = iStart; int iDir = bReverse ? -1 : 1; @@ -611,43 +576,39 @@ void CHudSpectator::FindNextPlayer(bool bReverse) //gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); - - do { iCurrent += iDir; // Loop through the clients - if (iCurrent > MAX_PLAYERS) + if( iCurrent > MAX_PLAYERS ) iCurrent = 1; - if (iCurrent < 1) + if( iCurrent < 1 ) iCurrent = MAX_PLAYERS; pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); - if ( !IsActivePlayer( pEnt ) ) + if( !IsActivePlayer( pEnt ) ) continue; // MOD AUTHORS: Add checks on target here. - g_iUser2 = iCurrent; break; - - } while ( iCurrent != iStart ); + } while( iCurrent != iStart ); // Did we find a target? - if ( !g_iUser2 ) + if( !g_iUser2 ) { gEngfuncs.Con_DPrintf( "No observer targets.\n" ); // take save camera position - VectorCopy(m_cameraOrigin, vJumpOrigin); - VectorCopy(m_cameraAngles, vJumpAngles); + VectorCopy( m_cameraOrigin, vJumpOrigin ); + VectorCopy( m_cameraAngles, vJumpAngles ); } else { // use new entity position for roaming - VectorCopy ( pEnt->origin, vJumpOrigin ); - VectorCopy ( pEnt->angles, vJumpAngles ); + VectorCopy( pEnt->origin, vJumpOrigin ); + VectorCopy( pEnt->angles, vJumpAngles ); } iJumpSpectator = 1; } @@ -656,93 +617,87 @@ void CHudSpectator::HandleButtonsDown( int ButtonPressed ) { double time = gEngfuncs.GetClientTime(); - int newMainMode = g_iUser1; - int newInsetMode = m_pip->value; + int newMainMode = g_iUser1; + int newInsetMode = m_pip->value; - // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + // gEngfuncs.Con_Printf( " HandleButtons:%i\n", ButtonPressed ); //Not in intermission. - if ( gHUD.m_iIntermission ) + if( gHUD.m_iIntermission ) return; - if ( !g_iUser1 ) + if( !g_iUser1 ) return; // dont do anything if not in spectator mode // don't handle buttons during normal demo playback - if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) return; // Slow down mouse clicks. - if ( m_flNextObserverInput > time ) + if( m_flNextObserverInput > time ) return; // enable spectator screen - //if ( ButtonPressed & IN_DUCK ) - // gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); + //if( ButtonPressed & IN_DUCK ) + // gViewPort->m_pSpectatorPanel->ShowMenu( !gViewPort->m_pSpectatorPanel->m_menuVisible ); // 'Use' changes inset window mode - if ( ButtonPressed & IN_USE ) + if( ButtonPressed & IN_USE ) { - newInsetMode = ToggleInset(true); + newInsetMode = ToggleInset( true ); } // if not in HLTV mode, buttons are handled server side - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { // changing target or chase mode not in overviewmode without inset window // Jump changes main window modes - if ( ButtonPressed & IN_JUMP ) + if( ButtonPressed & IN_JUMP ) { - if ( g_iUser1 == OBS_CHASE_LOCKED ) + if( g_iUser1 == OBS_CHASE_LOCKED ) newMainMode = OBS_CHASE_FREE; - - else if ( g_iUser1 == OBS_CHASE_FREE ) + else if( g_iUser1 == OBS_CHASE_FREE ) newMainMode = OBS_IN_EYE; - - else if ( g_iUser1 == OBS_IN_EYE ) + else if( g_iUser1 == OBS_IN_EYE ) newMainMode = OBS_ROAMING; - - else if ( g_iUser1 == OBS_ROAMING ) + else if( g_iUser1 == OBS_ROAMING ) newMainMode = OBS_MAP_FREE; - - else if ( g_iUser1 == OBS_MAP_FREE ) + else if( g_iUser1 == OBS_MAP_FREE ) newMainMode = OBS_MAP_CHASE; - else newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore } // Attack moves to the next player - if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + if( ButtonPressed & ( IN_ATTACK | IN_ATTACK2 ) ) { - FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + FindNextPlayer( ( ButtonPressed & IN_ATTACK2 ) ? true : false ); - if ( g_iUser1 == OBS_ROAMING ) + if( g_iUser1 == OBS_ROAMING ) { gEngfuncs.SetViewAngles( vJumpAngles ); iJumpSpectator = 1; - } // lease directed mode if player want to see another player m_autoDirector->value = 0.0f; } } - SetModes(newMainMode, newInsetMode); + SetModes( newMainMode, newInsetMode ); - if ( g_iUser1 == OBS_MAP_FREE ) + if( g_iUser1 == OBS_MAP_FREE ) { - if ( ButtonPressed & IN_FORWARD ) - m_zoomDelta = 0.01f; + if( ButtonPressed & IN_FORWARD ) + m_zoomDelta = 0.01f; - if ( ButtonPressed & IN_BACK ) + if( ButtonPressed & IN_BACK ) m_zoomDelta = -0.01f; - - if ( ButtonPressed & IN_MOVELEFT ) + + if( ButtonPressed & IN_MOVELEFT ) m_moveDelta = -12.0f; - if ( ButtonPressed & IN_MOVERIGHT ) - m_moveDelta = 12.0f; + if( ButtonPressed & IN_MOVERIGHT ) + m_moveDelta = 12.0f; } m_flNextObserverInput = time + 0.2; @@ -750,131 +705,129 @@ void CHudSpectator::HandleButtonsDown( int ButtonPressed ) void CHudSpectator::HandleButtonsUp( int ButtonPressed ) { - - if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) + if( ButtonPressed & ( IN_FORWARD | IN_BACK ) ) m_zoomDelta = 0.0f; - - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + + if( ButtonPressed & ( IN_MOVELEFT | IN_MOVERIGHT ) ) m_moveDelta = 0.0f; } -void CHudSpectator::SetModes(int iNewMainMode, int iNewInsetMode) +void CHudSpectator::SetModes( int iNewMainMode, int iNewInsetMode ) { // if value == -1 keep old value - if ( iNewMainMode == -1 ) + if( iNewMainMode == -1 ) iNewMainMode = g_iUser1; - if ( iNewInsetMode == -1 ) + if( iNewInsetMode == -1 ) iNewInsetMode = m_pip->value; // inset mode is handled only clients side m_pip->value = iNewInsetMode; - - if ( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) + + if( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) { - gEngfuncs.Con_Printf("Invalid spectator mode.\n"); + gEngfuncs.Con_Printf( "Invalid spectator mode.\n" ); return; } - + // main modes ettings will override inset window settings - if ( iNewMainMode != g_iUser1 ) + if( iNewMainMode != g_iUser1 ) { // if we are NOT in HLTV mode, main spectator mode is set on server - if ( !gEngfuncs.IsSpectateOnly() ) + if( !gEngfuncs.IsSpectateOnly() ) { return; } - if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + if( !g_iUser2 && ( iNewMainMode != OBS_ROAMING ) ) // make sure we have a target { // choose last Director object if still available - if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + if( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) { g_iUser2 = m_lastPrimaryObject; g_iUser3 = m_lastSecondaryObject; } else - FindNextPlayer(false); // find any target + FindNextPlayer( false ); // find any target } - switch ( iNewMainMode ) + switch( iNewMainMode ) { - case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; - break; - - case OBS_CHASE_FREE : g_iUser1 = OBS_CHASE_FREE; - break; - - case OBS_ROAMING : // jump to current vJumpOrigin/angle - g_iUser1 = OBS_ROAMING; - if ( g_iUser2 ) - { - V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); - gEngfuncs.SetViewAngles( vJumpAngles ); - iJumpSpectator = 1; - } - break; - - case OBS_IN_EYE : g_iUser1 = OBS_IN_EYE; - break; - - case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; - - case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; - // reset user values - m_mapZoom = m_OverviewData.zoom; - m_mapOrigin = m_OverviewData.origin; - break; + case OBS_CHASE_LOCKED: + g_iUser1 = OBS_CHASE_LOCKED; + break; + case OBS_CHASE_FREE: + g_iUser1 = OBS_CHASE_FREE; + break; + case OBS_ROAMING: // jump to current vJumpOrigin/angle + g_iUser1 = OBS_ROAMING; + if( g_iUser2 ) + { + V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; + case OBS_IN_EYE: + g_iUser1 = OBS_IN_EYE; + break; + case OBS_MAP_FREE: + g_iUser1 = OBS_MAP_FREE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + case OBS_MAP_CHASE: + g_iUser1 = OBS_MAP_CHASE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; } - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + if( ( g_iUser1 == OBS_IN_EYE ) || ( g_iUser1 == OBS_ROAMING ) ) { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; m_crosshairRect.bottom = 24; - + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); } else { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + memset( &m_crosshairRect, 0, sizeof(m_crosshairRect) ); SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } + } char string[128]; - sprintf(string, "#Spec_Mode%d", g_iUser1 ); - sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); - gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + sprintf( string, "#Spec_Mode%d", g_iUser1 ); + sprintf( string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string ) ); + gHUD.m_TextMessage.MsgFunc_TextMsg( NULL, strlen( string ) + 1, string ); } } -bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) +bool CHudSpectator::IsActivePlayer( cl_entity_t *ent ) { - return ( ent && - ent->player && + return ( ent && + ent->player && ent->curstate.solid != SOLID_NOT && ent != gEngfuncs.GetLocalPlayer() && g_PlayerInfoList[ent->index].name != NULL ); } - -bool CHudSpectator::ParseOverviewFile( ) +bool CHudSpectator::ParseOverviewFile() { char filename[255] = { 0 }; char levelname[255] = { 0 }; char token[1024] = { 0 }; float height; - + char *pfile = NULL; - memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewData, 0, sizeof(m_OverviewData) ); // fill in standrd values m_OverviewData.insetWindowX = 4; // upper left corner @@ -884,137 +837,129 @@ bool CHudSpectator::ParseOverviewFile( ) m_OverviewData.origin[0] = 0.0f; m_OverviewData.origin[1] = 0.0f; m_OverviewData.origin[2] = 0.0f; - m_OverviewData.zoom = 1.0f; + m_OverviewData.zoom = 1.0f; m_OverviewData.layers = 0; m_OverviewData.layersHeights[0] = 0.0f; strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); - if ( strlen( m_OverviewData.map ) == 0 ) + if( strlen( m_OverviewData.map ) == 0 ) return false; // not active yet - strcpy(levelname, m_OverviewData.map + 5); - levelname[strlen(levelname)-4] = 0; - - sprintf(filename, "overviews/%s.txt", levelname ); + strcpy( levelname, m_OverviewData.map + 5 ); + levelname[strlen( levelname ) - 4] = 0; - pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + sprintf( filename, "overviews/%s.txt", levelname ); - if (!pfile) + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL ); + + if( !pfile ) { - gEngfuncs.Con_DPrintf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + gEngfuncs.Con_DPrintf( "Couldn't open file %s. Using default values for overiew mode.\n", filename ); return false; } - - - while (true) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if (!pfile) + while( true ) + { + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + + if( !pfile ) break; - if ( !stricmp( token, "global" ) ) + if( !stricmp( token, "global" ) ) { // parse the global data - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if ( stricmp( token, "{" ) ) + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + if( stricmp( token, "{" ) ) { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + gEngfuncs.Con_Printf( "Error parsing overview file %s. (expected { )\n", filename ); return false; } - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); - while (stricmp( token, "}") ) + while( stricmp( token, "}") ) { - if ( !stricmp( token, "zoom" ) ) + if( !stricmp( token, "zoom" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.zoom = atof( token ); } - else if ( !stricmp( token, "origin" ) ) + else if( !stricmp( token, "origin" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile, token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.origin[0] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.origin[1] = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile, token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.origin[2] = atof( token ); } - else if ( !stricmp( token, "rotated" ) ) + else if( !stricmp( token, "rotated" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.rotated = atoi( token ); } - else if ( !stricmp( token, "inset" ) ) + else if( !stricmp( token, "inset" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.insetWindowX = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.insetWindowY = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.insetWindowWidth = atof( token ); - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); m_OverviewData.insetWindowHeight = atof( token ); - } else { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + gEngfuncs.Con_Printf( "Error parsing overview file %s. (%s unkown)\n", filename, token ); return false; } - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token - + pfile = gEngfuncs.COM_ParseFile( pfile, token ); // parse next token } } - else if ( !stricmp( token, "layer" ) ) + else if( !stricmp( token, "layer" ) ) { // parse a layer data - - if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) + if( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) { - gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); + gEngfuncs.Con_Printf( "Error parsing overview file %s. ( too many layers )\n", filename ); return false; } - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); - - if ( stricmp( token, "{" ) ) + if( stricmp( token, "{" ) ) { - gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + gEngfuncs.Con_Printf( "Error parsing overview file %s. (expected { )\n", filename ); return false; } - pfile = gEngfuncs.COM_ParseFile(pfile,token); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); - while (stricmp( token, "}") ) + while( stricmp( token, "}") ) { - if ( !stricmp( token, "image" ) ) + if( !stricmp( token, "image" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); - - + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + strcpy( m_OverviewData.layersImages[m_OverviewData.layers], token ); } else if ( !stricmp( token, "height" ) ) { - pfile = gEngfuncs.COM_ParseFile(pfile,token); - height = atof(token); - m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + height = atof( token ); + m_OverviewData.layersHeights[m_OverviewData.layers] = height; } else { - gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + gEngfuncs.Con_Printf( "Error parsing overview file %s. (%s unkown)\n", filename, token ); return false; } - pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + pfile = gEngfuncs.COM_ParseFile( pfile, token ); // parse next token } m_OverviewData.layers++; - } } @@ -1024,13 +969,12 @@ bool CHudSpectator::ParseOverviewFile( ) m_mapOrigin = m_OverviewData.origin; return true; - } void CHudSpectator::LoadMapSprites() { // right now only support for one map layer - if (m_OverviewData.layers > 0 ) + if( m_OverviewData.layers > 0 ) { m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); } @@ -1040,8 +984,8 @@ void CHudSpectator::LoadMapSprites() void CHudSpectator::DrawOverviewLayer() { - float screenaspect, xs, ys, xStep, yStep, x,y,z; - int ix,iy,i,xTiles,yTiles,frame; + float screenaspect, xs, ys, xStep, yStep, x, y, z; + int ix, iy, i, xTiles, yTiles, frame; qboolean hasMapImage = m_MapSprite?TRUE:FALSE; model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); @@ -1059,261 +1003,250 @@ void CHudSpectator::DrawOverviewLayer() yTiles = 6; } - - screenaspect = 4.0f/3.0f; - + screenaspect = 4.0f / 3.0f; xs = m_OverviewData.origin[0]; ys = m_OverviewData.origin[1]; z = ( 90.0f - v_angles[0] ) / 90.0f; z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; - // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); + // i = r_overviewTexture + ( layer * OVERVIEW_X_TILES * OVERVIEW_Y_TILES ); gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); gEngfuncs.pTriAPI->CullFace( TRI_NONE ); gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); frame = 0; - // rotated view ? - if ( m_OverviewData.rotated ) + if( m_OverviewData.rotated ) { - xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + xStep = ( 2 * 4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -( 2 * 4096.0f / ( m_OverviewData.zoom* screenaspect ) ) / yTiles; - y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); + y = ys + ( 4096.0f / ( m_OverviewData.zoom * screenaspect ) ); - for (iy = 0; iy < yTiles; iy++) + for( iy = 0; iy < yTiles; iy++ ) { - x = xs - (4096.0f / (m_OverviewData.zoom)); + x = xs - ( 4096.0f / (m_OverviewData.zoom ) ); - for (ix = 0; ix < xTiles; ix++) + for( ix = 0; ix < xTiles; ix++ ) { - if (hasMapImage) + if( hasMapImage ) gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); else gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); gEngfuncs.pTriAPI->Begin( TRI_QUADS ); gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); + gEngfuncs.pTriAPI->Vertex3f( x, y, z ); gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + gEngfuncs.pTriAPI->Vertex3f( x + xStep, y, z); gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + gEngfuncs.pTriAPI->Vertex3f( x + xStep, y + yStep, z ); gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->Vertex3f( x, y + yStep, z); gEngfuncs.pTriAPI->End(); frame++; - x+= xStep; + x += xStep; } - y+=yStep; + y += yStep; } } else { - xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; - yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + xStep = -( 2 * 4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -( 2 * 4096.0f / ( m_OverviewData.zoom* screenaspect ) ) / yTiles; - - x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); + x = xs + ( 4096.0f / ( m_OverviewData.zoom * screenaspect ) ); - - - for (ix = 0; ix < yTiles; ix++) + for( ix = 0; ix < yTiles; ix++ ) { - - y = ys + (4096.0f / (m_OverviewData.zoom)); - - for (iy = 0; iy < xTiles; iy++) + y = ys + ( 4096.0f / ( m_OverviewData.zoom ) ); + + for( iy = 0; iy < xTiles; iy++ ) { - if (hasMapImage) + if( hasMapImage ) gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); else gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); gEngfuncs.pTriAPI->Begin( TRI_QUADS ); gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z); + gEngfuncs.pTriAPI->Vertex3f( x, y, z ); gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + gEngfuncs.pTriAPI->Vertex3f( x + xStep, y, z); gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + gEngfuncs.pTriAPI->Vertex3f( x + xStep, y + yStep, z ); gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->Vertex3f( x, y + yStep, z ); gEngfuncs.pTriAPI->End(); frame++; - - y+=yStep; + + y += yStep; } - x+= xStep; - + x += xStep; } } } void CHudSpectator::DrawOverviewEntities() { - int i,ir,ig,ib; + int i, ir, ig, ib; struct model_s *hSpriteModel; vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; - float x,y,z, r,g,b, sizeScale = 4.0f; + float x, y, z, r, g, b, sizeScale = 4.0f; cl_entity_t * ent; float rmatrix[3][4]; // transformation matrix - - float zScale = (90.0f - v_angles[0] ) / 90.0f; - + + float zScale = ( 90.0f - v_angles[0] ) / 90.0f; z = m_OverviewData.layersHeights[0] * zScale; // get yellow/brown HUD color - UnpackRGB(ir,ig,ib, RGB_YELLOWISH); - r = (float)ir/255.0f; - g = (float)ig/255.0f; - b = (float)ib/255.0f; - + UnpackRGB( ir, ig, ib, RGB_YELLOWISH ); + r = (float)ir / 255.0f; + g = (float)ig / 255.0f; + b = (float)ib / 255.0f; + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - for (i=0; i < MAX_PLAYERS; i++ ) + for( i = 0; i < MAX_PLAYERS; i++ ) m_vPlayerPos[i][2] = -1; // mark as invisible // draw all players - for (i=0 ; i < MAX_OVERVIEW_ENTITIES ; i++) + for( i = 0; i < MAX_OVERVIEW_ENTITIES; i++ ) { - if ( !m_OverviewEntities[i].hSprite ) + if( !m_OverviewEntities[i].hSprite ) continue; hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); ent = m_OverviewEntities[i].entity; - + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); // see R_DrawSpriteModel // draws players sprite + AngleVectors( ent->angles, right, up, NULL ); - AngleVectors(ent->angles, right, up, NULL ); - - VectorCopy(ent->origin,origin); + VectorCopy( ent->origin,origin ); gEngfuncs.pTriAPI->Begin( TRI_QUADS ); gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); - - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); + + gEngfuncs.pTriAPI->TexCoord2f(1, 0); + VectorMA( origin, 16.0f * sizeScale, up, point ); + VectorMA( point, 16.0f * sizeScale, right, point ); point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); + gEngfuncs.pTriAPI->Vertex3fv( point ); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - - VectorMA (origin, 16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + + VectorMA( origin, 16.0f * sizeScale, up, point ); + VectorMA( point, -16.0f * sizeScale, right, point ); point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); + gEngfuncs.pTriAPI->Vertex3fv( point ); - gEngfuncs.pTriAPI->TexCoord2f (0,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, -16.0f * sizeScale, right, point); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + VectorMA( origin, -16.0f * sizeScale, up, point ); + VectorMA( point, -16.0f * sizeScale, right, point ); point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); + gEngfuncs.pTriAPI->Vertex3fv( point ); - gEngfuncs.pTriAPI->TexCoord2f (1,1); - VectorMA (origin, -16.0f * sizeScale, up, point); - VectorMA (point, 16.0f * sizeScale, right, point); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + VectorMA( origin, -16.0f * sizeScale, up, point ); + VectorMA( point, 16.0f * sizeScale, right, point ); point[2] *= zScale; - gEngfuncs.pTriAPI->Vertex3fv (point); + gEngfuncs.pTriAPI->Vertex3fv( point ); - gEngfuncs.pTriAPI->End (); + gEngfuncs.pTriAPI->End(); - - if ( !ent->player) + if( !ent->player ) continue; + // draw line under player icons origin[2] *= zScale; gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); + gEngfuncs.pTriAPI->Color4f( r, g, b, 0.3 ); - gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f (1, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 0); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); - gEngfuncs.pTriAPI->TexCoord2f (0, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); - gEngfuncs.pTriAPI->TexCoord2f (1, 1); - gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); - gEngfuncs.pTriAPI->End (); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] + 4, origin[1] + 4, origin[2] - zScale ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] - 4, origin[1] - 4, origin[2] - zScale ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] - 4, origin[1] - 4, z ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] + 4, origin[1] + 4, z ); + gEngfuncs.pTriAPI->End(); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] - 4, origin[1] + 4, origin[2] - zScale ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] + 4, origin[1] - 4, origin[2] - zScale ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] + 4, origin[1] - 4, z ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( origin[0] - 4, origin[1] + 4, z ); + gEngfuncs.pTriAPI->End(); // calculate screen position for name and infromation in hud::draw() - if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) + if( gEngfuncs.pTriAPI->WorldToScreen( origin, screen ) ) continue; // object is behind viewer - screen[0] = XPROJECT(screen[0]); - screen[1] = YPROJECT(screen[1]); + screen[0] = XPROJECT( screen[0] ); + screen[1] = YPROJECT( screen[1] ); screen[2] = 0.0f; // calculate some offset under the icon - origin[0]+=32.0f; - origin[1]+=32.0f; - - gEngfuncs.pTriAPI->WorldToScreen(origin,offset); + origin[0] += 32.0f; + origin[1] += 32.0f; - offset[0] = XPROJECT(offset[0]); - offset[1] = YPROJECT(offset[1]); + gEngfuncs.pTriAPI->WorldToScreen( origin, offset ); + + offset[0] = XPROJECT( offset[0] ); + offset[1] = YPROJECT( offset[1] ); offset[2] = 0.0f; - - VectorSubtract(offset, screen, offset ); + + VectorSubtract( offset, screen, offset ); int playerNum = ent->index - 1; m_vPlayerPos[playerNum][0] = screen[0]; - m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); + m_vPlayerPos[playerNum][1] = screen[1] + Length( offset ); m_vPlayerPos[playerNum][2] = 1; // mark player as visible } - if ( !m_pip->value || !m_drawcone->value ) + if( !m_pip->value || !m_drawcone->value ) return; // get current camera position and angle - - if ( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) - { + if( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) + { V_GetInEyePos( g_iUser2, origin, angles ); } - else if ( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) + else if( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) { V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); } - else if ( g_iUser1 == OBS_ROAMING ) + else if( g_iUser1 == OBS_ROAMING ) { VectorCopy( v_sim_org, origin ); VectorCopy( v_cl_angles, angles ); @@ -1321,9 +1254,7 @@ void CHudSpectator::DrawOverviewEntities() else V_GetChasePos( g_iUser2, NULL, origin, angles ); - // draw camera sprite - x = origin[0]; y = origin[1]; z = origin[2]; @@ -1333,39 +1264,35 @@ void CHudSpectator::DrawOverviewEntities() hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); - - + gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); - AngleVectors(angles, forward, NULL, NULL ); - VectorScale (forward, 512.0f, forward); - - offset[0] = 0.0f; - offset[1] = 45.0f; - offset[2] = 0.0f; + AngleVectors( angles, forward, NULL, NULL ); + VectorScale( forward, 512.0f, forward ); - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , right ); + offset[0] = 0.0f; + offset[1] = 45.0f; + offset[2] = 0.0f; + + AngleMatrix( offset, rmatrix ); + VectorTransform( forward, rmatrix, right ); offset[1]= -45.0f; - AngleMatrix(offset, rmatrix ); - VectorTransform(forward, rmatrix , left ); + AngleMatrix( offset, rmatrix ); + VectorTransform( forward, rmatrix , left ); - gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); + gEngfuncs.pTriAPI->Begin( TRI_TRIANGLES ); gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); + gEngfuncs.pTriAPI->Vertex3f( x + right[0], y + right[1], ( z + right[2] ) * zScale); gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); - + gEngfuncs.pTriAPI->Vertex3f( x, y, z * zScale ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); + gEngfuncs.pTriAPI->Vertex3f( x + left[0], y + left[1], ( z + left[2] ) * zScale ); gEngfuncs.pTriAPI->End (); - } - - void CHudSpectator::DrawOverview() { // draw only in sepctator mode @@ -1373,7 +1300,7 @@ void CHudSpectator::DrawOverview() return; // Only draw the overview if Map Mode is selected for this view - if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) + if( m_iDrawCycle == 0 && ( ( g_iUser1 != OBS_MAP_FREE ) && ( g_iUser1 != OBS_MAP_CHASE ) ) ) return; if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) @@ -1383,17 +1310,18 @@ void CHudSpectator::DrawOverview() DrawOverviewEntities(); CheckOverviewEntities(); } + void CHudSpectator::CheckOverviewEntities() { double time = gEngfuncs.GetClientTime(); // removes old entities from list - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + for( int i = 0; i < MAX_OVERVIEW_ENTITIES; i++ ) { // remove entity from list if it is too old - if ( m_OverviewEntities[i].killTime < time ) + if( m_OverviewEntities[i].killTime < time ) { - memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); + memset( &m_OverviewEntities[i], 0, sizeof(overviewEntity_t) ); } } } @@ -1403,49 +1331,55 @@ bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const HSPRITE hSprite = 0; double duration = -1.0f; // duration -1 means show it only this frame; - if ( !ent ) + if( !ent ) return false; - if ( type == ET_PLAYER ) + if( type == ET_PLAYER ) { - if ( ent->curstate.solid != SOLID_NOT) + if( ent->curstate.solid != SOLID_NOT) { switch ( g_PlayerExtraInfo[ent->index].teamnumber ) { // blue and red teams are swapped in CS and TFC - case 1 : hSprite = m_hsprPlayerBlue; break; - case 2 : hSprite = m_hsprPlayerRed; break; - default : hSprite = m_hsprPlayer; break; + case 1: + hSprite = m_hsprPlayerBlue; + break; + case 2: + hSprite = m_hsprPlayerRed; + break; + default: + hSprite = m_hsprPlayer; + break; } } else return false; // it's an spectator } - else if (type == ET_NORMAL) + else if( type == ET_NORMAL ) { return false; } else - return false; + return false; - return AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration ); + return AddOverviewEntityToList( hSprite, ent, gEngfuncs.GetClientTime() + duration ); } -void CHudSpectator::DeathMessage(int victim) +void CHudSpectator::DeathMessage( int victim ) { // find out where the victim is - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( victim ); - if (pl && pl->player) + if( pl && pl->player ) AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); } bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) { - for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + for( int i = 0; i < MAX_OVERVIEW_ENTITIES; i++ ) { // find empty entity slot - if ( m_OverviewEntities[i].entity == NULL) + if( m_OverviewEntities[i].entity == NULL) { m_OverviewEntities[i].entity = ent; m_OverviewEntities[i].hSprite = sprite; @@ -1456,93 +1390,91 @@ bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, do return false; // maximum overview entities reached } + void CHudSpectator::CheckSettings() { // disallow same inset mode as main mode: - m_pip->value = (int)m_pip->value; - if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) + if( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) { // otherwise both would show in World picures m_pip->value = INSET_MAP_FREE; } - if ( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) + if( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) { // both would show map views m_pip->value = INSET_CHASE_FREE; } // disble in intermission screen - if ( gHUD.m_iIntermission ) + if( gHUD.m_iIntermission ) m_pip->value = INSET_OFF; // check chat mode - if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) + if( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value != 0) ) { // hud_saytext changed - m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + m_chatEnabled = ( gHUD.m_SayText.m_HUD_saytext->value != 0 ); - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { // tell proxy our new chat mode char chatcmd[32]; - sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); - gEngfuncs.pfnServerCmd(chatcmd); + sprintf( chatcmd, "ignoremsg %i", m_chatEnabled ? 0 : 1 ); + gEngfuncs.pfnServerCmd( chatcmd ); } } // HL/TFC has no oberserver corsshair, so set it client side - if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + if( ( g_iUser1 == OBS_IN_EYE ) || ( g_iUser1 == OBS_ROAMING ) ) { - m_crosshairRect.left = 24; - m_crosshairRect.top = 0; - m_crosshairRect.right = 48; + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; m_crosshairRect.bottom = 24; SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); } else { - memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + memset( &m_crosshairRect, 0, sizeof(m_crosshairRect) ); SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); - } - - + } // if we are a real player on server don't allow inset window // in First Person mode since this is our resticted forcecamera mode 2 // team number 3 = SPECTATOR see player.h - if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) + if( ( ( g_iTeamNumber == 1 ) || ( g_iTeamNumber == 2 ) ) && ( g_iUser1 == OBS_IN_EYE ) ) m_pip->value = INSET_OFF; // draw small border around inset view, adjust upper black bar } -int CHudSpectator::ToggleInset(bool allowOff) +int CHudSpectator::ToggleInset( bool allowOff ) { int newInsetMode = (int)m_pip->value + 1; - if ( g_iUser1 < OBS_MAP_FREE ) + if( g_iUser1 < OBS_MAP_FREE ) { - if ( newInsetMode > INSET_MAP_CHASE ) + if( newInsetMode > INSET_MAP_CHASE ) { - if (allowOff) + if( allowOff ) newInsetMode = INSET_OFF; else newInsetMode = INSET_MAP_FREE; } - if ( newInsetMode == INSET_CHASE_FREE ) + if( newInsetMode == INSET_CHASE_FREE ) newInsetMode = INSET_MAP_FREE; } else { - if ( newInsetMode > INSET_IN_EYE ) + if( newInsetMode > INSET_IN_EYE ) { - if (allowOff) + if( allowOff ) newInsetMode = INSET_OFF; else newInsetMode = INSET_CHASE_FREE; @@ -1551,17 +1483,18 @@ int CHudSpectator::ToggleInset(bool allowOff) return newInsetMode; } + void CHudSpectator::Reset() { // Reset HUD - if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) + if( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) { // update level overview if level changed ParseOverviewFile(); LoadMapSprites(); } - memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities) ); SetSpectatorStartPosition(); } @@ -1572,13 +1505,13 @@ void CHudSpectator::InitHUDData() m_flNextObserverInput = 0.0f; m_lastHudMessage = 0; m_iSpectatorNumber = 0; - iJumpSpectator = 0; + iJumpSpectator = 0; g_iUser1 = g_iUser2 = 0; memset( &m_OverviewData, 0, sizeof(m_OverviewData)); memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); - if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) + if( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) m_autoDirector->value = 1.0f; else m_autoDirector->value = 0.0f; @@ -1590,6 +1523,5 @@ void CHudSpectator::InitHUDData() g_iUser2 = 0; // fake not target until first camera command // reset HUD FOV - gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); + gHUD.m_iFOV = CVAR_GET_FLOAT( "default_fov" ); } - diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 11c7c34c..f60353db 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -11,17 +11,13 @@ #include "cl_entity.h" - - -#define INSET_OFF 0 +#define INSET_OFF 0 #define INSET_CHASE_FREE 1 #define INSET_IN_EYE 2 #define INSET_MAP_FREE 3 #define INSET_MAP_CHASE 4 -#define MAX_SPEC_HUD_MESSAGES 8 - - +#define MAX_SPEC_HUD_MESSAGES 8 #define OVERVIEW_TILE_SIZE 128 // don't change this #define OVERVIEW_MAX_LAYERS 1 @@ -30,23 +26,24 @@ // Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) //----------------------------------------------------------------------------- -typedef struct overviewInfo_s { +typedef struct overviewInfo_s +{ char map[64]; // cl.levelname or empty vec3_t origin; // center of map float zoom; // zoom of map images - int layers; // how may layers do we have + int layers; // how may layers do we have float layersHeights[OVERVIEW_MAX_LAYERS]; char layersImages[OVERVIEW_MAX_LAYERS][255]; qboolean rotated; // are map images rotated (90 degrees) ? - - int insetWindowX; - int insetWindowY; - int insetWindowHeight; - int insetWindowWidth; + + int insetWindowX; + int insetWindowY; + int insetWindowHeight; + int insetWindowWidth; } overviewInfo_t; -typedef struct overviewEntity_s { - +typedef struct overviewEntity_s +{ HSPRITE hSprite; struct cl_entity_s * entity; double killTime; @@ -58,11 +55,11 @@ class CHudSpectator : public CHudBase { public: void Reset(); - int ToggleInset(bool allowOff); + int ToggleInset( bool allowOff ); void CheckSettings(); void InitHUDData( void ); - bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime); - void DeathMessage(int victim); + bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime ); + void DeathMessage( int victim ); bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); void CheckOverviewEntities(); void DrawOverview(); @@ -71,42 +68,40 @@ public: void DrawOverviewLayer(); void LoadMapSprites(); bool ParseOverviewFile(); - bool IsActivePlayer(cl_entity_t * ent); - void SetModes(int iMainMode, int iInsetMode); - void HandleButtonsDown(int ButtonPressed); - void HandleButtonsUp(int ButtonPressed); + bool IsActivePlayer( cl_entity_t * ent ); + void SetModes( int iMainMode, int iInsetMode ); + void HandleButtonsDown( int ButtonPressed ); + void HandleButtonsUp( int ButtonPressed ); void FindNextPlayer( bool bReverse ); void DirectorMessage( int iSize, void *pbuf ); void SetSpectatorStartPosition(); int Init(); int VidInit(); - int Draw(float flTime); + int Draw( float flTime ); int m_iDrawCycle; - client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; - char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; - int m_lastHudMessage; + client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; + char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; + int m_lastHudMessage; overviewInfo_t m_OverviewData; overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; - int m_iObserverFlags; - int m_iSpectatorNumber; - - float m_mapZoom; // zoom the user currently uses - vec3_t m_mapOrigin; // origin where user rotates around - cvar_t * m_drawnames; - cvar_t * m_drawcone; - cvar_t * m_drawstatus; - cvar_t * m_autoDirector; - cvar_t * m_pip; - + int m_iObserverFlags; + int m_iSpectatorNumber; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + cvar_t *m_drawnames; + cvar_t *m_drawcone; + cvar_t *m_drawstatus; + cvar_t *m_autoDirector; + cvar_t *m_pip; qboolean m_chatEnabled; vec3_t m_cameraOrigin; // a help camera vec3_t m_cameraAngles; // and it's angles - private: vec3_t m_vPlayerPos[MAX_PLAYERS]; HSPRITE m_hsprPlayerBlue; @@ -121,12 +116,11 @@ private: wrect_t m_crosshairRect; - struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame + struct model_s *m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame float m_flNextObserverInput; float m_zoomDelta; float m_moveDelta; - int m_lastPrimaryObject; - int m_lastSecondaryObject; + int m_lastPrimaryObject; + int m_lastSecondaryObject; }; - #endif // SPECTATOR_H diff --git a/cl_dll/hud_update.cpp b/cl_dll/hud_update.cpp index 9facc8c7..cecbb625 100644 --- a/cl_dll/hud_update.cpp +++ b/cl_dll/hud_update.cpp @@ -29,11 +29,11 @@ extern float v_idlescale; float in_fov; extern void HUD_SetCmdBits( int bits ); -int CHud::UpdateClientData(client_data_t *cdata, float time) +int CHud::UpdateClientData( client_data_t *cdata, float time ) { - memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); - memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); - + memcpy( m_vecOrigin, cdata->origin, sizeof(vec3_t) ); + memcpy( m_vecAngles, cdata->viewangles, sizeof(vec3_t) ); + m_iKeyBits = CL_ButtonBits( 0 ); m_iWeaponBits = cdata->iWeaponBits; @@ -42,7 +42,7 @@ int CHud::UpdateClientData(client_data_t *cdata, float time) Think(); cdata->fov = m_iFOV; - + v_idlescale = m_iConcussionEffect; CL_ResetButtonBits( m_iKeyBits ); @@ -50,5 +50,3 @@ int CHud::UpdateClientData(client_data_t *cdata, float time) // return 1 if in anything in the client_data struct has been changed, 0 otherwise return 1; } - - diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp index fb6a6735..92051afe 100644 --- a/cl_dll/in_camera.cpp +++ b/cl_dll/in_camera.cpp @@ -15,10 +15,9 @@ #include "camera.h" #include "in_defs.h" +float CL_KeyState( kbutton_t *key ); -float CL_KeyState (kbutton_t *key); - -extern "C" +extern "C" { void DLLEXPORT CAM_Think( void ); int DLLEXPORT CL_IsThirdPerson( void ); @@ -66,15 +65,14 @@ cvar_t *c_mindistance; // pitch, yaw, dist vec3_t cam_ofs; - // In third person int cam_thirdperson; int cam_mousemove; //true if we are moving the cam with the mouse, False if not -int iMouseInUse=0; +int iMouseInUse = 0; int cam_distancemove; extern int mouse_x, mouse_y; //used to determine what the current x and y values are int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement -POINT cam_mouse; +POINT cam_mouse; //-------------------------------------------------- Local Variables static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; @@ -87,7 +85,6 @@ void CAM_ToFirstPerson(void); void CAM_StartDistance(void); void CAM_EndDistance(void); - //-------------------------------------------------- Local Functions float MoveToward( float cur, float goal, float maxspeed ) @@ -118,7 +115,6 @@ float MoveToward( float cur, float goal, float maxspeed ) } } - // bring cur back into range if( cur < 0 ) cur += 360.0; @@ -128,7 +124,6 @@ float MoveToward( float cur, float goal, float maxspeed ) return cur; } - //-------------------------------------------------- Gobal Functions typedef struct @@ -138,12 +133,12 @@ typedef struct vec3_t mins2, maxs2; // size when clipping against mosnters float *start, *end; trace_t trace; - int type; + int type; edict_t *passedict; qboolean monsterclip; } moveclip_t; -extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); +extern trace_t SV_ClipMoveToEntity( edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end ); void DLLEXPORT CAM_Think( void ) { @@ -158,16 +153,14 @@ void DLLEXPORT CAM_Think( void ) #endif vec3_t viewangles; - switch( (int) cam_command->value ) + switch( (int)cam_command->value ) { case CAM_COMMAND_TOTHIRDPERSON: CAM_ToThirdPerson(); break; - case CAM_COMMAND_TOFIRSTPERSON: CAM_ToFirstPerson(); break; - case CAM_COMMAND_NONE: default: break; @@ -175,113 +168,108 @@ void DLLEXPORT CAM_Think( void ) if( !cam_thirdperson ) return; - #ifdef LATER - if ( cam_contain->value ) + if( cam_contain->value ) { gEngfuncs.GetClientOrigin( origin ); ext[0] = ext[1] = ext[2] = 0.0; } #endif - - camAngles[ PITCH ] = cam_idealpitch->value; - camAngles[ YAW ] = cam_idealyaw->value; + camAngles[PITCH] = cam_idealpitch->value; + camAngles[YAW] = cam_idealyaw->value; dist = cam_idealdist->value; + // //movement of the camera with the mouse // - if (cam_mousemove) + if( cam_mousemove ) { - //get windows cursor position - GetCursorPos (&cam_mouse); + //get windows cursor position + GetCursorPos( &cam_mouse ); + //check for X delta values and adjust accordingly //eventually adjust YAW based on amount of movement - //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera - if (!cam_distancemove) - { - - //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) - if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) + //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera + if( !cam_distancemove ) { - //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) - if (camAngles[YAW]value) + //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) + if( cam_mouse.x>gEngfuncs.GetWindowCenterX() ) { - camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); + //if( ( camAngles[YAW] >= 225.0 ) || ( camAngles[YAW] < 135.0 ) ) + if( camAngles[YAW] < c_maxyaw->value ) + { + camAngles[YAW] += CAM_ANGLE_MOVE * ( ( cam_mouse.x - gEngfuncs.GetWindowCenterX() ) / 2 ); + } + if( camAngles[YAW] > c_maxyaw->value ) + { + camAngles[YAW] = c_maxyaw->value; + } } - if (camAngles[YAW]>c_maxyaw->value) + else if( cam_mouse.xvalue; + //if( ( camAngles[YAW] <= 135.0 ) || ( camAngles[YAW] > 225.0 ) ) + if( camAngles[YAW] > c_minyaw->value ) + { + camAngles[YAW] -= CAM_ANGLE_MOVE * ( ( gEngfuncs.GetWindowCenterX() - cam_mouse.x ) / 2 ); + } + if( camAngles[YAW] < c_minyaw->value ) + { + camAngles[YAW] = c_minyaw->value; + } } - } - else if (cam_mouse.x225.0)) - if (camAngles[YAW]>c_minyaw->value) - { - camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); - - } - if (camAngles[YAW]value) - { - camAngles[YAW]=c_minyaw->value; - - } - } - //check for y delta values and adjust accordingly - //eventually adjust PITCH based on amount of movement - //also make sure camera is within bounds - if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) - { - if(camAngles[PITCH]value) + //check for y delta values and adjust accordingly + //eventually adjust PITCH based on amount of movement + //also make sure camera is within bounds + if( cam_mouse.y>gEngfuncs.GetWindowCenterY() ) { - camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + if( camAngles[PITCH] < c_maxpitch->value ) + { + camAngles[PITCH] += CAM_ANGLE_MOVE * ( ( cam_mouse.y - gEngfuncs.GetWindowCenterY() ) / 2 ); + } + if( camAngles[PITCH] > c_maxpitch->value ) + { + camAngles[PITCH] = c_maxpitch->value; + } } - if (camAngles[PITCH]>c_maxpitch->value) + else if( cam_mouse.yvalue; + if( camAngles[PITCH] > c_minpitch->value ) + { + camAngles[PITCH] -= CAM_ANGLE_MOVE * ( ( gEngfuncs.GetWindowCenterY() - cam_mouse.y ) / 2 ); + } + if( camAngles[PITCH] < c_minpitch->value ) + { + camAngles[PITCH] = c_minpitch->value; + } } - } - else if (cam_mouse.yc_minpitch->value) - { - camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); - } - if (camAngles[PITCH]value) - { - camAngles[PITCH]=c_minpitch->value; - } - } - //set old mouse coordinates to current mouse coordinates - //since we are done with the mouse - - if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) - { - cam_old_mouse_x=cam_mouse.x*flSensitivity; - cam_old_mouse_y=cam_mouse.y*flSensitivity; + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + if( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x = cam_mouse.x * flSensitivity; + cam_old_mouse_y = cam_mouse.y * flSensitivity; + } + else + { + cam_old_mouse_x = cam_mouse.x; + cam_old_mouse_y = cam_mouse.y; + } + SetCursorPos( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); } - else - { - cam_old_mouse_x=cam_mouse.x; - cam_old_mouse_y=cam_mouse.y; - } - SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); - } } //Nathan code here if( CL_KeyState( &cam_pitchup ) ) - camAngles[ PITCH ] += CAM_ANGLE_DELTA; + camAngles[PITCH] += CAM_ANGLE_DELTA; else if( CL_KeyState( &cam_pitchdown ) ) - camAngles[ PITCH ] -= CAM_ANGLE_DELTA; + camAngles[PITCH] -= CAM_ANGLE_DELTA; if( CL_KeyState( &cam_yawleft ) ) - camAngles[ YAW ] -= CAM_ANGLE_DELTA; + camAngles[YAW] -= CAM_ANGLE_DELTA; else if( CL_KeyState( &cam_yawright ) ) - camAngles[ YAW ] += CAM_ANGLE_DELTA; + camAngles[YAW] += CAM_ANGLE_DELTA; if( CL_KeyState( &cam_in ) ) { @@ -289,44 +277,43 @@ void DLLEXPORT CAM_Think( void ) if( dist < CAM_MIN_DIST ) { // If we go back into first person, reset the angle - camAngles[ PITCH ] = 0; - camAngles[ YAW ] = 0; + camAngles[PITCH] = 0; + camAngles[YAW] = 0; dist = CAM_MIN_DIST; } - } else if( CL_KeyState( &cam_out ) ) dist += CAM_DIST_DELTA; - if (cam_distancemove) + if( cam_distancemove ) { - if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + if( cam_mouse.y > gEngfuncs.GetWindowCenterY() ) { - if(distvalue) + if( dist < c_maxdistance->value ) { - dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + dist += CAM_DIST_DELTA * ( ( cam_mouse.y - gEngfuncs.GetWindowCenterY() ) / 2); } - if (dist>c_maxdistance->value) + if( dist > c_maxdistance->value ) { - dist=c_maxdistance->value; + dist = c_maxdistance->value; } } - else if (cam_mouse.yc_mindistance->value) + if( dist > c_mindistance->value ) { - dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + dist -= CAM_DIST_DELTA * ( ( gEngfuncs.GetWindowCenterY() - cam_mouse.y ) / 2 ); } - if (distvalue) + if ( dist < c_mindistance->value ) { - dist=c_mindistance->value; + dist = c_mindistance->value; } } //set old mouse coordinates to current mouse coordinates //since we are done with the mouse - cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); - cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); - SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + cam_old_mouse_x = cam_mouse.x * gHUD.GetSensitivity(); + cam_old_mouse_y = cam_mouse.y * gHUD.GetSensitivity(); + SetCursorPos( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); } #ifdef LATER if( cam_contain->value ) @@ -334,17 +321,17 @@ void DLLEXPORT CAM_Think( void ) // check new ideal VectorCopy( origin, pnt ); AngleVectors( camAngles, camForward, camRight, camUp ); - for (i=0 ; i<3 ; i++) - pnt[i] += -dist*camForward[i]; + for( i = 0; i < 3; i++ ) + pnt[i] += -dist * camForward[i]; // check line from r_refdef.vieworg to pnt - memset ( &clip, 0, sizeof ( moveclip_t ) ); + memset( &clip, 0, sizeof(moveclip_t) ); clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); if( clip.trace.fraction == 1.0 ) { // update ideal - cam_idealpitch->value = camAngles[ PITCH ]; - cam_idealyaw->value = camAngles[ YAW ]; + cam_idealpitch->value = camAngles[PITCH]; + cam_idealyaw->value = camAngles[YAW]; cam_idealdist->value = dist; } } @@ -352,8 +339,8 @@ void DLLEXPORT CAM_Think( void ) #endif { // update ideal - cam_idealpitch->value = camAngles[ PITCH ]; - cam_idealyaw->value = camAngles[ YAW ]; + cam_idealpitch->value = camAngles[PITCH]; + cam_idealyaw->value = camAngles[YAW]; cam_idealdist->value = dist; } @@ -364,91 +351,136 @@ void DLLEXPORT CAM_Think( void ) if( cam_snapto->value ) { - camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; - camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; - camAngles[ 2 ] = cam_idealdist->value; + camAngles[YAW] = cam_idealyaw->value + viewangles[YAW]; + camAngles[PITCH] = cam_idealpitch->value + viewangles[PITCH]; + camAngles[2] = cam_idealdist->value; } else { - if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) - camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); + if( camAngles[YAW] - viewangles[YAW] != cam_idealyaw->value ) + camAngles[YAW] = MoveToward( camAngles[YAW], cam_idealyaw->value + viewangles[YAW], CAM_ANGLE_SPEED ); - if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) - camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); + if( camAngles[PITCH] - viewangles[PITCH] != cam_idealpitch->value ) + camAngles[PITCH] = MoveToward( camAngles[PITCH], cam_idealpitch->value + viewangles[PITCH], CAM_ANGLE_SPEED ); - if( fabs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) - camAngles[ 2 ] = cam_idealdist->value; + if( fabs( camAngles[2] - cam_idealdist->value ) < 2.0 ) + camAngles[2] = cam_idealdist->value; else - camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; + camAngles[2] += ( cam_idealdist->value - camAngles[2] ) / 4.0; } #ifdef LATER if( cam_contain->value ) { // Test new position - dist = camAngles[ ROLL ]; - camAngles[ ROLL ] = 0; + dist = camAngles[ROLL]; + camAngles[ROLL] = 0; VectorCopy( origin, pnt ); AngleVectors( camAngles, camForward, camRight, camUp ); - for (i=0 ; i<3 ; i++) - pnt[i] += -dist*camForward[i]; + for( i = 0; i < 3; i++ ) + pnt[i] += -dist * camForward[i]; // check line from r_refdef.vieworg to pnt - memset ( &clip, 0, sizeof ( moveclip_t ) ); + memset( &clip, 0, sizeof(moveclip_t) ); ext[0] = ext[1] = ext[2] = 0.0; clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); if( clip.trace.fraction != 1.0 ) return; } #endif - cam_ofs[ 0 ] = camAngles[ 0 ]; - cam_ofs[ 1 ] = camAngles[ 1 ]; - cam_ofs[ 2 ] = dist; + cam_ofs[0] = camAngles[0]; + cam_ofs[1] = camAngles[1]; + cam_ofs[2] = dist; } -extern void KeyDown (kbutton_t *b); // HACK -extern void KeyUp (kbutton_t *b); // HACK +extern void KeyDown( kbutton_t *b ); // HACK +extern void KeyUp( kbutton_t *b ); // HACK -void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } -void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } -void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } -void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } -void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } -void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } -void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } -void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } -void CAM_InDown(void) { KeyDown( &cam_in ); } -void CAM_InUp(void) { KeyUp( &cam_in ); } -void CAM_OutDown(void) { KeyDown( &cam_out ); } -void CAM_OutUp(void) { KeyUp( &cam_out ); } +void CAM_PitchUpDown( void ) +{ + KeyDown( &cam_pitchup ); +} -void CAM_ToThirdPerson(void) -{ +void CAM_PitchUpUp( void ) +{ + KeyUp( &cam_pitchup ); +} + +void CAM_PitchDownDown( void ) +{ + KeyDown( &cam_pitchdown ); +} + +void CAM_PitchDownUp( void ) +{ + KeyUp( &cam_pitchdown ); +} + +void CAM_YawLeftDown( void ) +{ + KeyDown( &cam_yawleft ); +} + +void CAM_YawLeftUp( void ) +{ + KeyUp( &cam_yawleft ); +} + +void CAM_YawRightDown( void ) +{ + KeyDown( &cam_yawright ); +} + +void CAM_YawRightUp( void ) +{ + KeyUp( &cam_yawright ); +} + +void CAM_InDown( void ) +{ + KeyDown( &cam_in ); +} + +void CAM_InUp( void ) +{ + KeyUp( &cam_in ); +} + +void CAM_OutDown( void ) +{ + KeyDown( &cam_out ); +} + +void CAM_OutUp( void ) +{ + KeyUp( &cam_out ); +} + +void CAM_ToThirdPerson( void ) +{ vec3_t viewangles; - #if !defined( _DEBUG ) - if ( gEngfuncs.GetMaxClients() > 1 ) + if( gEngfuncs.GetMaxClients() > 1 ) { // no thirdperson in multiplayer. return; } #endif - gEngfuncs.GetViewAngles( (float *)viewangles ); if( !cam_thirdperson ) { cam_thirdperson = 1; - - cam_ofs[ YAW ] = viewangles[ YAW ]; - cam_ofs[ PITCH ] = viewangles[ PITCH ]; - cam_ofs[ 2 ] = CAM_MIN_DIST; + + cam_ofs[YAW] = viewangles[YAW]; + cam_ofs[PITCH] = viewangles[PITCH]; + cam_ofs[2] = CAM_MIN_DIST; } gEngfuncs.Cvar_SetValue( "cam_command", 0 ); } -void CAM_ToFirstPerson(void) +void CAM_ToFirstPerson( void ) { cam_thirdperson = 0; @@ -482,19 +514,19 @@ void CAM_Init( void ) gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); - cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson - cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view - cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw - cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch - cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance - cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world + cam_command = gEngfuncs.pfnRegisterVariable( "cam_command", "0", 0 ); // tells camera to go to thirdperson + cam_snapto = gEngfuncs.pfnRegisterVariable( "cam_snapto", "0", 0 ); // snap to thirdperson view + cam_idealyaw = gEngfuncs.pfnRegisterVariable( "cam_idealyaw", "90", 0 ); // thirdperson yaw + cam_idealpitch = gEngfuncs.pfnRegisterVariable( "cam_idealpitch", "0", 0 ); // thirperson pitch + cam_idealdist = gEngfuncs.pfnRegisterVariable( "cam_idealdist", "64", 0 ); // thirdperson distance + cam_contain = gEngfuncs.pfnRegisterVariable( "cam_contain", "0", 0 ); // contain camera to world - c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); - c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); - c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); - c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); - c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); - c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); + c_maxpitch = gEngfuncs.pfnRegisterVariable( "c_maxpitch", "90.0", 0 ); + c_minpitch = gEngfuncs.pfnRegisterVariable( "c_minpitch", "0.0", 0 ); + c_maxyaw = gEngfuncs.pfnRegisterVariable( "c_maxyaw", "135.0", 0 ); + c_minyaw = gEngfuncs.pfnRegisterVariable( "c_minyaw", "-135.0", 0 ); + c_maxdistance = gEngfuncs.pfnRegisterVariable( "c_maxdistance", "200.0", 0 ); + c_mindistance = gEngfuncs.pfnRegisterVariable( "c_mindistance", "30.0", 0 ); } void CAM_ClearStates( void ) @@ -517,101 +549,100 @@ void CAM_ClearStates( void ) cam_snapto->value = 0; cam_distancemove = 0; - cam_ofs[ 0 ] = 0.0; - cam_ofs[ 1 ] = 0.0; - cam_ofs[ 2 ] = CAM_MIN_DIST; + cam_ofs[0] = 0.0; + cam_ofs[1] = 0.0; + cam_ofs[2] = CAM_MIN_DIST; - cam_idealpitch->value = viewangles[ PITCH ]; - cam_idealyaw->value = viewangles[ YAW ]; + cam_idealpitch->value = viewangles[PITCH]; + cam_idealyaw->value = viewangles[YAW]; cam_idealdist->value = CAM_MIN_DIST; } -void CAM_StartMouseMove(void) +void CAM_StartMouseMove( void ) { float flSensitivity; - + //only move the cam with mouse if we are in third person. - if (cam_thirdperson) + if( cam_thirdperson ) { //set appropriate flags and initialize the old mouse position //variables for mouse camera movement - if (!cam_mousemove) + if( !cam_mousemove ) { - cam_mousemove=1; - iMouseInUse=1; - GetCursorPos (&cam_mouse); + cam_mousemove = 1; + iMouseInUse = 1; + GetCursorPos( &cam_mouse ); - if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + if( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) { - cam_old_mouse_x=cam_mouse.x*flSensitivity; - cam_old_mouse_y=cam_mouse.y*flSensitivity; + cam_old_mouse_x = cam_mouse.x * flSensitivity; + cam_old_mouse_y = cam_mouse.y * flSensitivity; } else { - cam_old_mouse_x=cam_mouse.x; - cam_old_mouse_y=cam_mouse.y; + cam_old_mouse_x = cam_mouse.x; + cam_old_mouse_y = cam_mouse.y; } } } //we are not in 3rd person view..therefore do not allow camera movement else { - cam_mousemove=0; - iMouseInUse=0; + cam_mousemove = 0; + iMouseInUse = 0; } } //the key has been released for camera movement //tell the engine that mouse camera movement is off -void CAM_EndMouseMove(void) +void CAM_EndMouseMove( void ) { - cam_mousemove=0; - iMouseInUse=0; + cam_mousemove = 0; + iMouseInUse = 0; } - //---------------------------------------------------------- //routines to start the process of moving the cam in or out //using the mouse //---------------------------------------------------------- -void CAM_StartDistance(void) +void CAM_StartDistance( void ) { //only move the cam with mouse if we are in third person. - if (cam_thirdperson) + if( cam_thirdperson ) { - //set appropriate flags and initialize the old mouse position - //variables for mouse camera movement - if (!cam_distancemove) - { - cam_distancemove=1; - cam_mousemove=1; - iMouseInUse=1; - GetCursorPos (&cam_mouse); - cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); - cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); - } + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if( !cam_distancemove ) + { + cam_distancemove = 1; + cam_mousemove = 1; + iMouseInUse = 1; + GetCursorPos( &cam_mouse ); + cam_old_mouse_x = cam_mouse.x * gHUD.GetSensitivity(); + cam_old_mouse_y = cam_mouse.y * gHUD.GetSensitivity(); + } } //we are not in 3rd person view..therefore do not allow camera movement else - { - cam_distancemove=0; - cam_mousemove=0; - iMouseInUse=0; + { + cam_distancemove = 0; + cam_mousemove = 0; + iMouseInUse = 0; } } //the key has been released for camera movement //tell the engine that mouse camera movement is off -void CAM_EndDistance(void) +void CAM_EndDistance( void ) { - cam_distancemove=0; - cam_mousemove=0; - iMouseInUse=0; + cam_distancemove = 0; + cam_mousemove = 0; + iMouseInUse = 0; } int DLLEXPORT CL_IsThirdPerson( void ) { - return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) ); + return ( cam_thirdperson ? 1 : 0 ) || ( g_iUser1 && ( g_iUser2 == gEngfuncs.GetLocalPlayer()->index ) ); } void DLLEXPORT CL_CameraOffset( float *ofs ) diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index c48cf373..a8c6423d 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -19,12 +19,12 @@ #ifdef _WIN32 #include #else -typedef struct point_s{ +typedef struct point_s +{ int x; int y; } POINT; #define GetCursorPos(x) #define SetCursorPos(x,y) #endif - #endif diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp index 8c2a6a3b..fd1ef7da 100644 --- a/cl_dll/input.cpp +++ b/cl_dll/input.cpp @@ -11,6 +11,7 @@ // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All // rights reserved. + #include "hud.h" #include "cl_util.h" #include "camera.h" @@ -30,7 +31,7 @@ extern "C" extern "C" { struct kbutton_s DLLEXPORT *KB_Find( const char *name ); - void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); + void DLLEXPORT CL_CreateMove( float frametime, struct usercmd_s *cmd, int active ); void DLLEXPORT HUD_Shutdown( void ); int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); } @@ -43,8 +44,8 @@ extern cl_enginefunc_t gEngfuncs; // Defined in pm_math.c extern "C" float anglemod( float a ); -void IN_Init (void); -void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Init( void ); +void IN_Move( float frametime, usercmd_t *cmd ); void IN_Shutdown( void ); void V_Init( void ); void VectorAngles( const float *forward, float *angles ); @@ -53,8 +54,8 @@ int CL_ButtonBits( int ); // xxx need client dll function to get and clear impuse extern cvar_t *in_joystick; -int in_impulse = 0; -int in_cancel = 0; +int in_impulse = 0; +int in_cancel = 0; cvar_t *m_pitch; cvar_t *m_yaw; @@ -74,6 +75,7 @@ cvar_t *cl_yawspeed; cvar_t *cl_pitchspeed; cvar_t *cl_anglespeedkey; cvar_t *cl_vsmoothing; + /* =============================================================================== @@ -95,7 +97,6 @@ state bit 2 is edge triggered on the down to up transition =============================================================================== */ - kbutton_t in_mlook; kbutton_t in_klook; kbutton_t in_jlook; @@ -142,39 +143,39 @@ NOTE: Only works for text with +word in it. */ int KB_ConvertString( char *in, char **ppout ) { - char sz[ 4096 ]; - char binding[ 64 ]; + char sz[4096]; + char binding[64]; char *p; char *pOut; char *pEnd; const char *pBinding; - if ( !ppout ) + if( !ppout ) return 0; *ppout = NULL; p = in; pOut = sz; - while ( *p ) + while( *p ) { - if ( *p == '+' ) + if( *p == '+' ) { pEnd = binding; - while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + while( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) { *pEnd++ = *p++; } - *pEnd = '\0'; + *pEnd = '\0'; pBinding = NULL; - if ( strlen( binding + 1 ) > 0 ) + if( strlen( binding + 1 ) > 0 ) { // See if there is a binding for binding? pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); } - if ( pBinding ) + if( pBinding ) { *pOut++ = '['; pEnd = (char *)pBinding; @@ -184,12 +185,12 @@ int KB_ConvertString( char *in, char **ppout ) pEnd = binding; } - while ( *pEnd ) + while( *pEnd ) { *pOut++ = *pEnd++; } - if ( pBinding ) + if( pBinding ) { *pOut++ = ']'; } @@ -202,7 +203,7 @@ int KB_ConvertString( char *in, char **ppout ) *pOut = '\0'; - pOut = ( char * )malloc( strlen( sz ) + 1 ); + pOut = (char *)malloc( strlen( sz ) + 1 ); strcpy( pOut, sz ); *ppout = pOut; @@ -220,9 +221,9 @@ struct kbutton_s DLLEXPORT *KB_Find( const char *name ) { kblist_t *p; p = g_kbkeys; - while ( p ) + while( p ) { - if ( !stricmp( name, p->name ) ) + if( !stricmp( name, p->name ) ) return p->pkey; p = p->next; @@ -243,12 +244,12 @@ void KB_Add( const char *name, kbutton_t *pkb ) kbutton_t *kb; kb = KB_Find( name ); - - if ( kb ) + + if( kb ) return; - p = ( kblist_t * )malloc( sizeof( kblist_t ) ); - memset( p, 0, sizeof( *p ) ); + p = (kblist_t *)malloc( sizeof(kblist_t) ); + memset( p, 0, sizeof(*p) ); strcpy( p->name, name ); p->pkey = pkb; @@ -284,7 +285,7 @@ void KB_Shutdown( void ) { kblist_t *p, *n; p = g_kbkeys; - while ( p ) + while( p ) { n = p->next; free( p ); @@ -298,31 +299,31 @@ void KB_Shutdown( void ) KeyDown ============ */ -void KeyDown (kbutton_t *b) +void KeyDown( kbutton_t *b ) { - int k; + int k; char *c; - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) - k = atoi(c); + c = gEngfuncs.Cmd_Argv( 1 ); + if( c[0] ) + k = atoi( c ); else k = -1; // typed manually at the console for continuous down - if (k == b->down[0] || k == b->down[1]) + if( k == b->down[0] || k == b->down[1] ) return; // repeating key - if (!b->down[0]) + if( !b->down[0] ) b->down[0] = k; - else if (!b->down[1]) + else if( !b->down[1] ) b->down[1] = k; else { - gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + gEngfuncs.Con_DPrintf( "Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c ); return; } - if (b->state & 1) + if( b->state & 1 ) return; // still down b->state |= 1 + 2; // down + impulse down } @@ -332,34 +333,35 @@ void KeyDown (kbutton_t *b) KeyUp ============ */ -void KeyUp (kbutton_t *b) +void KeyUp( kbutton_t *b ) { - int k; + int k; char *c; - c = gEngfuncs.Cmd_Argv(1); - if (c[0]) + c = gEngfuncs.Cmd_Argv( 1 ); + if( c[0] ) k = atoi(c); else - { // typed manually at the console, assume for unsticking, so clear all + { + // typed manually at the console, assume for unsticking, so clear all b->down[0] = b->down[1] = 0; b->state = 4; // impulse up return; } - if (b->down[0] == k) + if( b->down[0] == k ) b->down[0] = 0; - else if (b->down[1] == k) + else if( b->down[1] == k ) b->down[1] = 0; else return; // key up without coresponding down (menu pass through) - if (b->down[0] || b->down[1]) + if( b->down[0] || b->down[1] ) { - //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + //Con_Printf ( "Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c ); return; // some other key is still holding it down } - if (!(b->state & 1)) + if( !( b->state & 1 ) ) return; // still up (this should not happen) b->state &= ~1; // now up @@ -374,154 +376,283 @@ Return 1 to allow engine to process the key, otherwise, act on it as needed ============ */ int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) -{ - +{ return 1; } -void IN_BreakDown( void ) { KeyDown( &in_break ); } -void IN_BreakUp( void ) { KeyUp( &in_break ); } -void IN_KLookDown (void) {KeyDown(&in_klook);} -void IN_KLookUp (void) {KeyUp(&in_klook);} -void IN_JLookDown (void) {KeyDown(&in_jlook);} -void IN_JLookUp (void) {KeyUp(&in_jlook);} -void IN_MLookDown (void) {KeyDown(&in_mlook);} -void IN_UpDown(void) {KeyDown(&in_up);} -void IN_UpUp(void) {KeyUp(&in_up);} -void IN_DownDown(void) {KeyDown(&in_down);} -void IN_DownUp(void) {KeyUp(&in_down);} -void IN_LeftDown(void) {KeyDown(&in_left);} -void IN_LeftUp(void) {KeyUp(&in_left);} -void IN_RightDown(void) {KeyDown(&in_right);} -void IN_RightUp(void) {KeyUp(&in_right);} - -void IN_ForwardDown(void) +void IN_BreakDown( void ) { - KeyDown(&in_forward); + KeyDown( &in_break ); +} + +void IN_BreakUp( void ) +{ + KeyUp( &in_break ); +} + +void IN_KLookDown( void ) +{ + KeyDown( &in_klook ); +} + +void IN_KLookUp( void ) +{ + KeyUp( &in_klook ); +} + +void IN_JLookDown( void ) +{ + KeyDown( &in_jlook ); +} + +void IN_JLookUp( void ) +{ + KeyUp( &in_jlook ); +} + +void IN_MLookDown( void ) +{ + KeyDown( &in_mlook ); +} + +void IN_UpDown( void ) +{ + KeyDown( &in_up ); +} + +void IN_UpUp( void ) +{ + KeyUp( &in_up ); +} + +void IN_DownDown( void ) +{ + KeyDown( &in_down ); +} + +void IN_DownUp( void ) +{ + KeyUp( &in_down ); +} + +void IN_LeftDown( void ) +{ + KeyDown( &in_left ); +} + +void IN_LeftUp( void ) +{ + KeyUp( &in_left ); +} + +void IN_RightDown( void ) +{ + KeyDown( &in_right ); +} + +void IN_RightUp( void ) +{ + KeyUp( &in_right ); +} + +void IN_ForwardDown( void ) +{ + KeyDown( &in_forward ); gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); } -void IN_ForwardUp(void) +void IN_ForwardUp( void ) { - KeyUp(&in_forward); + KeyUp( &in_forward ); gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); } -void IN_BackDown(void) +void IN_BackDown( void ) { - KeyDown(&in_back); + KeyDown( &in_back ); gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); } -void IN_BackUp(void) +void IN_BackUp( void ) { - KeyUp(&in_back); + KeyUp( &in_back ); gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); } -void IN_LookupDown(void) {KeyDown(&in_lookup);} -void IN_LookupUp(void) {KeyUp(&in_lookup);} -void IN_LookdownDown(void) {KeyDown(&in_lookdown);} -void IN_LookdownUp(void) {KeyUp(&in_lookdown);} -void IN_MoveleftDown(void) + +void IN_LookupDown( void ) { - KeyDown(&in_moveleft); + KeyDown( &in_lookup ); +} + +void IN_LookupUp( void ) +{ + KeyUp( &in_lookup ); +} + +void IN_LookdownDown( void ) +{ + KeyDown( &in_lookdown ); +} + +void IN_LookdownUp( void ) +{ + KeyUp( &in_lookdown ); +} + +void IN_MoveleftDown( void ) +{ + KeyDown( &in_moveleft ); gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); } -void IN_MoveleftUp(void) +void IN_MoveleftUp( void ) { - KeyUp(&in_moveleft); + KeyUp( &in_moveleft ); gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); } -void IN_MoverightDown(void) +void IN_MoverightDown( void ) { - KeyDown(&in_moveright); + KeyDown( &in_moveright ); gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); } -void IN_MoverightUp(void) +void IN_MoverightUp( void ) { - KeyUp(&in_moveright); + KeyUp( &in_moveright ); gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); } -void IN_SpeedDown(void) {KeyDown(&in_speed);} -void IN_SpeedUp(void) {KeyUp(&in_speed);} -void IN_StrafeDown(void) {KeyDown(&in_strafe);} -void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +void IN_SpeedDown( void ) +{ + KeyDown( &in_speed ); +} + +void IN_SpeedUp( void ) +{ + KeyUp( &in_speed ); +} + +void IN_StrafeDown( void ) +{ + KeyDown( &in_strafe ); +} + +void IN_StrafeUp( void ) +{ + KeyUp( &in_strafe ); +} // needs capture by hud/vgui also -extern void __CmdFunc_InputPlayerSpecial(void); +extern void __CmdFunc_InputPlayerSpecial( void ); -void IN_Attack2Down(void) +void IN_Attack2Down( void ) { - KeyDown(&in_attack2); + KeyDown( &in_attack2 ); gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); } -void IN_Attack2Up(void) {KeyUp(&in_attack2);} -void IN_UseDown (void) +void IN_Attack2Up( void ) { - KeyDown(&in_use); + KeyUp( &in_attack2 ); +} + +void IN_UseDown( void ) +{ + KeyDown( &in_use ); gHUD.m_Spectator.HandleButtonsDown( IN_USE ); } -void IN_UseUp (void) {KeyUp(&in_use);} -void IN_JumpDown (void) +void IN_UseUp( void ) { - KeyDown(&in_jump); + KeyUp( &in_use ); +} +void IN_JumpDown( void ) +{ + KeyDown( &in_jump ); gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); - } -void IN_JumpUp (void) {KeyUp(&in_jump);} -void IN_DuckDown(void) + +void IN_JumpUp( void ) { - KeyDown(&in_duck); - gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); - + KeyUp( &in_jump ); } -void IN_DuckUp(void) {KeyUp(&in_duck);} -void IN_ReloadDown(void) {KeyDown(&in_reload);} -void IN_ReloadUp(void) {KeyUp(&in_reload);} -void IN_Alt1Down(void) {KeyDown(&in_alt1);} -void IN_Alt1Up(void) {KeyUp(&in_alt1);} -void IN_GraphDown(void) {KeyDown(&in_graph);} -void IN_GraphUp(void) {KeyUp(&in_graph);} -void IN_AttackDown(void) +void IN_DuckDown( void ) +{ + KeyDown( &in_duck ); + gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); +} + +void IN_DuckUp( void ) +{ + KeyUp( &in_duck ); +} + +void IN_ReloadDown( void ) +{ + KeyDown( &in_reload ); +} + +void IN_ReloadUp( void ) +{ + KeyUp( &in_reload ); +} + +void IN_Alt1Down( void ) +{ + KeyDown( &in_alt1 ); +} + +void IN_Alt1Up( void ) +{ + KeyUp( &in_alt1 ); +} + +void IN_GraphDown( void ) +{ + KeyDown( &in_graph ); +} + +void IN_GraphUp( void ) +{ + KeyUp( &in_graph ); +} + +void IN_AttackDown( void ) { KeyDown( &in_attack ); gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); } -void IN_AttackUp(void) +void IN_AttackUp( void ) { KeyUp( &in_attack ); in_cancel = 0; } // Special handling -void IN_Cancel(void) +void IN_Cancel( void ) { in_cancel = 1; } -void IN_Impulse (void) +void IN_Impulse( void ) { - in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); + in_impulse = atoi( gEngfuncs.Cmd_Argv( 1 ) ); } -void IN_ScoreDown(void) +void IN_ScoreDown( void ) { - KeyDown(&in_score); + KeyDown( &in_score ); } -void IN_ScoreUp(void) +void IN_ScoreUp( void ) { - KeyUp(&in_score); + KeyUp( &in_score ); } -void IN_MLookUp (void) +void IN_MLookUp( void ) { KeyUp( &in_mlook ); } @@ -536,36 +667,36 @@ Returns 0.25 if a key was pressed and released during the frame, 1.0 if held for the entire time =============== */ -float CL_KeyState (kbutton_t *key) +float CL_KeyState( kbutton_t *key ) { float val = 0.0; - int impulsedown, impulseup, down; - + int impulsedown, impulseup, down; + impulsedown = key->state & 2; - impulseup = key->state & 4; - down = key->state & 1; - - if ( impulsedown && !impulseup ) + impulseup = key->state & 4; + down = key->state & 1; + + if( impulsedown && !impulseup ) { // pressed and held this frame? val = down ? 0.5 : 0.0; } - if ( impulseup && !impulsedown ) + if( impulseup && !impulsedown ) { // released this frame? val = down ? 0.0 : 0.0; } - if ( !impulsedown && !impulseup ) + if( !impulsedown && !impulseup ) { // held the entire frame? val = down ? 1.0 : 0.0; } - if ( impulsedown && impulseup ) + if( impulsedown && impulseup ) { - if ( down ) + if( down ) { // released and re-pressed this frame val = 0.75; @@ -589,12 +720,12 @@ CL_AdjustAngles Moves the local angle positions ================ */ -void CL_AdjustAngles ( float frametime, float *viewangles ) +void CL_AdjustAngles( float frametime, float *viewangles ) { - float speed; - float up, down; - - if (in_speed.state & 1) + float speed; + float up, down; + + if( in_speed.state & 1 ) { speed = frametime * cl_anglespeedkey->value; } @@ -603,32 +734,33 @@ void CL_AdjustAngles ( float frametime, float *viewangles ) speed = frametime; } - if (!(in_strafe.state & 1)) + if( !( in_strafe.state & 1 ) ) { - viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); - viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); - viewangles[YAW] = anglemod(viewangles[YAW]); + viewangles[YAW] -= speed * cl_yawspeed->value * CL_KeyState( &in_right ); + viewangles[YAW] += speed * cl_yawspeed->value * CL_KeyState( &in_left ); + viewangles[YAW] = anglemod( viewangles[YAW] ); } - if (in_klook.state & 1) - { - viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); - viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); - } - - up = CL_KeyState (&in_lookup); - down = CL_KeyState(&in_lookdown); - - viewangles[PITCH] -= speed*cl_pitchspeed->value * up; - viewangles[PITCH] += speed*cl_pitchspeed->value * down; - if (viewangles[PITCH] > cl_pitchdown->value) + if( in_klook.state & 1 ) + { + viewangles[PITCH] -= speed * cl_pitchspeed->value * CL_KeyState( &in_forward ); + viewangles[PITCH] += speed * cl_pitchspeed->value * CL_KeyState( &in_back ); + } + + up = CL_KeyState( &in_lookup ); + down = CL_KeyState( &in_lookdown ); + + viewangles[PITCH] -= speed * cl_pitchspeed->value * up; + viewangles[PITCH] += speed * cl_pitchspeed->value * down; + + if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) + if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; - if (viewangles[ROLL] > 50) + if( viewangles[ROLL] > 50 ) viewangles[ROLL] = 50; - if (viewangles[ROLL] < -50) + if( viewangles[ROLL] < -50 ) viewangles[ROLL] = -50; } @@ -641,44 +773,44 @@ if active == 1 then we are 1) not playing back demos ( where our commands are ig 2 ) we have finished signing on to server ================ */ -void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) -{ +void DLLEXPORT CL_CreateMove( float frametime, struct usercmd_s *cmd, int active ) +{ float spd; vec3_t viewangles; static vec3_t oldangles; - if ( active ) + if( active ) { - //memset( viewangles, 0, sizeof( vec3_t ) ); - //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + //memset( viewangles, 0, sizeof(vec3_t) ); + //viewangles[0] = viewangles[1] = viewangles[2] = 0.0; gEngfuncs.GetViewAngles( (float *)viewangles ); - CL_AdjustAngles ( frametime, viewangles ); + CL_AdjustAngles( frametime, viewangles ); + + memset( cmd, 0, sizeof(*cmd) ); - memset (cmd, 0, sizeof(*cmd)); - gEngfuncs.SetViewAngles( (float *)viewangles ); - if ( in_strafe.state & 1 ) + if( in_strafe.state & 1 ) { - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_right ); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_left ); } - cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_moveright ); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_moveleft ); - cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); - cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + cmd->upmove += cl_upspeed->value * CL_KeyState( &in_up ); + cmd->upmove -= cl_upspeed->value * CL_KeyState( &in_down ); - if ( !(in_klook.state & 1 ) ) + if( !(in_klook.state & 1 ) ) { - cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); - cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); - } + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState( &in_forward ); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState( &in_back ); + } // adjust for speed key - if ( in_speed.state & 1 ) + if( in_speed.state & 1 ) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; @@ -687,12 +819,12 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ // clip to maxspeed spd = gEngfuncs.GetClientMaxspeed(); - if ( spd != 0.0 ) + if( spd != 0.0 ) { // scale the 3 speeds so that the total velocity is not > cl.maxspeed - float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + float fmov = sqrt( ( cmd->forwardmove * cmd->forwardmove ) + ( cmd->sidemove * cmd->sidemove ) + ( cmd->upmove * cmd->upmove ) ); - if ( fmov > spd ) + if( fmov > spd ) { float fratio = spd / fmov; cmd->forwardmove *= fratio; @@ -702,7 +834,7 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ } // Allow mice and other controllers to add their inputs - IN_Move ( frametime, cmd ); + IN_Move( frametime, cmd ); } cmd->impulse = in_impulse; @@ -715,15 +847,14 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ // cmd->buttons = CL_ButtonBits( 1 ); - // Using joystick? - if ( in_joystick->value ) + if( in_joystick->value ) { - if ( cmd->forwardmove > 0 ) + if( cmd->forwardmove > 0 ) { cmd->buttons |= IN_FORWARD; } - else if ( cmd->forwardmove < 0 ) + else if( cmd->forwardmove < 0 ) { cmd->buttons |= IN_BACK; } @@ -732,7 +863,7 @@ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int activ gEngfuncs.GetViewAngles( (float *)viewangles ); // Set current view angles. - if ( g_iAlive ) + if( g_iAlive ) { VectorCopy( viewangles, cmd->viewangles ); VectorCopy( viewangles, oldangles ); @@ -751,7 +882,7 @@ CL_IsDead Returns 1 if health is <= 0 ============ */ -int CL_IsDead( void ) +int CL_IsDead( void ) { return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; } @@ -768,92 +899,91 @@ int CL_ButtonBits( int bResetState ) { int bits = 0; - if ( in_attack.state & 3 ) + if( in_attack.state & 3 ) { - if(gHUD.m_MOTD.m_bShow) + if( gHUD.m_MOTD.m_bShow ) gHUD.m_MOTD.Reset(); else bits |= IN_ATTACK; } - - if (in_duck.state & 3) + if( in_duck.state & 3 ) { bits |= IN_DUCK; } - - if (in_jump.state & 3) + + if( in_jump.state & 3 ) { bits |= IN_JUMP; } - if ( in_forward.state & 3 ) + if( in_forward.state & 3 ) { bits |= IN_FORWARD; } - - if (in_back.state & 3) + + if( in_back.state & 3 ) { bits |= IN_BACK; } - if (in_use.state & 3) + if( in_use.state & 3 ) { bits |= IN_USE; } - if (in_cancel) + if( in_cancel ) { bits |= IN_CANCEL; } - if ( in_left.state & 3 ) + if( in_left.state & 3 ) { bits |= IN_LEFT; } - if (in_right.state & 3) + if( in_right.state & 3 ) { bits |= IN_RIGHT; } - - if ( in_moveleft.state & 3 ) + + if( in_moveleft.state & 3 ) { bits |= IN_MOVELEFT; } - if (in_moveright.state & 3) + if( in_moveright.state & 3 ) { bits |= IN_MOVERIGHT; } - if (in_attack2.state & 3) + if( in_attack2.state & 3 ) { bits |= IN_ATTACK2; } - if (in_reload.state & 3) + if( in_reload.state & 3 ) { bits |= IN_RELOAD; } - if (in_alt1.state & 3) + if( in_alt1.state & 3 ) { bits |= IN_ALT1; } - if ( in_score.state & 3 ) + if( in_score.state & 3 ) { bits |= IN_SCORE; } // Dead or in intermission? Shore scoreboard, too - if ( CL_IsDead() || gHUD.m_iIntermission ) + if( CL_IsDead() || gHUD.m_iIntermission ) { bits |= IN_SCORE; } - if ( bResetState ) + if( bResetState ) { in_attack.state &= ~2; in_duck.state &= ~2; @@ -885,10 +1015,10 @@ void CL_ResetButtonBits( int bits ) int bitsNew = CL_ButtonBits( 0 ) ^ bits; // Has the attack button been changed - if ( bitsNew & IN_ATTACK ) + if( bitsNew & IN_ATTACK ) { // Was it pressed? or let go? - if ( bits & IN_ATTACK ) + if( bits & IN_ATTACK ) { KeyDown( &in_attack ); } @@ -905,77 +1035,77 @@ void CL_ResetButtonBits( int bits ) InitInput ============ */ -void InitInput (void) +void InitInput( void ) { - gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); - gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); - gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); - gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); - gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); - gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); - gEngfuncs.pfnAddCommand ("+right",IN_RightDown); - gEngfuncs.pfnAddCommand ("-right",IN_RightUp); - gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); - gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); - gEngfuncs.pfnAddCommand ("+back",IN_BackDown); - gEngfuncs.pfnAddCommand ("-back",IN_BackUp); - gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); - gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); - gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); - gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); - gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); - gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); - gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); - gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); - gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); - gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); - gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); - gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); - gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); - gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); - gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); - gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); - gEngfuncs.pfnAddCommand ("+use", IN_UseDown); - gEngfuncs.pfnAddCommand ("-use", IN_UseUp); - gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); - gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); - gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); - gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); - gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); - gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); - gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); - gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); - gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); - gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); - gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); - gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); - gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); - gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); - gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); - gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); - gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); - gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); - gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + gEngfuncs.pfnAddCommand( "+moveup", IN_UpDown ); + gEngfuncs.pfnAddCommand( "-moveup", IN_UpUp ); + gEngfuncs.pfnAddCommand( "+movedown", IN_DownDown ); + gEngfuncs.pfnAddCommand( "-movedown", IN_DownUp ); + gEngfuncs.pfnAddCommand( "+left", IN_LeftDown ); + gEngfuncs.pfnAddCommand( "-left", IN_LeftUp ); + gEngfuncs.pfnAddCommand( "+right", IN_RightDown ); + gEngfuncs.pfnAddCommand( "-right", IN_RightUp ); + gEngfuncs.pfnAddCommand( "+forward", IN_ForwardDown ); + gEngfuncs.pfnAddCommand( "-forward", IN_ForwardUp ); + gEngfuncs.pfnAddCommand( "+back", IN_BackDown ); + gEngfuncs.pfnAddCommand( "-back", IN_BackUp ); + gEngfuncs.pfnAddCommand( "+lookup", IN_LookupDown ); + gEngfuncs.pfnAddCommand( "-lookup", IN_LookupUp ); + gEngfuncs.pfnAddCommand( "+lookdown", IN_LookdownDown ); + gEngfuncs.pfnAddCommand( "-lookdown", IN_LookdownUp ); + gEngfuncs.pfnAddCommand( "+strafe", IN_StrafeDown ); + gEngfuncs.pfnAddCommand( "-strafe", IN_StrafeUp ); + gEngfuncs.pfnAddCommand( "+moveleft", IN_MoveleftDown ); + gEngfuncs.pfnAddCommand( "-moveleft", IN_MoveleftUp ); + gEngfuncs.pfnAddCommand( "+moveright", IN_MoverightDown ); + gEngfuncs.pfnAddCommand( "-moveright", IN_MoverightUp ); + gEngfuncs.pfnAddCommand( "+speed", IN_SpeedDown ); + gEngfuncs.pfnAddCommand( "-speed", IN_SpeedUp ); + gEngfuncs.pfnAddCommand( "+attack", IN_AttackDown ); + gEngfuncs.pfnAddCommand( "-attack", IN_AttackUp ); + gEngfuncs.pfnAddCommand( "+attack2", IN_Attack2Down ); + gEngfuncs.pfnAddCommand( "-attack2", IN_Attack2Up ); + gEngfuncs.pfnAddCommand( "+use", IN_UseDown ); + gEngfuncs.pfnAddCommand( "-use", IN_UseUp ); + gEngfuncs.pfnAddCommand( "+jump", IN_JumpDown ); + gEngfuncs.pfnAddCommand( "-jump", IN_JumpUp ); + gEngfuncs.pfnAddCommand( "impulse", IN_Impulse ); + gEngfuncs.pfnAddCommand( "+klook", IN_KLookDown ); + gEngfuncs.pfnAddCommand( "-klook", IN_KLookUp ); + gEngfuncs.pfnAddCommand( "+mlook", IN_MLookDown ); + gEngfuncs.pfnAddCommand( "-mlook", IN_MLookUp ); + gEngfuncs.pfnAddCommand( "+jlook", IN_JLookDown ); + gEngfuncs.pfnAddCommand( "-jlook", IN_JLookUp ); + gEngfuncs.pfnAddCommand( "+duck", IN_DuckDown ); + gEngfuncs.pfnAddCommand( "-duck", IN_DuckUp ); + gEngfuncs.pfnAddCommand( "+reload", IN_ReloadDown ); + gEngfuncs.pfnAddCommand( "-reload", IN_ReloadUp ); + gEngfuncs.pfnAddCommand( "+alt1", IN_Alt1Down ); + gEngfuncs.pfnAddCommand( "-alt1", IN_Alt1Up ); + gEngfuncs.pfnAddCommand( "+graph", IN_GraphDown ); + gEngfuncs.pfnAddCommand( "-graph", IN_GraphUp ); + gEngfuncs.pfnAddCommand( "+break", IN_BreakDown ); + gEngfuncs.pfnAddCommand( "-break", IN_BreakUp ); - lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); - lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); - cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); - cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); - cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); - cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); - cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); - cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); - cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); - cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); - cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); - cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + lookstrafe = gEngfuncs.pfnRegisterVariable( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable( "cl_pitchdown", "89", 0 ); - cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + cl_vsmoothing = gEngfuncs.pfnRegisterVariable( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); - m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); - m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); - m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); - m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + m_pitch = gEngfuncs.pfnRegisterVariable( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable( "m_side","0.8", FCVAR_ARCHIVE ); // Initialize third person camera controls. CAM_Init(); @@ -992,7 +1122,7 @@ void InitInput (void) ShutdownInput ============ */ -void ShutdownInput (void) +void ShutdownInput( void ) { IN_Shutdown(); KB_Shutdown(); diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index dd621d19..93a7eefb 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -91,47 +91,46 @@ void IN_ToggleButtons( float forwardmove, float sidemove ) } } - if ( forwardmove > 0.7 && !( moveflags & F )) + if( forwardmove > 0.7 && !( moveflags & F ) ) { moveflags |= F; in_forward.state |= BUTTON_DOWN; } - if ( forwardmove < 0.7 && ( moveflags & F )) + if( forwardmove < 0.7 && ( moveflags & F ) ) { moveflags &= ~F; in_forward.state &= ~BUTTON_DOWN; } - if ( forwardmove < -0.7 && !( moveflags & B )) + if( forwardmove < -0.7 && !( moveflags & B ) ) { moveflags |= B; in_back.state |= BUTTON_DOWN; } - if ( forwardmove > -0.7 && ( moveflags & B )) + if( forwardmove > -0.7 && ( moveflags & B ) ) { moveflags &= ~B; in_back.state &= ~BUTTON_DOWN; } - if ( sidemove > 0.9 && !( moveflags & R )) + if( sidemove > 0.9 && !( moveflags & R ) ) { moveflags |= R; in_moveright.state |= BUTTON_DOWN; } - if ( sidemove < 0.9 && ( moveflags & R )) + if( sidemove < 0.9 && ( moveflags & R ) ) { moveflags &= ~R; in_moveright.state &= ~BUTTON_DOWN; } - if ( sidemove < -0.9 && !( moveflags & L )) + if( sidemove < -0.9 && !( moveflags & L ) ) { moveflags |= L; in_moveleft.state |= BUTTON_DOWN; } - if ( sidemove > -0.9 && ( moveflags & L )) + if( sidemove > -0.9 && ( moveflags & L ) ) { moveflags &= ~L; in_moveleft.state &= ~BUTTON_DOWN; } - } void IN_ClientMoveEvent( float forwardmove, float sidemove ) @@ -148,15 +147,17 @@ void IN_ClientLookEvent( float relyaw, float relpitch ) rel_yaw += relyaw; rel_pitch += relpitch; } + // Rotate camera and add move values to usercmd void IN_Move( float frametime, usercmd_t *cmd ) { Vector viewangles; gEngfuncs.GetViewAngles( viewangles ); bool fLadder = false; - if( cl_laddermode->value !=2 ) fLadder = gEngfuncs.GetLocalPlayer()->curstate.movetype == MOVETYPE_FLY; - //if(ac_forwardmove || ac_sidemove) - //gEngfuncs.Con_Printf("Move: %f %f %f %f\n", ac_forwardmove, ac_sidemove, rel_pitch, rel_yaw); + if( cl_laddermode->value != 2 ) + fLadder = gEngfuncs.GetLocalPlayer()->curstate.movetype == MOVETYPE_FLY; + //if( ac_forwardmove || ac_sidemove ) + //gEngfuncs.Con_Printf( "Move: %f %f %f %f\n", ac_forwardmove, ac_sidemove, rel_pitch, rel_yaw ); #if 0 if( in_mlook.state & 1 ) { @@ -183,30 +184,31 @@ void IN_Move( float frametime, usercmd_t *cmd ) viewangles[YAW] -= ac_sidemove * 5; ac_sidemove = 0; } - if(gHUD.m_MOTD.m_bShow) + if( gHUD.m_MOTD.m_bShow ) gHUD.m_MOTD.scroll += rel_pitch; else viewangles[PITCH] += rel_pitch; - if (viewangles[PITCH] > cl_pitchdown->value) + if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) + if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; } float rgfl[3]; viewangles.CopyToArray( rgfl ); gEngfuncs.SetViewAngles( rgfl ); - + if( ac_movecount ) { IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); - if( ac_forwardmove ) cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; - if( ac_sidemove ) cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; - if (in_speed.state & 1) + if( ac_forwardmove ) + cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; + if( ac_sidemove ) + cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; + if(in_speed.state & 1) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; } - } ac_sidemove = ac_forwardmove = rel_pitch = rel_yaw = 0; @@ -219,55 +221,56 @@ extern "C" void DLLEXPORT IN_MouseEvent( int mstate ) // perform button actions for( int i = 0; i < 5; i++ ) { - if(( mstate & (1 << i)) && !( mouse_oldbuttonstate & (1 << i))) + if( ( mstate & ( 1 << i ) ) && !( mouse_oldbuttonstate & ( 1 << i ) ) ) { gEngfuncs.Key_Event( K_MOUSE1 + i, 1 ); } - if( !( mstate & (1 << i)) && ( mouse_oldbuttonstate & (1 << i))) + if( !( mstate & ( 1 << i ) ) && ( mouse_oldbuttonstate & ( 1 << i ) ) ) { gEngfuncs.Key_Event( K_MOUSE1 + i, 0 ); } } - + mouse_oldbuttonstate = mstate; } // Stubs -extern "C" void DLLEXPORT IN_ClearStates ( void ) +extern "C" void DLLEXPORT IN_ClearStates( void ) { - //gEngfuncs.Con_Printf("IN_ClearStates\n"); + //gEngfuncs.Con_Printf( "IN_ClearStates\n" ); } -extern "C" void DLLEXPORT IN_ActivateMouse ( void ) +extern "C" void DLLEXPORT IN_ActivateMouse( void ) { - //gEngfuncs.Con_Printf("IN_ActivateMouse\n"); + //gEngfuncs.Con_Printf( "IN_ActivateMouse\n" ); } -extern "C" void DLLEXPORT IN_DeactivateMouse ( void ) +extern "C" void DLLEXPORT IN_DeactivateMouse( void ) { - //gEngfuncs.Con_Printf("IN_DeactivateMouse\n"); + //gEngfuncs.Con_Printf( "IN_DeactivateMouse\n" ); } -extern "C" void DLLEXPORT IN_Accumulate ( void ) +extern "C" void DLLEXPORT IN_Accumulate( void ) { - //gEngfuncs.Con_Printf("IN_Accumulate\n"); + //gEngfuncs.Con_Printf( "IN_Accumulate\n" ); } -void IN_Commands ( void ) +void IN_Commands( void ) { - //gEngfuncs.Con_Printf("IN_Commands\n"); + //gEngfuncs.Con_Printf( "IN_Commands\n" ); } -void IN_Shutdown ( void ) +void IN_Shutdown( void ) { } + // Register cvars and reset data void IN_Init( void ) { - sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity", "3", FCVAR_ARCHIVE ); - in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick", "0", FCVAR_ARCHIVE ); - cl_laddermode = gEngfuncs.pfnRegisterVariable ( "cl_laddermode", "2", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable( "sensitivity", "3", FCVAR_ARCHIVE ); + in_joystick = gEngfuncs.pfnRegisterVariable( "joystick", "0", FCVAR_ARCHIVE ); + cl_laddermode = gEngfuncs.pfnRegisterVariable( "cl_laddermode", "2", FCVAR_ARCHIVE ); ac_forwardmove = ac_sidemove = rel_yaw = rel_pitch = 0; } diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp index 33144a8b..5c8210fa 100644 --- a/cl_dll/inputw32.cpp +++ b/cl_dll/inputw32.cpp @@ -24,30 +24,30 @@ #define MOUSE_BUTTON_COUNT 5 // Set this to 1 to show mouse cursor. Experimental -int g_iVisibleMouse = 0; +int g_iVisibleMouse = 0; extern "C" { void DLLEXPORT IN_ActivateMouse( void ); void DLLEXPORT IN_DeactivateMouse( void ); - void DLLEXPORT IN_MouseEvent (int mstate); - void DLLEXPORT IN_Accumulate (void); - void DLLEXPORT IN_ClearStates (void); + void DLLEXPORT IN_MouseEvent( int mstate ); + void DLLEXPORT IN_Accumulate( void ); + void DLLEXPORT IN_ClearStates( void ); } extern cl_enginefunc_t gEngfuncs; extern int iMouseInUse; -extern kbutton_t in_strafe; -extern kbutton_t in_mlook; -extern kbutton_t in_speed; -extern kbutton_t in_jlook; +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; -extern cvar_t *m_pitch; -extern cvar_t *m_yaw; -extern cvar_t *m_forward; -extern cvar_t *m_side; +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; extern cvar_t *lookstrafe; extern cvar_t *lookspring; @@ -60,26 +60,26 @@ extern cvar_t *cl_pitchspeed; extern cvar_t *cl_movespeedkey; // mouse variables -cvar_t *m_filter; -cvar_t *sensitivity; +cvar_t *m_filter; +cvar_t *sensitivity; -int mouse_buttons; -int mouse_oldbuttonstate; -POINT current_pos; -int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; -static int restore_spi; -static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; -static int mouseactive; -int mouseinitialized; -static int mouseparmsvalid; -static int mouseshowtoggle = 1; +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; // joystick defines and variables // where should defines be moved? #define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick #define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball -#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V #define JOY_AXIS_X 0 #define JOY_AXIS_Y 1 #define JOY_AXIS_Z 2 @@ -106,57 +106,57 @@ DWORD dwAxisFlags[JOY_MAX_AXES] = JOY_RETURNV }; -DWORD dwAxisMap[ JOY_MAX_AXES ]; -DWORD dwControlMap[ JOY_MAX_AXES ]; -PDWORD pdwRawValue[ JOY_MAX_AXES ]; +DWORD dwAxisMap[JOY_MAX_AXES]; +DWORD dwControlMap[JOY_MAX_AXES]; +PDWORD pdwRawValue[JOY_MAX_AXES]; // none of these cvars are saved over a session // this means that advanced controller configuration needs to be executed // each time. this avoids any problems with getting back to a default usage // or when changing from one controller to another. this way at least something // works. -cvar_t *in_joystick; -cvar_t *joy_name; -cvar_t *joy_advanced; -cvar_t *joy_advaxisx; -cvar_t *joy_advaxisy; -cvar_t *joy_advaxisz; -cvar_t *joy_advaxisr; -cvar_t *joy_advaxisu; -cvar_t *joy_advaxisv; -cvar_t *joy_forwardthreshold; -cvar_t *joy_sidethreshold; -cvar_t *joy_pitchthreshold; -cvar_t *joy_yawthreshold; -cvar_t *joy_forwardsensitivity; -cvar_t *joy_sidesensitivity; -cvar_t *joy_pitchsensitivity; -cvar_t *joy_yawsensitivity; -cvar_t *joy_wwhack1; -cvar_t *joy_wwhack2; +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; -int joy_avail, joy_advancedinit, joy_haspov; -DWORD joy_oldbuttonstate, joy_oldpovstate; +int joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; -int joy_id; -DWORD joy_flags; -DWORD joy_numbuttons; +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; -static JOYINFOEX ji; +static JOYINFOEX ji; /* =========== Force_CenterView_f =========== */ -void Force_CenterView_f (void) +void Force_CenterView_f( void ) { vec3_t viewangles; - if (!iMouseInUse) + if( !iMouseInUse ) { gEngfuncs.GetViewAngles( (float *)viewangles ); - viewangles[PITCH] = 0; + viewangles[PITCH] = 0; gEngfuncs.SetViewAngles( (float *)viewangles ); } } @@ -166,12 +166,12 @@ void Force_CenterView_f (void) IN_ActivateMouse =========== */ -void DLLEXPORT IN_ActivateMouse (void) +void DLLEXPORT IN_ActivateMouse( void ) { - if (mouseinitialized) + if( mouseinitialized ) { - if (mouseparmsvalid) - restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + if( mouseparmsvalid ) + restore_spi = SystemParametersInfo( SPI_SETMOUSE, 0, newmouseparms, 0 ); mouseactive = 1; } } @@ -181,13 +181,12 @@ void DLLEXPORT IN_ActivateMouse (void) IN_DeactivateMouse =========== */ -void DLLEXPORT IN_DeactivateMouse (void) +void DLLEXPORT IN_DeactivateMouse( void ) { - if (mouseinitialized) + if( mouseinitialized ) { - if (restore_spi) - SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); - + if( restore_spi ) + SystemParametersInfo( SPI_SETMOUSE, 0, originalmouseparms, 0 ); mouseactive = 0; } } @@ -197,26 +196,26 @@ void DLLEXPORT IN_DeactivateMouse (void) IN_StartupMouse =========== */ -void IN_StartupMouse (void) +void IN_StartupMouse( void ) { - if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) - return; + if( gEngfuncs.CheckParm( "-nomouse", NULL ) ) + return; mouseinitialized = 1; - mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + mouseparmsvalid = SystemParametersInfo( SPI_GETMOUSE, 0, originalmouseparms, 0 ); - if (mouseparmsvalid) + if( mouseparmsvalid ) { - if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + if( gEngfuncs.CheckParm( "-noforcemspd", NULL ) ) newmouseparms[2] = originalmouseparms[2]; - if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + if( gEngfuncs.CheckParm( "-noforcemaccel", NULL ) ) { newmouseparms[0] = originalmouseparms[0]; newmouseparms[1] = originalmouseparms[1]; } - if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + if( gEngfuncs.CheckParm( "-noforcemparms", NULL ) ) { newmouseparms[0] = originalmouseparms[0]; newmouseparms[1] = originalmouseparms[1]; @@ -232,7 +231,7 @@ void IN_StartupMouse (void) IN_Shutdown =========== */ -void IN_Shutdown (void) +void IN_Shutdown( void ) { IN_DeactivateMouse (); } @@ -258,7 +257,7 @@ FIXME: Call through to engine? */ void IN_ResetMouse( void ) { - SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); + SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); } /* @@ -266,29 +265,29 @@ void IN_ResetMouse( void ) IN_MouseEvent =========== */ -void DLLEXPORT IN_MouseEvent (int mstate) +void DLLEXPORT IN_MouseEvent( int mstate ) { - int i; + int i; - if ( iMouseInUse || g_iVisibleMouse ) + if( iMouseInUse || g_iVisibleMouse ) return; // perform button actions - for (i=0 ; ivalue) + if( m_filter->value ) { - mouse_x = (mx + old_mouse_x) * 0.5; - mouse_y = (my + old_mouse_y) * 0.5; + mouse_x = ( mx + old_mouse_x ) * 0.5; + mouse_y = ( my + old_mouse_y ) * 0.5; } else { @@ -330,7 +329,7 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) old_mouse_x = mx; old_mouse_y = my; - if ( gHUD.GetSensitivity() != 0 ) + if( gHUD.GetSensitivity() != 0 ) { mouse_x *= gHUD.GetSensitivity(); mouse_y *= gHUD.GetSensitivity(); @@ -342,22 +341,22 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) } // add mouse X/Y movement to cmd - if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + if( ( in_strafe.state & 1 ) || ( lookstrafe->value && ( in_mlook.state & 1 ) ) ) cmd->sidemove += m_side->value * mouse_x; else viewangles[YAW] -= m_yaw->value * mouse_x; - if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + if( ( in_mlook.state & 1 ) && !( in_strafe.state & 1 ) ) { viewangles[PITCH] += m_pitch->value * mouse_y; - if (viewangles[PITCH] > cl_pitchdown->value) + if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) + if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; } else { - if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + if( ( in_strafe.state & 1 ) && gEngfuncs.IsNoClipping() ) { cmd->upmove -= m_forward->value * mouse_y; } @@ -368,7 +367,7 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) } // if the mouse has moved, force it to the center, so there's room to move - if ( mx || my ) + if( mx || my ) { IN_ResetMouse(); } @@ -394,14 +393,14 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) IN_Accumulate =========== */ -void DLLEXPORT IN_Accumulate (void) +void DLLEXPORT IN_Accumulate( void ) { //only accumulate mouse if we are not moving the camera with the mouse - if ( !iMouseInUse && !g_iVisibleMouse ) + if( !iMouseInUse && !g_iVisibleMouse ) { - if (mouseactive) - { - GetCursorPos (¤t_pos); + if( mouseactive ) + { + GetCursorPos( ¤t_pos ); mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); @@ -410,7 +409,6 @@ void DLLEXPORT IN_Accumulate (void) IN_ResetMouse(); } } - } /* @@ -418,9 +416,9 @@ void DLLEXPORT IN_Accumulate (void) IN_ClearStates =================== */ -void DLLEXPORT IN_ClearStates (void) +void DLLEXPORT IN_ClearStates( void ) { - if ( !mouseactive ) + if( !mouseactive ) return; mx_accum = 0; @@ -433,50 +431,50 @@ void DLLEXPORT IN_ClearStates (void) IN_StartupJoystick =============== */ -void IN_StartupJoystick (void) +void IN_StartupJoystick( void ) { - int numdevs; - JOYCAPS jc; - MMRESULT mmr; - - // assume no joystick + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick joy_avail = 0; // abort startup if user requests no joystick - if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) - return; - + if( gEngfuncs.CheckParm( "-nojoy", NULL ) ) + return; + // verify joystick driver is present - if ((numdevs = joyGetNumDevs ()) == 0) + if( ( numdevs = joyGetNumDevs() ) == 0 ) { - gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + gEngfuncs.Con_DPrintf( "joystick not found -- driver not present\n\n" ); return; } // cycle through the joystick ids for the first valid one - for (joy_id=0 ; joy_idvalue == 0.0) + if( joy_advanced->value == 0.0 ) { // default joystick initialization // 2 axes only with joystick control @@ -554,134 +549,130 @@ void Joy_AdvancedUpdate_f (void) } else { - if ( strcmp ( joy_name->string, "joystick") != 0 ) + if( strcmp( joy_name->string, "joystick" ) != 0 ) { // notify user of advanced controller - gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + gEngfuncs.Con_Printf( "\n%s configured\n\n", joy_name->string ); } // advanced initialization here // data supplied by user via joy_axisn cvars - dwTemp = (DWORD) joy_advaxisx->value; + dwTemp = (DWORD)joy_advaxisx->value; dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisy->value; + dwTemp = (DWORD)joy_advaxisy->value; dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisz->value; + dwTemp = (DWORD)joy_advaxisz->value; dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisr->value; + dwTemp = (DWORD)joy_advaxisr->value; dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisu->value; + dwTemp = (DWORD)joy_advaxisu->value; dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD) joy_advaxisv->value; + dwTemp = (DWORD)joy_advaxisv->value; dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; } // compute the axes to collect from DirectInput joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; - for (i = 0; i < JOY_MAX_AXES; i++) + for( i = 0; i < JOY_MAX_AXES; i++ ) { - if (dwAxisMap[i] != AxisNada) + if( dwAxisMap[i] != AxisNada ) { joy_flags |= dwAxisFlags[i]; } } } - /* =========== IN_Commands =========== */ -void IN_Commands (void) +void IN_Commands( void ) { - int i, key_index; - DWORD buttonstate, povstate; + int i, key_index; + DWORD buttonstate, povstate; - if (!joy_avail) + if( !joy_avail ) { return; } - // loop through the joystick buttons // key a joystick event or auxillary event for higher number buttons for each state change buttonstate = ji.dwButtons; - for (i=0 ; i < (int)joy_numbuttons ; i++) + for( i = 0; i < (int)joy_numbuttons; i++ ) { - if ( (buttonstate & (1<value != 0.0) + if( joy_wwhack1->value != 0.0 ) { ji.dwUpos += 100; } @@ -692,28 +683,26 @@ int IN_ReadJoystick (void) // read error occurred // turning off the joystick seems too harsh for 1 read error,\ // but what should be done? - // Con_Printf ("IN_ReadJoystick: no response\n"); + // Con_Printf( "IN_ReadJoystick: no response\n" ); // joy_avail = 0; return 0; } } - /* =========== IN_JoyMove =========== */ -void IN_JoyMove ( float frametime, usercmd_t *cmd ) +void IN_JoyMove( float frametime, usercmd_t *cmd ) { - float speed, aspeed; - float fAxisValue, fTemp; - int i; + float speed, aspeed; + float fAxisValue, fTemp; + int i; vec3_t viewangles; gEngfuncs.GetViewAngles( (float *)viewangles ); - // complete initialization if first time in // this is needed as cvars are not available at initialization time if( joy_advancedinit != 1 ) @@ -723,18 +712,18 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) } // verify joystick is available and that the user wants to use it - if (!joy_avail || !in_joystick->value) + if( !joy_avail || !in_joystick->value ) { return; } - + // collect the joystick data, if possible - if (IN_ReadJoystick () != 1) + if( IN_ReadJoystick () != 1 ) { return; } - if (in_speed.state & 1) + if( in_speed.state & 1 ) speed = cl_movespeedkey->value; else speed = 1; @@ -742,126 +731,121 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) aspeed = speed * frametime; // loop through the axes - for (i = 0; i < JOY_MAX_AXES; i++) + for( i = 0; i < JOY_MAX_AXES; i++ ) { // get the floating point zero-centered, potentially-inverted data for the current axis fAxisValue = (float) *pdwRawValue[i]; // move centerpoint to zero fAxisValue -= 32768.0; - if (joy_wwhack2->value != 0.0) + if( joy_wwhack2->value != 0.0 ) { - if (dwAxisMap[i] == AxisTurn) + if( dwAxisMap[i] == AxisTurn ) { // this is a special formula for the Logitech WingMan Warrior // y=ax^b; where a = 300 and b = 1.3 // also x values are in increments of 800 (so this is factored out) // then bounds check result to level out excessively high spin rates - fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); - if (fTemp > 14000.0) + fTemp = 300.0 * pow( abs( fAxisValue ) / 800.0, 1.3 ); + if( fTemp > 14000.0 ) fTemp = 14000.0; // restore direction information - fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + fAxisValue = ( fAxisValue > 0.0 ) ? fTemp : -fTemp; } } - // convert range from -32768..32767 to -1..1 + // convert range from -32768..32767 to -1..1 fAxisValue /= 32768.0; - switch (dwAxisMap[i]) + switch( dwAxisMap[i] ) { case AxisForward: - if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + if( ( joy_advanced->value == 0.0 ) && ( in_jlook.state & 1 ) ) { // user wants forward control to become look control - if (fabs(fAxisValue) > joy_pitchthreshold->value) - { + if( fabs( fAxisValue ) > joy_pitchthreshold->value ) + { // if mouse invert is on, invert the joystick pitch value // only absolute control support here (joy_advanced is 0) - if (m_pitch->value < 0.0) + if( m_pitch->value < 0.0 ) { - viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] -= ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; } else { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; } } } else { // user wants forward control to be forward control - if (fabs(fAxisValue) > joy_forwardthreshold->value) + if( fabs( fAxisValue ) > joy_forwardthreshold->value ) { - cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + cmd->forwardmove += ( fAxisValue * joy_forwardsensitivity->value ) * speed * cl_forwardspeed->value; } } break; - case AxisSide: - if (fabs(fAxisValue) > joy_sidethreshold->value) + if( fabs( fAxisValue ) > joy_sidethreshold->value ) { - cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + cmd->sidemove += ( fAxisValue * joy_sidesensitivity->value ) * speed * cl_sidespeed->value; } break; - case AxisTurn: - if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + if( ( in_strafe.state & 1 ) || ( lookstrafe->value && ( in_jlook.state & 1 ) ) ) { // user wants turn control to become side control - if (fabs(fAxisValue) > joy_sidethreshold->value) + if( fabs( fAxisValue ) > joy_sidethreshold->value ) { - cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + cmd->sidemove -= ( fAxisValue * joy_sidesensitivity->value ) * speed * cl_sidespeed->value; } } else { // user wants turn control to be turn control - if (fabs(fAxisValue) > joy_yawthreshold->value) + if( fabs( fAxisValue ) > joy_yawthreshold->value ) { - if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) { - viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * aspeed * cl_yawspeed->value; } else { - viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * speed * 180.0; } } } break; - case AxisLook: - if (in_jlook.state & 1) + if( in_jlook.state & 1 ) { - if (fabs(fAxisValue) > joy_pitchthreshold->value) + if( fabs( fAxisValue ) > joy_pitchthreshold->value ) { // pitch movement detected and pitch movement desired by user - if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; } else { - viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * speed * 180.0; } } } break; - default: break; } } // bounds check pitch - if (viewangles[PITCH] > cl_pitchdown->value) + if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) + if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; gEngfuncs.SetViewAngles( (float *)viewangles ); - } /* @@ -869,14 +853,14 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) IN_Move =========== */ -void IN_Move ( float frametime, usercmd_t *cmd) +void IN_Move( float frametime, usercmd_t *cmd ) { - if ( !iMouseInUse && mouseactive ) + if( !iMouseInUse && mouseactive ) { - IN_MouseMove ( frametime, cmd); + IN_MouseMove( frametime, cmd ); } - IN_JoyMove ( frametime, cmd); + IN_JoyMove( frametime, cmd ); } /* @@ -884,30 +868,30 @@ void IN_Move ( float frametime, usercmd_t *cmd) IN_Init =========== */ -void IN_Init (void) +void IN_Init( void ) { - m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); - sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + m_filter = gEngfuncs.pfnRegisterVariable( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. - in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); - joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); - joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); - joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); - joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); - joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); - joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); - joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); - joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); - joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); - joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); - joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); - joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); - joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); - joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); - joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); - joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); - joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); - joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + in_joystick = gEngfuncs.pfnRegisterVariable( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable( "joywwhack2", "0.0", 0 ); gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h index 23cd8acc..29accdf5 100644 --- a/cl_dll/kbutton.h +++ b/cl_dll/kbutton.h @@ -11,8 +11,7 @@ typedef struct kbutton_s { - int down[2]; // key nums holding it down - int state; // low bit is down state + int down[2]; // key nums holding it down + int state; // low bit is down state } kbutton_t; - -#endif // !KBUTTONH \ No newline at end of file +#endif // !KBUTTONH diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index 2ed362fb..5f710a33 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -17,6 +17,7 @@ // // generic menu handler // + #include "hud.h" #include "cl_util.h" #include "parsemsg.h" @@ -31,7 +32,7 @@ int KB_ConvertString( char *in, char **ppout ); DECLARE_MESSAGE( m_Menu, ShowMenu ) -int CHudMenu :: Init( void ) +int CHudMenu::Init( void ) { gHUD.AddHudElem( this ); @@ -42,33 +43,34 @@ int CHudMenu :: Init( void ) return 1; } -void CHudMenu :: InitHUDData( void ) +void CHudMenu::InitHUDData( void ) { m_fMenuDisplayed = 0; m_bitsValidSlots = 0; Reset(); } -void CHudMenu :: Reset( void ) +void CHudMenu::Reset( void ) { g_szPrelocalisedMenuString[0] = 0; m_fWaitingForMore = FALSE; } -int CHudMenu :: VidInit( void ) +int CHudMenu::VidInit( void ) { return 1; } -int CHudMenu :: Draw( float flTime ) +int CHudMenu::Draw( float flTime ) { int i; // check for if menu is set to disappear - if ( m_flShutoffTime > 0 ) + if( m_flShutoffTime > 0 ) { - if ( m_flShutoffTime <= gHUD.m_flTime ) - { // times up, shutoff + if( m_flShutoffTime <= gHUD.m_flTime ) + { + // times up, shutoff m_fMenuDisplayed = 0; m_iFlags &= ~HUD_ACTIVE; return 1; @@ -76,43 +78,39 @@ int CHudMenu :: Draw( float flTime ) } // don't draw the menu if the scoreboard is being shown - - - // draw the menu, along the left-hand side of the screen - // count the number of newlines int nlc = 0; - for ( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + for( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) { if ( g_szMenuString[i] == '\n' ) nlc++; } // center it - int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text + int y = ( ScreenHeight / 2 ) - ( ( nlc / 2 ) * 12 ) - 40; // make sure it is above the say text int x = 20; i = 0; - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) + while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) { gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); y += 12; - while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) + while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) i++; - if ( g_szMenuString[i] == '\n' ) + if( g_szMenuString[i] == '\n' ) i++; } - + return 1; } // selects an item from the menu -void CHudMenu :: SelectMenuItem( int menu_item ) +void CHudMenu::SelectMenuItem( int menu_item ) { // if menu_item is in a valid slot, send a menuselect command to the server - if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) + if( ( menu_item > 0 ) && ( m_bitsValidSlots & ( 1 << ( menu_item - 1 ) ) ) ) { char szbuf[32]; sprintf( szbuf, "menuselect %d\n", menu_item ); @@ -124,7 +122,6 @@ void CHudMenu :: SelectMenuItem( int menu_item ) } } - // Message handler for ShowMenu message // takes four values: // short: a bitfield of keys that are valid input @@ -132,7 +129,7 @@ void CHudMenu :: SelectMenuItem( int menu_item ) // byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string // string: menu string to display // if this message is never received, then scores will simply be the combined totals of the players. -int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) +int CHudMenu::MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) { char *temp = NULL; @@ -142,29 +139,31 @@ int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) int DisplayTime = READ_CHAR(); int NeedMore = READ_BYTE(); - if ( DisplayTime > 0 ) + if( DisplayTime > 0 ) m_flShutoffTime = DisplayTime + gHUD.m_flTime; else m_flShutoffTime = -1; - if ( m_bitsValidSlots ) + if( m_bitsValidSlots ) { - if ( !m_fWaitingForMore ) // this is the start of a new menu + if( !m_fWaitingForMore ) // this is the start of a new menu { strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING ); } else - { // append to the current menu string - strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); + { + // append to the current menu string + strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen( g_szPrelocalisedMenuString ) ); } - g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) + g_szPrelocalisedMenuString[MAX_MENU_STRING - 1] = 0; // ensure null termination (strncat/strncpy does not) - if ( !NeedMore ) - { // we have the whole string, so we can localise it now + if( !NeedMore ) + { + // we have the whole string, so we can localise it now strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); // Swap in characters - if ( KB_ConvertString( g_szMenuString, &temp ) ) + if( KB_ConvertString( g_szMenuString, &temp ) ) { strcpy( g_szMenuString, temp ); free( temp ); diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index bb93bb5a..a9c706ec 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -32,12 +32,12 @@ client_textmessage_t g_pCustomMessage; char *g_pCustomName = "Custom"; char g_pCustomText[1024]; -int CHudMessage::Init(void) +int CHudMessage::Init( void ) { HOOK_MESSAGE( HudText ); HOOK_MESSAGE( GameTitle ); - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); Reset(); @@ -52,33 +52,31 @@ int CHudMessage::VidInit( void ) return 1; } - void CHudMessage::Reset( void ) { - memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); - memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); - + memset( m_pMessages, 0, sizeof(m_pMessages[0]) * maxHUDMessages ); + memset( m_startTime, 0, sizeof(m_startTime[0]) * maxHUDMessages ); + m_gameTitleTime = 0; m_pGameTitle = NULL; } - float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) { float fadeTime = fadein + hold; float fadeBlend; - if ( localTime < 0 ) + if( localTime < 0 ) return 0; - if ( localTime < fadein ) + if( localTime < fadein ) { - fadeBlend = 1 - ((fadein - localTime) / fadein); + fadeBlend = 1 - ( ( fadein - localTime ) / fadein ); } - else if ( localTime > fadeTime ) + else if( localTime > fadeTime ) { - if ( fadeout > 0 ) - fadeBlend = 1 - ((localTime - fadeTime) / fadeout); + if( fadeout > 0 ) + fadeBlend = 1 - ( ( localTime - fadeTime ) / fadeout ); else fadeBlend = 0; } @@ -89,42 +87,41 @@ float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float loc } -int CHudMessage::XPosition( float x, int width, int totalWidth ) +int CHudMessage::XPosition( float x, int width, int totalWidth ) { int xPos; - if ( x == -1 ) + if( x == -1 ) { - xPos = (ScreenWidth - width) / 2; + xPos = ( ScreenWidth - width ) / 2; } else { - if ( x < 0 ) - xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right + if( x < 0 ) + xPos = ( 1.0 + x ) * ScreenWidth - totalWidth; // Alight right else xPos = x * ScreenWidth; } - if ( xPos + width > ScreenWidth ) + if( xPos + width > ScreenWidth ) xPos = ScreenWidth - width; - else if ( xPos < 0 ) + else if( xPos < 0 ) xPos = 0; return xPos; } - int CHudMessage::YPosition( float y, int height ) { int yPos; - if ( y == -1 ) // Centered? - yPos = (ScreenHeight - height) * 0.5; + if( y == -1 ) // Centered? + yPos = ( ScreenHeight - height ) * 0.5; else { // Alight bottom? if ( y < 0 ) - yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom + yPos = ( 1.0 + y ) * ScreenHeight - height; // Alight bottom else // align top yPos = y * ScreenHeight; } @@ -137,7 +134,6 @@ int CHudMessage::YPosition( float y, int height ) return yPos; } - void CHudMessage::MessageScanNextChar( void ) { int srcRed, srcGreen, srcBlue, destRed = 0, destGreen = 0, destBlue = 0; @@ -156,10 +152,9 @@ void CHudMessage::MessageScanNextChar( void ) destRed = destGreen = destBlue = 0; blend = m_parms.fadeBlend; break; - case 2: m_parms.charTime += m_parms.pMessage->fadein; - if ( m_parms.charTime > m_parms.time ) + if( m_parms.charTime > m_parms.time ) { srcRed = srcGreen = srcBlue = 0; blend = 0; // pure source @@ -185,23 +180,22 @@ void CHudMessage::MessageScanNextChar( void ) } break; } - if ( blend > 255 ) + if( blend > 255 ) blend = 255; - else if ( blend < 0 ) + else if( blend < 0 ) blend = 0; - m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; - m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; - m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; + m_parms.r = ( ( srcRed * ( 255 - blend ) ) + ( destRed * blend ) ) >> 8; + m_parms.g = ( ( srcGreen * (255 - blend ) ) + ( destGreen * blend ) ) >> 8; + m_parms.b = ( ( srcBlue * ( 255 - blend ) ) + ( destBlue * blend ) ) >> 8; - if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) + if( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) { - if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) + if( m_parms.x >= 0 && m_parms.y >= 0 && ( m_parms.x + gHUD.m_scrinfo.charWidths[m_parms.text] ) <= ScreenWidth ) TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); } } - void CHudMessage::MessageScanStart( void ) { switch( m_parms.pMessage->effect ) @@ -212,14 +206,14 @@ void CHudMessage::MessageScanStart( void ) m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; - if ( m_parms.time < m_parms.pMessage->fadein ) + if( m_parms.time < m_parms.pMessage->fadein ) { - m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); + m_parms.fadeBlend = ( ( m_parms.pMessage->fadein - m_parms.time ) * ( 1.0 / m_parms.pMessage->fadein ) * 255 ); } - else if ( m_parms.time > m_parms.fadeTime ) + else if( m_parms.time > m_parms.fadeTime ) { - if ( m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + if( m_parms.pMessage->fadeout > 0 ) + m_parms.fadeBlend = ( ( ( m_parms.time - m_parms.fadeTime ) / m_parms.pMessage->fadeout) * 255); else m_parms.fadeBlend = 255; // Pure dest (off) } @@ -227,15 +221,14 @@ void CHudMessage::MessageScanStart( void ) m_parms.fadeBlend = 0; // Pure source (on) m_parms.charTime = 0; - if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) + if( m_parms.pMessage->effect == 1 && ( rand() % 100 ) < 10 ) m_parms.charTime = 1; break; - case 2: m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) - m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); + m_parms.fadeBlend = ( ( ( m_parms.time - m_parms.fadeTime ) / m_parms.pMessage->fadeout ) * 255 ); else m_parms.fadeBlend = 0; break; @@ -257,12 +250,12 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) length = 0; width = 0; m_parms.totalWidth = 0; - while ( *pText ) + while( *pText ) { - if ( *pText == '\n' ) + if( *pText == '\n' ) { m_parms.lines++; - if ( width > m_parms.totalWidth ) + if( width > m_parms.totalWidth ) m_parms.totalWidth = width; width = 0; } @@ -272,8 +265,7 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) length++; } m_parms.length = length; - m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight); - + m_parms.totalHeight = ( m_parms.lines * gHUD.m_scrinfo.iCharHeight ); m_parms.y = YPosition( pMessage->y, m_parms.totalHeight ); pText = pMessage->pMessage; @@ -282,11 +274,11 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) MessageScanStart(); - for ( i = 0; i < m_parms.lines; i++ ) + for( i = 0; i < m_parms.lines; i++ ) { m_parms.lineLength = 0; m_parms.width = 0; - while ( *pText && *pText != '\n' ) + while( *pText && *pText != '\n' ) { unsigned char c = *pText; line[m_parms.lineLength] = c; @@ -299,13 +291,13 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); - for ( j = 0; j < m_parms.lineLength; j++ ) + for( j = 0; j < m_parms.lineLength; j++ ) { m_parms.text = line[j]; - int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]; + int next = m_parms.x + gHUD.m_scrinfo.charWidths[m_parms.text]; MessageScanNextChar(); - - if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth ) + + if( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth ) TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); m_parms.x = next; } @@ -314,7 +306,6 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) } } - int CHudMessage::Draw( float fTime ) { int i, drawn; @@ -323,53 +314,52 @@ int CHudMessage::Draw( float fTime ) drawn = 0; - if ( m_gameTitleTime > 0 ) + if( m_gameTitleTime > 0 ) { float localTime = gHUD.m_flTime - m_gameTitleTime; float brightness; // Maybe timer isn't set yet - if ( m_gameTitleTime > gHUD.m_flTime ) + if( m_gameTitleTime > gHUD.m_flTime ) m_gameTitleTime = gHUD.m_flTime; - if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) ) + if( localTime > ( m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout ) ) m_gameTitleTime = 0; else { brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime ); - int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left; - int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left; - int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top; + int halfWidth = gHUD.GetSpriteRect( m_HUD_title_half ).right - gHUD.GetSpriteRect( m_HUD_title_half ).left; + int fullWidth = halfWidth + gHUD.GetSpriteRect( m_HUD_title_life ).right - gHUD.GetSpriteRect( m_HUD_title_life ).left; + int fullHeight = gHUD.GetSpriteRect( m_HUD_title_half ).bottom - gHUD.GetSpriteRect( m_HUD_title_half ).top; int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth ); int y = YPosition( m_pGameTitle->y, fullHeight ); + SPR_Set( gHUD.GetSprite( m_HUD_title_half ), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_title_half ) ); - SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) ); - - SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); - SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) ); + SPR_Set( gHUD.GetSprite( m_HUD_title_life ), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 ); + SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect( m_HUD_title_life ) ); drawn = 1; } } // Fixup level transitions - for ( i = 0; i < maxHUDMessages; i++ ) + for( i = 0; i < maxHUDMessages; i++ ) { // Assume m_parms.time contains last time - if ( m_pMessages[i] ) + if( m_pMessages[i] ) { pMessage = m_pMessages[i]; - if ( m_startTime[i] > gHUD.m_flTime ) + if( m_startTime[i] > gHUD.m_flTime ) m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this } } - for ( i = 0; i < maxHUDMessages; i++ ) + for( i = 0; i < maxHUDMessages; i++ ) { - if ( m_pMessages[i] ) + if( m_pMessages[i] ) { pMessage = m_pMessages[i]; @@ -380,14 +370,14 @@ int CHudMessage::Draw( float fTime ) case 1: endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime; break; - + // Fade in is per character in scanning messages case 2: - endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime; + endTime = m_startTime[i] + ( pMessage->fadein * strlen( pMessage->pMessage ) ) + pMessage->fadeout + pMessage->holdtime; break; } - if ( fTime <= endTime ) + if( fTime <= endTime ) { float messageTime = fTime - m_startTime[i]; @@ -410,29 +400,28 @@ int CHudMessage::Draw( float fTime ) // Remember the time -- to fix up level transitions m_parms.time = gHUD.m_flTime; // Don't call until we get another message - if ( !drawn ) + if( !drawn ) m_iFlags &= ~HUD_ACTIVE; return 1; } - void CHudMessage::MessageAdd( const char *pName, float time ) { - int i,j; + int i, j; client_textmessage_t *tempMessage; - for ( i = 0; i < maxHUDMessages; i++ ) + for( i = 0; i < maxHUDMessages; i++ ) { - if ( !m_pMessages[i] ) + if( !m_pMessages[i] ) { // Trim off a leading # if it's there - if ( pName[0] == '#' ) - tempMessage = TextMessageGet( pName+1 ); + if( pName[0] == '#' ) + tempMessage = TextMessageGet( pName + 1 ); else tempMessage = TextMessageGet( pName ); // If we couldnt find it in the titles.txt, just create it - if ( !tempMessage ) + if( !tempMessage ) { g_pCustomMessage.effect = 2; g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; @@ -453,18 +442,18 @@ void CHudMessage::MessageAdd( const char *pName, float time ) tempMessage = &g_pCustomMessage; } - for ( j = 0; j < maxHUDMessages; j++ ) + for( j = 0; j < maxHUDMessages; j++ ) { - if ( m_pMessages[j] ) + if( m_pMessages[j] ) { // is this message already in the list - if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) + if( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) { return; } // get rid of any other messages in same location (only one displays at a time) - if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) + if( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) { if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) { @@ -481,7 +470,6 @@ void CHudMessage::MessageAdd( const char *pName, float time ) } } - int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); @@ -489,48 +477,47 @@ int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) char *pString = READ_STRING(); MessageAdd( pString, gHUD.m_flTime ); + // Remember the time -- to fix up level transitions m_parms.time = gHUD.m_flTime; // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) + if( !( m_iFlags & HUD_ACTIVE ) ) m_iFlags |= HUD_ACTIVE; return 1; } - int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) { m_pGameTitle = TextMessageGet( "GAMETITLE" ); - if ( m_pGameTitle != NULL ) + if( m_pGameTitle != NULL ) { m_gameTitleTime = gHUD.m_flTime; // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) + if( !( m_iFlags & HUD_ACTIVE ) ) m_iFlags |= HUD_ACTIVE; } return 1; } -void CHudMessage::MessageAdd(client_textmessage_t * newMessage ) +void CHudMessage::MessageAdd( client_textmessage_t * newMessage ) { m_parms.time = gHUD.m_flTime; // Turn on drawing - if ( !(m_iFlags & HUD_ACTIVE) ) + if( !( m_iFlags & HUD_ACTIVE ) ) m_iFlags |= HUD_ACTIVE; - - for ( int i = 0; i < maxHUDMessages; i++ ) + + for( int i = 0; i < maxHUDMessages; i++ ) { - if ( !m_pMessages[i] ) + if( !m_pMessages[i] ) { m_pMessages[i] = newMessage; m_startTime[i] = gHUD.m_flTime; return; } } - } diff --git a/cl_dll/overview.cpp b/cl_dll/overview.cpp index 04f1a984..881812f7 100644 --- a/cl_dll/overview.cpp +++ b/cl_dll/overview.cpp @@ -34,8 +34,8 @@ int CHudOverview::Init() //----------------------------------------------------------------------------- int CHudOverview::VidInit() { - m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); - m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); + m_hsprPlayer = gEngfuncs.pfnSPR_Load( "sprites/ring.spr" ); + m_hsprViewcone = gEngfuncs.pfnSPR_Load( "sprites/camera.spr" ); return 1; } @@ -45,42 +45,42 @@ int CHudOverview::VidInit() // Input : flTime - // intermission - //----------------------------------------------------------------------------- -int CHudOverview::Draw(float flTime) +int CHudOverview::Draw( float flTime ) { #if 0 // only draw in overview mode - if (!gEngfuncs.Overview_GetOverviewState()) + if( !gEngfuncs.Overview_GetOverviewState() ) return 1; // make sure we have player info -// gViewPort->GetAllPlayersInfo(); + //gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); // calculate player size on the overview int x1, y1, x2, y2; - float v0[3]={0,0,0}, v1[3]={64,64,0}; - gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); - gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); - float scale = abs(x2 - x1); + float v0[3] = { 0.0f }, v1[3] = { 64.0f, 64.0f }; + gEngfuncs.Overview_WorldToScreen( v0, &x1, &y1 ); + gEngfuncs.Overview_WorldToScreen( v1, &x2, &y2 ); + float scale = abs( x2 - x1 ); // loop through all the players and draw them on the map - for (int i = 1; i < MAX_PLAYERS; i++) + for( int i = 1; i < MAX_PLAYERS; i++ ) { - cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( i ); - if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) + if( pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT ) { int x, y, z = 0; - float v[3]={pl->origin[0], pl->origin[1], 0}; - gEngfuncs.Overview_WorldToScreen(v, &x, &y); + float v[3] = { pl->origin[0], pl->origin[1], 0 }; + gEngfuncs.Overview_WorldToScreen( v, &x, &y ); // hack in some team colors float r, g, bc; - if (g_PlayerExtraInfo[i].teamnumber == 1) + if( g_PlayerExtraInfo[i].teamnumber == 1 ) { r = 0.0f; g = 0.0f; bc = 1.0f; } - else if (g_PlayerExtraInfo[i].teamnumber == 2) + else if( g_PlayerExtraInfo[i].teamnumber == 2 ) { r = 1.0f; g = 0.0f; bc = 0.0f; } @@ -91,50 +91,50 @@ int CHudOverview::Draw(float flTime) } // set the current texture - gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); + gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprPlayer ), 0 ); // additive render mode - gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); // no culling - gEngfuncs.pTriAPI->CullFace(TRI_NONE); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); // draw a square - gEngfuncs.pTriAPI->Begin(TRI_QUADS); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); // set the color to be that of the team - gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); + gEngfuncs.pTriAPI->Color4f( r, g, bc, 1.0f ); // calculate rotational matrix vec3_t a, b, angles; float rmatrix[3][4]; // transformation matrix - VectorCopy(pl->angles, angles); + VectorCopy( pl->angles, angles ); angles[0] = 0.0f; angles[1] += 90.f; angles[1] = -angles[1]; angles[2] = 0.0f; - AngleMatrix(angles, rmatrix); + AngleMatrix( angles, rmatrix ); a[2] = 0; a[0] = -scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); + VectorTransform( a, rmatrix, b ); gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); + gEngfuncs.pTriAPI->Vertex3f( x + b[0], y + b[1], z ); - a[0]=-scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); + a[0] = -scale; a[1] = scale; + VectorTransform( a, rmatrix, b ); gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); - - a[0]=scale; a[1] = scale; - VectorTransform(a, rmatrix , b ); - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + gEngfuncs.pTriAPI->Vertex3f( x + b[0], y + b[1], z ); - a[0]=scale; a[1] = -scale; - VectorTransform(a, rmatrix , b ); + a[0] = scale; a[1] = scale; + VectorTransform( a, rmatrix, b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( x + b[0], y + b[1], z ); + + a[0] = scale; a[1] = -scale; + VectorTransform( a, rmatrix, b ); gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + gEngfuncs.pTriAPI->Vertex3f( x + b[0], y + b[1], z ); // finish up gEngfuncs.pTriAPI->End(); @@ -142,11 +142,10 @@ int CHudOverview::Draw(float flTime) // draw the players name and health underneath char string[256]; - sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); - DrawConsoleString(x, y + (1.1 * scale), string); + sprintf( string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health ); + DrawConsoleString( x, y + ( 1.1 * scale ), string ); } } - #endif return 1; } @@ -156,8 +155,7 @@ int CHudOverview::Draw(float flTime) //----------------------------------------------------------------------------- void CHudOverview::InitHUDData() { -// this block would force the spectator view to be on -// gEngfuncs.Overview_SetDrawOverview( 1 ); -// gEngfuncs.Overview_SetDrawInset( 0 ); + //this block would force the spectator view to be on + //gEngfuncs.Overview_SetDrawOverview( 1 ); + //gEngfuncs.Overview_SetDrawInset( 0 ); } - diff --git a/cl_dll/overview.h b/cl_dll/overview.h index 4de9ae75..6748760b 100644 --- a/cl_dll/overview.h +++ b/cl_dll/overview.h @@ -9,7 +9,6 @@ #define OVERVIEW_H #pragma once - //----------------------------------------------------------------------------- // Purpose: Handles the drawing of the top-down map and all the things on it //----------------------------------------------------------------------------- @@ -19,13 +18,11 @@ public: int Init(); int VidInit(); - int Draw(float flTime); + int Draw( float flTime ); void InitHUDData( void ); private: HSPRITE m_hsprPlayer; HSPRITE m_hsprViewcone; }; - - #endif // OVERVIEW_H diff --git a/cl_dll/parsemsg.cpp b/cl_dll/parsemsg.cpp index f242ff0d..4e58a161 100644 --- a/cl_dll/parsemsg.cpp +++ b/cl_dll/parsemsg.cpp @@ -15,6 +15,7 @@ // // parsemsg.cpp // + typedef unsigned char byte; #define true 1 @@ -31,28 +32,27 @@ void BEGIN_READ( void *buf, int size ) gpBuf = (byte*)buf; } - int READ_CHAR( void ) { - int c; - - if (giRead + 1 > giSize) + int c; + + if( giRead + 1 > giSize ) { giBadRead = true; return -1; } - + c = (signed char)gpBuf[giRead]; giRead++; - + return c; } int READ_BYTE( void ) { - int c; - - if (giRead+1 > giSize) + int c; + + if( giRead + 1 > giSize ) { giBadRead = true; return -1; @@ -66,18 +66,18 @@ int READ_BYTE( void ) int READ_SHORT( void ) { - int c; - - if (giRead+2 > giSize) + int c; + + if( giRead + 2 > giSize ) { giBadRead = true; return -1; } - - c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); - + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead + 1] << 8 ) ); + giRead += 2; - + return c; } @@ -86,21 +86,20 @@ int READ_WORD( void ) return READ_SHORT(); } - int READ_LONG( void ) { - int c; - - if (giRead+4 > giSize) + int c; + + if( giRead + 4 > giSize ) { giBadRead = true; return -1; } - - c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); - + + c = gpBuf[giRead] + ( gpBuf[giRead + 1] << 8 ) + ( gpBuf[giRead + 2] << 16 ) + ( gpBuf[giRead + 3] << 24 ); + giRead += 4; - + return c; } @@ -108,59 +107,58 @@ float READ_FLOAT( void ) { union { - byte b[4]; - float f; - int l; + byte b[4]; + float f; + int l; } dat; - - dat.b[0] = gpBuf[giRead]; - dat.b[1] = gpBuf[giRead+1]; - dat.b[2] = gpBuf[giRead+2]; - dat.b[3] = gpBuf[giRead+3]; - giRead += 4; - -// dat.l = LittleLong (dat.l); - return dat.f; + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead + 1]; + dat.b[2] = gpBuf[giRead + 2]; + dat.b[3] = gpBuf[giRead + 3]; + giRead += 4; + + //dat.l = LittleLong( dat.l ); + + return dat.f; } char* READ_STRING( void ) { - static char string[2048]; - int l,c; + static char string[2048]; + int l, c; string[0] = 0; l = 0; do { - if ( giRead+1 > giSize ) + if( giRead+1 > giSize ) break; // no more characters c = READ_BYTE(); - if (c == -1 || c == 0) + if( c == -1 || c == 0 ) break; string[l] = c; l++; - } while (l < sizeof(string)-1); - + }while( l < sizeof(string) - 1 ); + string[l] = 0; - + return string; } float READ_COORD( void ) { - return (float)(READ_SHORT() * (1.0/8)); + return (float)( READ_SHORT() * ( 1.0 / 8 ) ); } float READ_ANGLE( void ) { - return (float)(READ_CHAR() * (360.0/256)); + return (float)( READ_CHAR() * ( 360.0 / 256 ) ); } float READ_HIRESANGLE( void ) { - return (float)(READ_SHORT() * (360.0/65536)); + return (float)( READ_SHORT() * ( 360.0 / 65536 ) ); } - diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 2f785b83..8f2e2520 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -25,7 +25,6 @@ #include #include - extern float *GetClientColor( int clientIndex ); #define MAX_LINES 5 @@ -36,9 +35,9 @@ extern float *GetClientColor( int clientIndex ); #define LINE_START 10 static float SCROLL_SPEED = 5; -static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; -static float *g_pflNameColors[ MAX_LINES + 1 ]; -static int g_iNameLengths[ MAX_LINES + 1 ]; +static char g_szLineBuffer[MAX_LINES + 1][MAX_CHARS_PER_LINE]; +static float *g_pflNameColors[MAX_LINES + 1]; +static int g_iNameLengths[MAX_LINES + 1]; static float flScrollTime = 0; // the time at which the lines next scroll up static int Y_START = 0; @@ -46,7 +45,7 @@ static int line_height = 0; DECLARE_MESSAGE( m_SayText, SayText ) -int CHudSayText :: Init( void ) +int CHudSayText::Init( void ) { gHUD.AddHudElem( this ); @@ -54,7 +53,7 @@ int CHudSayText :: Init( void ) InitHUDData(); - m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); + m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission @@ -62,20 +61,18 @@ int CHudSayText :: Init( void ) return 1; } - -void CHudSayText :: InitHUDData( void ) +void CHudSayText::InitHUDData( void ) { memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); memset( g_pflNameColors, 0, sizeof g_pflNameColors ); memset( g_iNameLengths, 0, sizeof g_iNameLengths ); } -int CHudSayText :: VidInit( void ) +int CHudSayText::VidInit( void ) { return 1; } - int ScrollTextUp( void ) { ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer @@ -85,7 +82,7 @@ int ScrollTextUp( void ) memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); g_szLineBuffer[MAX_LINES-1][0] = 0; - if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines + if( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines { g_szLineBuffer[0][0] = 2; return 1 + ScrollTextUp(); @@ -94,7 +91,7 @@ int ScrollTextUp( void ) return 1; } -int CHudSayText :: Draw( float flTime ) +int CHudSayText::Draw( float flTime ) { int y = Y_START; @@ -104,32 +101,33 @@ int CHudSayText :: Draw( float flTime ) // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); - if ( flScrollTime <= flTime ) + if( flScrollTime <= flTime ) { - if ( *g_szLineBuffer[0] ) + if( *g_szLineBuffer[0] ) { flScrollTime = flTime + m_HUD_saytext_time->value; // push the console up ScrollTextUp(); } else - { // buffer is empty, just disable drawing of this section + { + // buffer is empty, just disable drawing of this section m_iFlags &= ~HUD_ACTIVE; } } - for ( int i = 0; i < MAX_LINES; i++ ) + for( int i = 0; i < MAX_LINES; i++ ) { - if ( *g_szLineBuffer[i] ) + if( *g_szLineBuffer[i] ) { - if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + if( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) { // it's a saytext string - static char buf[MAX_PLAYER_NAME_LENGTH+32]; + static char buf[MAX_PLAYER_NAME_LENGTH + 32]; // draw the first x characters in the player color - strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); - buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH + 32 ) ); + buf[min( g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH + 31 )] = 0; DrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); int x = DrawConsoleString( LINE_START, y, buf ); @@ -146,32 +144,31 @@ int CHudSayText :: Draw( float flTime ) y += line_height; } - return 1; } -int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) +int CHudSayText::MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int client_index = READ_BYTE(); // the client who spoke the message SayTextPrint( READ_STRING(), iSize - 1, client_index ); - + return 1; } -void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) +void CHudSayText::SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) { int i; ConsolePrint( pszBuf ); // find an empty string slot - for ( i = 0; i < MAX_LINES; i++ ) + for( i = 0; i < MAX_LINES; i++ ) { - if ( ! *g_szLineBuffer[i] ) + if( !( *g_szLineBuffer[i] ) ) break; } - if ( i == MAX_LINES ) + if( i == MAX_LINES ) { // force scroll buffer up ScrollTextUp(); @@ -182,30 +179,30 @@ void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIn g_pflNameColors[i] = NULL; // if it's a say message, search for the players name in the string - if ( *pszBuf == 2 && clientIndex > 0 ) + if( *pszBuf == 2 && clientIndex > 0 ) { GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); const char *pName = g_PlayerInfoList[clientIndex].name; - if ( pName ) + if( pName ) { const char *nameInString = strstr( pszBuf, pName ); - if ( nameInString ) + if( nameInString ) { - g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); + g_iNameLengths[i] = strlen( pName ) + ( nameInString - pszBuf ); g_pflNameColors[i] = GetClientColor( clientIndex ); } } } - strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); + strncpy( g_szLineBuffer[i], pszBuf, max( iBufSize - 1, MAX_CHARS_PER_LINE - 1 ) ); // make sure the text fits in one line EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); // Set scroll time - if ( i == 0 ) + if( i == 0 ) { flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; } @@ -213,56 +210,57 @@ void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIn m_iFlags |= HUD_ACTIVE; PlaySound( "misc/talk.wav", 1 ); - if ( ScreenHeight >= 480 ) + if( ScreenHeight >= 480 ) Y_START = ScreenHeight - 60; else Y_START = ScreenHeight - 45; - Y_START -= (line_height * (MAX_LINES+1)); - + Y_START -= ( line_height * ( MAX_LINES + 1 ) ); } -void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) +void CHudSayText::EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) { int line_width = 0; GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); - if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) - { // string is too long to fit on line + if( ( line_width + LINE_START ) > MAX_LINE_WIDTH ) + { + // string is too long to fit on line // scan the string until we find what word is too long, and wrap the end of the sentence after the word int length = LINE_START; int tmp_len = 0; char *last_break = NULL; - for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) + for( char *x = g_szLineBuffer[line]; *x != 0; x++ ) { // check for a color change, if so skip past it - if ( x[0] == '/' && x[1] == '(' ) + if( x[0] == '/' && x[1] == '(' ) { x += 2; // skip forward until past mode specifier while ( *x != 0 && *x != ')' ) x++; - if ( *x != 0 ) + if( *x != 0 ) x++; - if ( *x == 0 ) + if( *x == 0 ) break; } char buf[2]; buf[1] = 0; - if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character + if( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character last_break = x; buf[0] = *x; // get the length of the current character GetConsoleStringSize( buf, &tmp_len, &line_height ); length += tmp_len; - if ( length > MAX_LINE_WIDTH ) - { // needs to be broken up - if ( !last_break ) - last_break = x-1; + if( length > MAX_LINE_WIDTH ) + { + // needs to be broken up + if( !last_break ) + last_break = x - 1; x = last_break; @@ -270,33 +268,33 @@ void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) int j; do { - for ( j = 0; j < MAX_LINES; j++ ) + for( j = 0; j < MAX_LINES; j++ ) { - if ( ! *g_szLineBuffer[j] ) + if( !( *g_szLineBuffer[j] ) ) break; } - if ( j == MAX_LINES ) + if( j == MAX_LINES ) { // need to make more room to display text, scroll stuff up then fix the pointers int linesmoved = ScrollTextUp(); line -= linesmoved; - last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + last_break = last_break - ( sizeof(g_szLineBuffer[0]) * linesmoved ); } } - while ( j == MAX_LINES ); + while( j == MAX_LINES ); // copy remaining string into next buffer, making sure it starts with a space character - if ( (char)*last_break == (char)' ' ) + if( (char)*last_break == (char)' ' ) { - int linelen = strlen(g_szLineBuffer[j]); - int remaininglen = strlen(last_break); + int linelen = strlen( g_szLineBuffer[j] ); + int remaininglen = strlen( last_break ); - if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) + if( ( linelen - remaininglen ) <= MAX_CHARS_PER_LINE ) strcat( g_szLineBuffer[j], last_break ); } else { - if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) + if ( ( strlen( g_szLineBuffer[j] ) - strlen( last_break ) - 2 ) < MAX_CHARS_PER_LINE ) { strcat( g_szLineBuffer[j], " " ); strcat( g_szLineBuffer[j], last_break ); diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index adcbb3e7..62d140e1 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -27,9 +27,9 @@ #include cvar_t *cl_showpacketloss; -hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine -extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll -team_info_t g_TeamInfo[MAX_TEAMS+1]; +hud_player_info_t g_PlayerInfoList[MAX_PLAYERS + 1]; // player info from the engine +extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS + 1]; // additional player info sent directly to the client dll +team_info_t g_TeamInfo[MAX_TEAMS + 1]; int g_iUser1; int g_iUser2; int g_iUser3; @@ -45,7 +45,7 @@ DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ) DECLARE_MESSAGE( m_Scoreboard, TeamInfo ) DECLARE_MESSAGE( m_Scoreboard, TeamScore ) -int CHudScoreboard :: Init( void ) +int CHudScoreboard::Init( void ) { gHUD.AddHudElem( this ); @@ -64,14 +64,13 @@ int CHudScoreboard :: Init( void ) return 1; } - -int CHudScoreboard :: VidInit( void ) +int CHudScoreboard::VidInit( void ) { // Load sprites here return 1; } -void CHudScoreboard :: InitHUDData( void ) +void CHudScoreboard::InitHUDData( void ) { memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); m_iLastKilledBy = 0; @@ -104,20 +103,19 @@ We have a minimum width of 1-320 - we could have the field widths scale with it? #define PL_RANGE_MAX 375 int SCOREBOARD_WIDTH = 320; - // Y positions #define ROW_GAP 13 #define ROW_RANGE_MIN 15 -#define ROW_RANGE_MAX ( ScreenHeight - 50 ) +#define ROW_RANGE_MAX( ScreenHeight - 50 ) -int CHudScoreboard :: Draw( float fTime ) +int CHudScoreboard::Draw( float fTime ) { int i, j, can_show_packetloss = 0; int FAR_RIGHT; gHUD.m_iNoConsolePrint &= ~( 1 << 0 ); - if ( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) + if( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) return 1; gHUD.m_iNoConsolePrint |= 1 << 0; @@ -125,7 +123,7 @@ int CHudScoreboard :: Draw( float fTime ) GetAllPlayersInfo(); // Packetloss removed on Kelly 'shipping nazi' Bailey's orders - if ( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) + if( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) { can_show_packetloss = 1; SCOREBOARD_WIDTH = 400; @@ -138,16 +136,16 @@ int CHudScoreboard :: Draw( float fTime ) // just sort the list on the fly // list is sorted first by frags, then by deaths float list_slot = 0; - int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; + int xpos_rel = ( ScreenWidth - SCOREBOARD_WIDTH ) / 2; // print the heading line - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - int xpos = NAME_RANGE_MIN + xpos_rel; + int ypos = ROW_RANGE_MIN + ( list_slot * ROW_GAP ); + int xpos = NAME_RANGE_MIN + xpos_rel; FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; FAR_RIGHT += 5; - gHUD.DrawDarkRectangle(xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX); - if ( !gHUD.m_Teamplay ) + gHUD.DrawDarkRectangle( xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX ); + if( !gHUD.m_Teamplay ) gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); else gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); @@ -157,20 +155,19 @@ int CHudScoreboard :: Draw( float fTime ) gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); - if ( can_show_packetloss ) + if( can_show_packetloss ) { gHUD.DrawHudString( PL_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "pkt loss", 255, 140, 0 ); } - list_slot += 1.2; - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + ypos = ROW_RANGE_MIN + ( list_slot * ROW_GAP ); xpos = NAME_RANGE_MIN + xpos_rel; - FillRGBA( xpos - 4, ypos, FAR_RIGHT -2, 1, 255, 140, 0, 255); // draw the seperator line - + FillRGBA( xpos - 4, ypos, FAR_RIGHT -2, 1, 255, 140, 0, 255 ); // draw the seperator line + list_slot += 0.8; - if ( !gHUD.m_Teamplay ) + if( !gHUD.m_Teamplay ) { // it's not teamplay, so just draw a simple player list DrawPlayers( xpos_rel, list_slot ); @@ -178,32 +175,32 @@ int CHudScoreboard :: Draw( float fTime ) } // clear out team scores - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { - if ( !g_TeamInfo[i].scores_overriden ) + if( !g_TeamInfo[i].scores_overriden ) g_TeamInfo[i].frags = g_TeamInfo[i].deaths = 0; g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; } // recalc the team scores, then draw them - for ( i = 1; i < MAX_PLAYERS; i++ ) + for( i = 1; i < MAX_PLAYERS; i++ ) { - //if ( g_PlayerInfoList[i].name == NULL ) + //if( g_PlayerInfoList[i].name == NULL ) // continue; // empty player slot, skip - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + if( g_PlayerExtraInfo[i].teamname[0] == 0 ) continue; // skip over players who are not in a team // find what team this player is in - for ( j = 1; j <= m_iNumTeams; j++ ) + for( j = 1; j <= m_iNumTeams; j++ ) { - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + if( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) break; } - if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy + if( j > m_iNumTeams ) // player is not in a team, skip to the next guy continue; - if ( !g_TeamInfo[j].scores_overriden ) + if( !g_TeamInfo[j].scores_overriden ) { g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; @@ -212,18 +209,18 @@ int CHudScoreboard :: Draw( float fTime ) g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; - if ( g_PlayerInfoList[i].thisplayer ) + if( g_PlayerInfoList[i].thisplayer ) g_TeamInfo[j].ownteam = TRUE; else g_TeamInfo[j].ownteam = FALSE; } // find team ping/packetloss averages - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { g_TeamInfo[i].already_drawn = FALSE; - if ( g_TeamInfo[i].players > 0 ) + if( g_TeamInfo[i].players > 0 ) { g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping @@ -231,19 +228,19 @@ int CHudScoreboard :: Draw( float fTime ) } // Draw the teams - while ( 1 ) + while( 1 ) { int highest_frags = -99999; int lowest_deaths = 99999; int best_team = 0; - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { - if ( g_TeamInfo[i].players < 0 ) + if( g_TeamInfo[i].players < 0 ) continue; - if ( !g_TeamInfo[i].already_drawn && g_TeamInfo[i].frags >= highest_frags ) + if( !g_TeamInfo[i].already_drawn && g_TeamInfo[i].frags >= highest_frags ) { - if ( g_TeamInfo[i].frags > highest_frags || g_TeamInfo[i].deaths < lowest_deaths ) + if( g_TeamInfo[i].frags > highest_frags || g_TeamInfo[i].deaths < lowest_deaths ) { best_team = i; lowest_deaths = g_TeamInfo[i].deaths; @@ -253,22 +250,22 @@ int CHudScoreboard :: Draw( float fTime ) } // draw the best team on the scoreboard - if ( !best_team ) + if( !best_team ) break; // draw out the best team team_info_t *team_info = &g_TeamInfo[best_team]; - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + ypos = ROW_RANGE_MIN + ( list_slot * ROW_GAP ); // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + if( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border break; xpos = NAME_RANGE_MIN + xpos_rel; int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish - - if ( team_info->ownteam ) // if it is their team, draw the background different color + + if( team_info->ownteam ) // if it is their team, draw the background different color { // overlay the background in blue, then draw the score text over it FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 0, 0, 255, 70 ); @@ -293,15 +290,15 @@ int CHudScoreboard :: Draw( float fTime ) // draw ping & packetloss static char buf[64]; sprintf( buf, "%d", team_info->ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + xpos = ( ( PING_RANGE_MAX - PING_RANGE_MIN ) / 2) + PING_RANGE_MIN + xpos_rel + 25; UnpackRGB( r, g, b, RGB_YELLOWISH ); gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); - // Packetloss removed on Kelly 'shipping nazi' Bailey's orders - if ( can_show_packetloss ) + // Packetloss removed on Kelly 'shipping nazi' Bailey's orders + if( can_show_packetloss ) { - xpos = ((PL_RANGE_MAX - PL_RANGE_MIN) / 2) + PL_RANGE_MIN + xpos_rel + 25; - + xpos = ( ( PL_RANGE_MAX - PL_RANGE_MIN ) / 2) + PL_RANGE_MIN + xpos_rel + 25; + sprintf( buf, " %d", team_info->packetloss ); gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); } @@ -319,15 +316,17 @@ int CHudScoreboard :: Draw( float fTime ) return 1; } + extern float *GetClientColor( int client ); + // returns the ypos where it finishes drawing -int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team ) +int CHudScoreboard::DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team ) { int can_show_packetloss = 0; int FAR_RIGHT; // Packetloss removed on Kelly 'shipping nazi' Bailey's orders - if ( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) + if( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) { can_show_packetloss = 1; SCOREBOARD_WIDTH = 400; @@ -341,20 +340,21 @@ int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset FAR_RIGHT += 5; // draw the players, in order, and restricted to team if set - while ( 1 ) + while( 1 ) { // Find the top ranking player - int highest_frags = -99999; int lowest_deaths = 99999; + int highest_frags = -99999; + int lowest_deaths = 99999; int best_player = 0; - for ( int i = 1; i < MAX_PLAYERS; i++ ) + for( int i = 1; i < MAX_PLAYERS; i++ ) { - if ( g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) + if( g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) { - if ( !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team + if( !( team && stricmp( g_PlayerExtraInfo[i].teamname, team ) ) ) // make sure it is the specified team { extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; - if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) + if( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) { best_player = i; lowest_deaths = pl_info->deaths; @@ -364,34 +364,36 @@ int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset } } - if ( !best_player ) + if( !best_player ) break; // draw out the best player hud_player_info_t *pl_info = &g_PlayerInfoList[best_player]; - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); + int ypos = ROW_RANGE_MIN + ( list_slot * ROW_GAP ); // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border + if( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border break; int xpos = NAME_RANGE_MIN + xpos_rel; int r = 255, g = 255, b = 255; float *colors = GetClientColor( best_player ); r *= colors[0], g *= colors[1], b *= colors[2]; - if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + if( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) { - if ( pl_info->thisplayer ) - { // green is the suicide color? i wish this could do grey... + if( pl_info->thisplayer ) + { + // green is the suicide color? i wish this could do grey... FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 80, 155, 0, 70 ); } else - { // Highlight the killers name - overlay the background in red, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + { + // Highlight the killers name - overlay the background in red, then draw the score text over it + FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 255, 0, 0, ( (float)15 * (float)( m_fLastKillTime - gHUD.m_flTime ) ) ); } } - else if ( pl_info->thisplayer ) // if it is their name, draw it a different color + else if( pl_info->thisplayer ) // if it is their name, draw it a different color { // overlay the background in blue, then draw the score text over it FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, FAR_RIGHT, ROW_GAP, 0, 0, 255, 70 ); @@ -415,13 +417,13 @@ int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset // draw ping & packetloss static char buf[64]; sprintf( buf, "%d", g_PlayerInfoList[best_player].ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; + xpos = ( ( PING_RANGE_MAX - PING_RANGE_MIN ) / 2 ) + PING_RANGE_MIN + xpos_rel + 25; gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); // Packetloss removed on Kelly 'shipping nazi' Bailey's orders - if ( can_show_packetloss ) + if( can_show_packetloss ) { - if ( g_PlayerInfoList[best_player].packetloss >= 63 ) + if( g_PlayerInfoList[best_player].packetloss >= 63 ) { UnpackRGB( r, g, b, RGB_REDISH ); sprintf( buf, " !!!!" ); @@ -431,11 +433,11 @@ int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset sprintf( buf, " %d", g_PlayerInfoList[best_player].packetloss ); } - xpos = ((PL_RANGE_MAX - PL_RANGE_MIN) / 2) + PL_RANGE_MIN + xpos_rel + 25; - + xpos = ( ( PL_RANGE_MAX - PL_RANGE_MIN ) / 2 ) + PL_RANGE_MIN + xpos_rel + 25; + gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); } - + pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again list_slot++; } @@ -443,19 +445,18 @@ int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset return list_slot; } - -void CHudScoreboard :: GetAllPlayersInfo( void ) +void CHudScoreboard::GetAllPlayersInfo( void ) { - for ( int i = 1; i < MAX_PLAYERS; i++ ) + for( int i = 1; i < MAX_PLAYERS; i++ ) { GetPlayerInfo( i, &g_PlayerInfoList[i] ); - if ( g_PlayerInfoList[i].thisplayer ) + if( g_PlayerInfoList[i].thisplayer ) m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine } } -int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) +int CHudScoreboard::MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) { m_iFlags |= HUD_ACTIVE; @@ -466,7 +467,7 @@ int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *p short playerclass = READ_SHORT(); short teamnumber = READ_SHORT(); - if ( cl > 0 && cl <= MAX_PLAYERS ) + if( cl > 0 && cl <= MAX_PLAYERS ) { g_PlayerExtraInfo[cl].frags = frags; g_PlayerExtraInfo[cl].deaths = deaths; @@ -483,21 +484,21 @@ int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *p // accepts two values: // byte: client number // string: client team name -int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) +int CHudScoreboard::MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) { int i, j; BEGIN_READ( pbuf, iSize ); short cl = READ_BYTE(); - - if ( cl > 0 && cl <= MAX_PLAYERS ) - { // set the players team + + if( cl > 0 && cl <= MAX_PLAYERS ) + { + // set the players team strncpy( g_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); } // rebuild the list of teams - // clear out player counts from teams - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { g_TeamInfo[i].players = 0; } @@ -505,30 +506,31 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb // rebuild the team list GetAllPlayersInfo(); m_iNumTeams = 0; - for ( i = 1; i < MAX_PLAYERS; i++ ) + for( i = 1; i < MAX_PLAYERS; i++ ) { //if ( g_PlayerInfoList[i].name == NULL ) // continue; - if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + if( g_PlayerExtraInfo[i].teamname[0] == 0 ) continue; // skip over players who are not in a team // is this player in an existing team? - for ( j = 1; j <= m_iNumTeams; j++ ) + for( j = 1; j <= m_iNumTeams; j++ ) { - if ( g_TeamInfo[j].name[0] == '\0' ) + if( g_TeamInfo[j].name[0] == '\0' ) break; - if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + if( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) break; } - if ( j > m_iNumTeams ) - { // they aren't in a listed team, so make a new one + if( j > m_iNumTeams ) + { + // they aren't in a listed team, so make a new one // search through for an empty team slot - for ( j = 1; j <= m_iNumTeams; j++ ) + for( j = 1; j <= m_iNumTeams; j++ ) { - if ( g_TeamInfo[j].name[0] == '\0' ) + if( g_TeamInfo[j].name[0] == '\0' ) break; } m_iNumTeams = max( j, m_iNumTeams ); @@ -541,9 +543,9 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb } // clear out any empty teams - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { - if ( g_TeamInfo[i].players < 1 ) + if( g_TeamInfo[i].players < 1 ) memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); } @@ -556,50 +558,48 @@ int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pb // short: teams kills // short: teams deaths // if this message is never received, then scores will simply be the combined totals of the players. -int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) +int CHudScoreboard::MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); char *TeamName = READ_STRING(); int i; // find the team matching the name - for ( i = 1; i <= m_iNumTeams; i++ ) + for( i = 1; i <= m_iNumTeams; i++ ) { - if ( !stricmp( TeamName, g_TeamInfo[i].name ) ) + if( !stricmp( TeamName, g_TeamInfo[i].name ) ) break; } - if ( i > m_iNumTeams ) + if( i > m_iNumTeams ) return 1; // use this new score data instead of combined player scores g_TeamInfo[i].scores_overriden = TRUE; g_TeamInfo[i].frags = READ_SHORT(); g_TeamInfo[i].deaths = READ_SHORT(); - + return 1; } -void CHudScoreboard :: DeathMsg( int killer, int victim ) +void CHudScoreboard::DeathMsg( int killer, int victim ) { // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide - if ( victim == m_iPlayerNum || killer == 0 ) + if( victim == m_iPlayerNum || killer == 0 ) { m_iLastKilledBy = killer ? killer : m_iPlayerNum; m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds - if ( killer == m_iPlayerNum ) + if( killer == m_iPlayerNum ) m_iLastKilledBy = m_iPlayerNum; } } - - -void CHudScoreboard :: UserCmd_ShowScores( void ) +void CHudScoreboard::UserCmd_ShowScores( void ) { m_iShowscoresHeld = TRUE; } -void CHudScoreboard :: UserCmd_HideScores( void ) +void CHudScoreboard::UserCmd_HideScores( void ) { m_iShowscoresHeld = FALSE; } diff --git a/cl_dll/soundsystem.cpp b/cl_dll/soundsystem.cpp index d368109b..9ee33861 100644 --- a/cl_dll/soundsystem.cpp +++ b/cl_dll/soundsystem.cpp @@ -15,6 +15,7 @@ // // $NoKeywords: $ //============================================================================= + #include #include #include @@ -28,9 +29,9 @@ extern engine_studio_api_t IEngineStudio; #define ENGINE_LAUNCHER_API_VERSION 1 -LPDIRECTSOUND lpDS = NULL; -LPDIRECTSOUNDBUFFER lpDSBuf = NULL; -LPHWAVEOUT lpHW = NULL; +LPDIRECTSOUND lpDS = NULL; +LPDIRECTSOUNDBUFFER lpDSBuf = NULL; +LPHWAVEOUT lpHW = NULL; static HMODULE hEngine = 0; @@ -116,10 +117,10 @@ int Eng_LoadFunctions( HMODULE hMod ) engine_api_func pfnEngineAPI; pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); - if ( !pfnEngineAPI ) + if( !pfnEngineAPI ) return 0; - if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + if( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) return 0; // All is okay @@ -132,11 +133,11 @@ int Eng_LoadFunctions( HMODULE hMod ) void LoadSoundAPIs( void ) { hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); - if ( hEngine ) + if( hEngine ) { - if ( Eng_LoadFunctions( hEngine ) ) + if( Eng_LoadFunctions( hEngine ) ) { - if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) + if( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) { engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); @@ -155,7 +156,7 @@ void ShutdownSoundAPIs( void ) FreeLibrary( hEngine ); hEngine = 0; } - + lpDS = 0; lpDSBuf = 0; lpHW = 0; diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index 375c9d57..c960d5ef 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -15,6 +15,7 @@ // // status_icons.cpp // + #include "hud.h" #include "cl_util.h" #include "const.h" @@ -40,7 +41,6 @@ int CHudStatusIcons::Init( void ) int CHudStatusIcons::VidInit( void ) { - return 1; } @@ -53,24 +53,24 @@ void CHudStatusIcons::Reset( void ) // Draw status icons along the left-hand side of the screen int CHudStatusIcons::Draw( float flTime ) { - if (gEngfuncs.IsSpectateOnly()) + if( gEngfuncs.IsSpectateOnly() ) return 1; // find starting position to draw from, along right-hand side of screen int x = 5; int y = ScreenHeight / 2; // loop through icon list, and draw any valid icons drawing up from the middle of screen - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + for( int i = 0; i < MAX_ICONSPRITES; i++ ) { - if ( m_IconList[i].spr ) + if( m_IconList[i].spr ) { y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5; - + SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b ); SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); } } - + return 1; } @@ -87,7 +87,7 @@ int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *p int ShouldEnable = READ_BYTE(); char *pszIconName = READ_STRING(); - if ( ShouldEnable ) + if( ShouldEnable ) { int r = READ_BYTE(); int g = READ_BYTE(); @@ -109,24 +109,24 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned int i; // check to see if the sprite is in the current list - for ( i = 0; i < MAX_ICONSPRITES; i++ ) + for( i = 0; i < MAX_ICONSPRITES; i++ ) { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + if( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) break; } - if ( i == MAX_ICONSPRITES ) + if( i == MAX_ICONSPRITES ) { // icon not in list, so find an empty slot to add to - for ( i = 0; i < MAX_ICONSPRITES; i++ ) + for( i = 0; i < MAX_ICONSPRITES; i++ ) { - if ( !m_IconList[i].spr ) + if( !m_IconList[i].spr ) break; } } // if we've run out of space in the list, overwrite the first icon - if ( i == MAX_ICONSPRITES ) + if( i == MAX_ICONSPRITES ) { i = 0; } @@ -142,7 +142,7 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned strcpy( m_IconList[i].szSpriteName, pszIconName ); // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) - if ( strstr(m_IconList[i].szSpriteName, "grenade") ) + if( strstr(m_IconList[i].szSpriteName, "grenade") ) { cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); @@ -152,12 +152,12 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned void CHudStatusIcons::DisableIcon( char *pszIconName ) { // find the sprite is in the current list - for ( int i = 0; i < MAX_ICONSPRITES; i++ ) + for( int i = 0; i < MAX_ICONSPRITES; i++ ) { - if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + if( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) { // clear the item from the list - memset( &m_IconList[i], 0, sizeof( icon_sprite_t ) ); + memset( &m_IconList[i], 0, sizeof(icon_sprite_t) ); return; } } diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index 152fb9b1..e730f05e 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -34,7 +34,7 @@ DECLARE_MESSAGE( m_StatusBar, StatusValue ) float *GetClientColor( int clientIndex ); extern float g_ColorYellow[3]; -int CHudStatusBar :: Init( void ) +int CHudStatusBar::Init( void ) { gHUD.AddHudElem( this ); @@ -48,19 +48,18 @@ int CHudStatusBar :: Init( void ) return 1; } -int CHudStatusBar :: VidInit( void ) +int CHudStatusBar::VidInit( void ) { // Load sprites here - return 1; } -void CHudStatusBar :: Reset( void ) +void CHudStatusBar::Reset( void ) { int i = 0; m_iFlags &= ~HUD_ACTIVE; // start out inactive - for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + for( i = 0; i < MAX_STATUSBAR_LINES; i++ ) m_szStatusText[i][0] = 0; memset( m_iStatusValues, 0, sizeof m_iStatusValues ); @@ -71,7 +70,7 @@ void CHudStatusBar :: Reset( void ) m_pflNameColors[i] = g_ColorYellow; } -void CHudStatusBar :: ParseStatusString( int line_num ) +void CHudStatusBar::ParseStatusString( int line_num ) { // localise string first char szBuffer[MAX_STATUSTEXT_LENGTH]; @@ -85,29 +84,31 @@ void CHudStatusBar :: ParseStatusString( int line_num ) char *src_start = src, *dst_start = dst; - while ( *src != 0 ) + while( *src != 0 ) { - while ( *src == '\n' ) + while( *src == '\n' ) src++; // skip over any newlines - if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) ) + if( ( ( src - src_start ) >= MAX_STATUSTEXT_LENGTH ) || ( ( dst - dst_start ) >= MAX_STATUSTEXT_LENGTH ) ) break; int index = atoi( src ); // should we draw this line? - if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) ) - { // parse this line and append result to the status bar + if( ( index >= 0 && index < MAX_STATUSBAR_VALUES ) && ( m_iStatusValues[index] != 0 ) ) + { + // parse this line and append result to the status bar while ( *src >= '0' && *src <= '9' ) src++; - if ( *src == '\n' || *src == 0 ) + if( *src == '\n' || *src == 0 ) continue; // no more left in this text line // copy the text, char by char, until we hit a % or a \n - while ( *src != '\n' && *src != 0 ) + while( *src != '\n' && *src != 0 ) { - if ( *src != '%' ) - { // just copy the character + if( *src != '%' ) + { + // just copy the character *dst = *src; dst++, src++; } @@ -126,20 +127,20 @@ void CHudStatusBar :: ParseStatusString( int line_num ) // move over descriptor, then get and move over the index index = atoi( ++src ); - while ( *src >= '0' && *src <= '9' ) + while( *src >= '0' && *src <= '9' ) src++; - if ( index >= 0 && index < MAX_STATUSBAR_VALUES ) + if( index >= 0 && index < MAX_STATUSBAR_VALUES ) { int indexval = m_iStatusValues[index]; // get the string to substitute in place of the %XX char szRepString[MAX_PLAYER_NAME_LENGTH]; - switch ( valtype ) + switch( valtype ) { case 'p': // player name GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); - if ( g_PlayerInfoList[indexval].name != NULL ) + if( g_PlayerInfoList[indexval].name != NULL ) { strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); m_pflNameColors[line_num] = GetClientColor( indexval ); @@ -148,7 +149,6 @@ void CHudStatusBar :: ParseStatusString( int line_num ) { strcpy( szRepString, "******" ); } - break; case 'i': // number sprintf( szRepString, "%d", indexval ); @@ -157,7 +157,7 @@ void CHudStatusBar :: ParseStatusString( int line_num ) szRepString[0] = 0; } - for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ ) + for( char *cp = szRepString; *cp != 0 && ( ( dst - dst_start ) < MAX_STATUSTEXT_LENGTH ); cp++, dst++ ) *dst = *cp; } } @@ -166,17 +166,17 @@ void CHudStatusBar :: ParseStatusString( int line_num ) else { // skip to next line of text - while ( *src != 0 && *src != '\n' ) + while( *src != 0 && *src != '\n' ) src++; } } } -int CHudStatusBar :: Draw( float fTime ) +int CHudStatusBar::Draw( float fTime ) { - if ( m_bReparseString ) + if( m_bReparseString ) { - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + for( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) { m_pflNameColors[i] = g_ColorYellow; ParseStatusString( i ); @@ -184,10 +184,10 @@ int CHudStatusBar :: Draw( float fTime ) m_bReparseString = FALSE; } - int Y_START = ScreenHeight - YRES(32 + 4); + int Y_START = ScreenHeight - YRES( 32 + 4 ); // Draw the status bar lines - for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + for( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) { int TextHeight, TextWidth; GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); @@ -196,13 +196,13 @@ int CHudStatusBar :: Draw( float fTime ) int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen // let user set status ID bar centering - if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) + if( ( i == STATUSBAR_ID_LINE ) && CVAR_GET_FLOAT( "hud_centerid" ) ) { - x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 ); - y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); + x = max( 0, max( 2, ( ScreenWidth - TextWidth ) ) / 2 ); + y = ( ScreenHeight / 2 ) + ( TextHeight * CVAR_GET_FLOAT( "hud_centerid" ) ); } - if ( m_pflNameColors[i] ) + if( m_pflNameColors[i] ) DrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); DrawConsoleString( x, y, m_szStatusBar[i] ); @@ -223,19 +223,19 @@ int CHudStatusBar :: Draw( float fTime ) // if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline // %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] // %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] -int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) +int CHudStatusBar::MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int line = READ_BYTE(); - if ( line < 0 || line >= MAX_STATUSBAR_LINES ) + if( line < 0 || line >= MAX_STATUSBAR_LINES ) return 1; strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH ); - m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) + m_szStatusText[line][MAX_STATUSTEXT_LENGTH - 1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) - if ( m_szStatusText[0] == 0 ) + if( m_szStatusText[0] == 0 ) m_iFlags &= ~HUD_ACTIVE; else m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar @@ -249,17 +249,17 @@ int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *p // accepts two values: // byte: index into the status value array // short: value to store -int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) +int CHudStatusBar::MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int index = READ_BYTE(); - if ( index < 1 || index >= MAX_STATUSBAR_VALUES ) + if( index < 1 || index >= MAX_STATUSBAR_VALUES ) return 1; // index out of range m_iStatusValues[index] = READ_SHORT(); m_bReparseString = TRUE; - + return 1; } diff --git a/cl_dll/studio_util.cpp b/cl_dll/studio_util.cpp index df5fc4bf..a5eb39f1 100644 --- a/cl_dll/studio_util.cpp +++ b/cl_dll/studio_util.cpp @@ -18,31 +18,31 @@ AngleMatrix ==================== */ -void AngleMatrix (const float *angles, float (*matrix)[4] ) +void AngleMatrix( const float *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); + 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[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][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; @@ -54,14 +54,14 @@ VectorCompare ==================== */ -int VectorCompare (const float *v1, const float *v2) +int VectorCompare( const float *v1, const float *v2 ) { - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) + int i; + + for( i = 0; i < 3; i++ ) + if( v1[i] != v2[i] ) return 0; - + return 1; } @@ -71,7 +71,7 @@ CrossProduct ==================== */ -void CrossProduct (const float *v1, const float *v2, float *cross) +void CrossProduct( const float *v1, const float *v2, float *cross ) { cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; @@ -84,7 +84,7 @@ VectorTransform ==================== */ -void VectorTransform (const float *in1, float in2[3][4], float *out) +void VectorTransform( const float *in1, float in2[3][4], float *out ) { out[0] = DotProduct(in1, in2[0]) + in2[0][3]; out[1] = DotProduct(in1, in2[1]) + in2[1][3]; @@ -97,7 +97,7 @@ ConcatTransforms ================ */ -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +void ConcatTransforms( float in1[3][4], float in2[3][4], float out[3][4] ) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; @@ -135,24 +135,24 @@ AngleQuaternion */ void AngleQuaternion( float *angles, vec4_t quaternion ) { - float angle; - float sr, sp, sy, cr, cp, cy; + float angle; + float sr, sp, sy, cr, cp, cy; // FIXME: rescale the inputs to 1/2 angle angle = angles[2] * 0.5; - sy = sin(angle); - cy = cos(angle); + sy = sin( angle ); + cy = cos( angle ); angle = angles[1] * 0.5; - sp = sin(angle); - cp = cos(angle); + sp = sin( angle ); + cp = cos( angle ); angle = angles[0] * 0.5; - sr = sin(angle); - cr = cos(angle); + sr = sin( angle ); + cr = cos( angle ); - quaternion[0] = sr*cp*cy-cr*sp*sy; // X - quaternion[1] = cr*sp*cy+sr*cp*sy; // Y - quaternion[2] = cr*cp*sy-sr*sp*cy; // Z - quaternion[3] = cr*cp*cy+sr*sp*sy; // W + quaternion[0] = sr * cp * cy - cr * sp * sy; // X + quaternion[1] = cr * sp * cy + sr * cp * sy; // Y + quaternion[2] = cr * cp * sy - sr * sp * cy; // Z + quaternion[3] = cr * cp * cy + sr * sp * sy; // W } /* @@ -164,42 +164,43 @@ QuaternionSlerp void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) { int i; - float omega, cosom, sinom, sclp, sclq; + float omega, cosom, sinom, sclp, sclq; // decide if one of the quaternions is backwards float a = 0; float b = 0; - for (i = 0; i < 4; i++) + for( i = 0; i < 4; i++ ) { - a += (p[i]-q[i])*(p[i]-q[i]); - b += (p[i]+q[i])*(p[i]+q[i]); + a += ( p[i] - q[i] ) * ( p[i] - q[i] ); + b += ( p[i] + q[i] ) * ( p[i] + q[i] ); } - if (a > b) + if(a > b) { - for (i = 0; i < 4; i++) + for( i = 0; i < 4; i++ ) { q[i] = -q[i]; } } - cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + cosom = p[0] * q[0] + p[1] * q[1] + p[2] * q[2] + p[3] * q[3]; - if ((1.0 + cosom) > 0.000001) + if( ( 1.0 + cosom ) > 0.000001 ) { - if ((1.0 - cosom) > 0.000001) + if( ( 1.0 - cosom ) > 0.000001 ) { omega = acos( cosom ); sinom = sin( omega ); - sclp = sin( (1.0 - t)*omega) / sinom; - sclq = sin( t*omega ) / sinom; + sclp = sin( ( 1.0 - t ) * omega ) / sinom; + sclq = sin( t * omega ) / sinom; } else { sclp = 1.0 - t; sclq = t; } - for (i = 0; i < 4; i++) { + for( i = 0; i < 4; i++ ) + { qt[i] = sclp * p[i] + sclq * q[i]; } } @@ -209,9 +210,9 @@ void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) qt[1] = q[0]; qt[2] = -q[3]; qt[3] = q[2]; - sclp = sin( (1.0 - t) * (0.5 * M_PI)); - sclq = sin( t * (0.5 * M_PI)); - for (i = 0; i < 3; i++) + sclp = sin( ( 1.0 - t ) * ( 0.5 * M_PI ) ); + sclq = sin( t * ( 0.5 * M_PI ) ); + for( i = 0; i < 3; i++ ) { qt[i] = sclp * p[i] + sclq * qt[i]; } @@ -248,4 +249,4 @@ MatrixCopy void MatrixCopy( float in[3][4], float out[3][4] ) { memcpy( out, in, sizeof( float ) * 3 * 4 ); -} \ No newline at end of file +} diff --git a/cl_dll/studio_util.h b/cl_dll/studio_util.h index aa8dcf6b..963dcda7 100644 --- a/cl_dll/studio_util.h +++ b/cl_dll/studio_util.h @@ -25,16 +25,15 @@ #define ROLL 2 #endif -#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) +#define FDotProduct( a, b ) ( fabs( ( a[0] ) * ( b[0] ) ) + fabs( ( a[1] ) * ( b[1] ) ) + fabs( ( a[2] ) * ( b[2] ) ) ) -void AngleMatrix (const float *angles, float (*matrix)[4] ); -int VectorCompare (const float *v1, const float *v2); -void CrossProduct (const float *v1, const float *v2, float *cross); -void VectorTransform (const float *in1, float in2[3][4], float *out); -void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void AngleMatrix( const float *angles, float (*matrix)[4] ); +int VectorCompare( const float *v1, const float *v2 ); +void CrossProduct( const float *v1, const float *v2, float *cross ); +void VectorTransform( const float *in1, float in2[3][4], float *out ); +void ConcatTransforms( float in1[3][4], float in2[3][4], float out[3][4] ); void MatrixCopy( float in[3][4], float out[3][4] ); void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); void AngleQuaternion( float *angles, vec4_t quaternion ); - -#endif // STUDIO_UTIL_H \ No newline at end of file +#endif // STUDIO_UTIL_H diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index eb6f73a9..af62a915 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -26,10 +26,9 @@ #include #include "parsemsg.h" - DECLARE_MESSAGE( m_TextMessage, TextMsg ) -int CHudTextMessage::Init(void) +int CHudTextMessage::Init( void ) { HOOK_MESSAGE( TextMsg ); @@ -46,14 +45,14 @@ int CHudTextMessage::Init(void) char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) { char *dst = dst_buffer; - for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + for( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) { - if ( *src == '#' ) + if( *src == '#' ) { // cut msg name out of string static char word_buf[255]; char *wdst = word_buf, *word_start = src; - for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) + for( ++src; ( *src >= 'A' && *src <= 'z' ) || ( *src >= '0' && *src <= '9' ); wdst++, src++ ) { *wdst = *src; } @@ -61,7 +60,7 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in // lookup msg name in titles.txt client_textmessage_t *clmsg = TextMessageGet( word_buf ); - if ( !clmsg || !(clmsg->pMessage) ) + if( !clmsg || !( clmsg->pMessage ) ) { src = word_start; *dst = *src; @@ -70,7 +69,7 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in } // copy string into message over the msg name - for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) + for( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) { *dst = *wsrc; } @@ -84,7 +83,7 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in } } - dst_buffer[buffer_size-1] = 0; // ensure null termination + dst_buffer[buffer_size - 1] = 0; // ensure null termination return dst_buffer; } @@ -99,30 +98,31 @@ char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) // Simplified version of LocaliseTextString; assumes string is only one word char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) { - if ( !msg ) + if( !msg ) return ""; // '#' character indicates this is a reference to a string in titles.txt, and not the string itself - if ( msg[0] == '#' ) + if( msg[0] == '#' ) { // this is a message name, so look up the real message - client_textmessage_t *clmsg = TextMessageGet( msg+1 ); + client_textmessage_t *clmsg = TextMessageGet( msg + 1 ); - if ( !clmsg || !(clmsg->pMessage) ) + if( !clmsg || !(clmsg->pMessage) ) return (char*)msg; // lookup failed, so return the original string - - if ( msg_dest ) + + if( msg_dest ) { // check to see if titles.txt info overrides msg destination // if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination - if ( clmsg->effect < 0 ) // + if( clmsg->effect < 0 ) // *msg_dest = -clmsg->effect; } return (char*)clmsg->pMessage; } else - { // nothing special about this message, so just return the same string + { + // nothing special about this message, so just return the same string return (char*)msg; } } @@ -130,7 +130,7 @@ char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) void StripEndNewlineFromString( char *str ) { int s = strlen( str ) - 1; - if ( str[s] == '\n' || str[s] == '\r' ) + if( str[s] == '\n' || str[s] == '\r' ) str[s] = 0; } @@ -138,8 +138,8 @@ void StripEndNewlineFromString( char *str ) // returns a pointer to str char* ConvertCRtoNL( char *str ) { - for ( char *ch = str; *ch != 0; ch++ ) - if ( *ch == '\r' ) + for( char *ch = str; *ch != 0; ch++ ) + if( *ch == '\r' ) *ch = '\n'; return str; } @@ -181,24 +181,21 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf StripEndNewlineFromString( sstr4 ); char *psz = szBuf[5]; - switch ( msg_dest ) + switch( msg_dest ) { case HUD_PRINTCENTER: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); CenterPrint( ConvertCRtoNL( psz ) ); break; - case HUD_PRINTNOTIFY: psz[0] = 1; // mark this message to go into the notify buffer - sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 ); + sprintf( psz + 1, msg_text, sstr1, sstr2, sstr3, sstr4 ); ConsolePrint( ConvertCRtoNL( psz ) ); break; - case HUD_PRINTTALK: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); break; - case HUD_PRINTCONSOLE: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); ConsolePrint( ConvertCRtoNL( psz ) ); diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h index 06d9af09..a9270f1e 100644 --- a/cl_dll/tf_defs.h +++ b/cl_dll/tf_defs.h @@ -362,7 +362,6 @@ enum // Silent Spy Feign #define TF_SPY_SILENTDIE 199 - /*==================================================*/ /* Defines for the ENGINEER's Building ability */ /*==================================================*/ @@ -458,28 +457,28 @@ enum // HL-compatible weapon numbers #define WEAPON_HOOK 1 -#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) -#define WEAPON_MEDIKIT (WEAPON_HOOK+2) -#define WEAPON_SPANNER (WEAPON_HOOK+3) -#define WEAPON_AXE (WEAPON_HOOK+4) -#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) -#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) -#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) -#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) -#define WEAPON_NAILGUN (WEAPON_HOOK+9) -#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) -#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) -#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) -#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) -#define WEAPON_INCENDIARY (WEAPON_HOOK+14) -#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) -#define WEAPON_LIGHTNING (WEAPON_HOOK+17) -#define WEAPON_DETPACK (WEAPON_HOOK+18) -#define WEAPON_TRANQ (WEAPON_HOOK+19) -#define WEAPON_LASER (WEAPON_HOOK+20) -#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) -#define WEAPON_KNIFE (WEAPON_HOOK+22) -#define WEAPON_BENCHMARK (WEAPON_HOOK+23) +#define WEAPON_BIOWEAPON (WEAPON_HOOK + 1) +#define WEAPON_MEDIKIT (WEAPON_HOOK + 2) +#define WEAPON_SPANNER (WEAPON_HOOK + 3) +#define WEAPON_AXE (WEAPON_HOOK + 4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK + 5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK + 6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK + 7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK + 8) +#define WEAPON_NAILGUN (WEAPON_HOOK + 9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK + 10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK + 11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK + 12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK + 13) +#define WEAPON_INCENDIARY (WEAPON_HOOK + 14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK + 16) +#define WEAPON_LIGHTNING (WEAPON_HOOK + 17) +#define WEAPON_DETPACK (WEAPON_HOOK + 18) +#define WEAPON_TRANQ (WEAPON_HOOK + 19) +#define WEAPON_LASER (WEAPON_HOOK + 20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK + 21) +#define WEAPON_KNIFE (WEAPON_HOOK + 22) +#define WEAPON_BENCHMARK (WEAPON_HOOK + 23) /*==================================================*/ /* New Weapon Related Defines */ @@ -509,7 +508,7 @@ enum // Detpack #define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack #define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack -#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_SIZE 700 // Explosion Size #define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering #define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into @@ -519,15 +518,15 @@ enum // Grenades #define GR_PRIMETIME 3 #define GR_CALTROP_PRIME 0.5 -#define GR_TYPE_NONE 0 -#define GR_TYPE_NORMAL 1 -#define GR_TYPE_CONCUSSION 2 -#define GR_TYPE_NAIL 3 -#define GR_TYPE_MIRV 4 -#define GR_TYPE_NAPALM 5 -//#define GR_TYPE_FLARE 6 -#define GR_TYPE_GAS 7 -#define GR_TYPE_EMP 8 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 #define GR_TYPE_CALTROP 9 //#define GR_TYPE_FLASH 10 @@ -542,8 +541,8 @@ enum // Defines for Concussion Grenade #define GR_CONCUSS_TIME 0.25 #define GR_CONCUSS_DEC 10 -#define MEDIUM_PING 150 -#define HIGH_PING 200 +#define MEDIUM_PING 150 +#define HIGH_PING 200 // Defines for the Gas Grenade #define GR_HALLU_TIME 0.3 @@ -551,7 +550,7 @@ enum #define GR_HALLU_DEC 2.5 // Defines for the BioInfection -#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players /*==================================================*/ /* New Items */ @@ -1382,8 +1381,5 @@ public: void Spawn( void ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; - #endif // TF_DEFS_ONLY #endif // __TF_DEFS_H - - diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp index 1cbbb444..de480ec2 100644 --- a/cl_dll/train.cpp +++ b/cl_dll/train.cpp @@ -24,59 +24,56 @@ #include #include "parsemsg.h" -DECLARE_MESSAGE(m_Train, Train ) +DECLARE_MESSAGE( m_Train, Train ) - -int CHudTrain::Init(void) +int CHudTrain::Init( void ) { HOOK_MESSAGE( Train ); m_iPos = 0; m_iFlags = 0; - gHUD.AddHudElem(this); + gHUD.AddHudElem( this ); return 1; } -int CHudTrain::VidInit(void) +int CHudTrain::VidInit( void ) { m_hSprite = 0; return 1; } -int CHudTrain::Draw(float fTime) +int CHudTrain::Draw( float fTime ) { - if ( !m_hSprite ) - m_hSprite = LoadSprite("sprites/%d_train.spr"); + if( !m_hSprite ) + m_hSprite = LoadSprite( "sprites/%d_train.spr" ); - if (m_iPos) + if( m_iPos ) { int r, g, b, x, y; - UnpackRGB(r,g,b, RGB_YELLOWISH); - SPR_Set(m_hSprite, r, g, b ); + UnpackRGB( r, g, b, RGB_YELLOWISH ); + SPR_Set( m_hSprite, r, g, b ); // This should show up to the right and part way up the armor number - y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; - x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4; - - SPR_DrawAdditive( m_iPos - 1, x, y, NULL); + y = ScreenHeight - SPR_Height( m_hSprite, 0 ) - gHUD.m_iFontHeight; + x = ScreenWidth / 3 + SPR_Width( m_hSprite, 0 ) / 4; + SPR_DrawAdditive( m_iPos - 1, x, y, NULL ); } return 1; } - -int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) +int CHudTrain::MsgFunc_Train( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); // update Train data m_iPos = READ_BYTE(); - if (m_iPos) + if( m_iPos ) m_iFlags |= HUD_ACTIVE; else m_iFlags &= ~HUD_ACTIVE; diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp index 77d1d466..517ef982 100644 --- a/cl_dll/tri.cpp +++ b/cl_dll/tri.cpp @@ -40,7 +40,7 @@ void Draw_Triangles( void ) // Load it up with some bogus data player = gEngfuncs.GetLocalPlayer(); - if ( !player ) + if( !player ) return; org = player->origin; @@ -48,18 +48,18 @@ void Draw_Triangles( void ) org.x += 50; org.y += 50; - if (gHUD.m_hsprCursor == 0) + if( gHUD.m_hsprCursor == 0 ) { char sz[256]; sprintf( sz, "sprites/cursor.spr" ); gHUD.m_hsprCursor = SPR_Load( sz ); } - if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) + if( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 ) ) { return; } - + // Create a triangle, sigh gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); gEngfuncs.pTriAPI->CullFace( TRI_NONE ); @@ -86,7 +86,6 @@ void Draw_Triangles( void ) gEngfuncs.pTriAPI->End(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); } - #endif /* @@ -98,9 +97,7 @@ Non-transparent triangles-- add them here */ void DLLEXPORT HUD_DrawNormalTriangles( void ) { - gHUD.m_Spectator.DrawOverview(); - #if defined( TEST_IT ) // Draw_Triangles(); #endif @@ -115,7 +112,6 @@ Render any triangles with transparent rendermode needs here */ void DLLEXPORT HUD_DrawTransparentTriangles( void ) { - #if defined( TEST_IT ) // Draw_Triangles(); #endif diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp index 14474a9f..52dc2f61 100644 --- a/cl_dll/util.cpp +++ b/cl_dll/util.cpp @@ -32,102 +32,100 @@ extern vec3_t vec3_origin; -double sqrt(double x); +double sqrt( double x ); -float Length(const float *v) +float Length( const float *v ) { - int i; + int i; float length; - + length = 0; - for (i=0 ; i< 3 ; i++) - length += v[i]*v[i]; - length = sqrt (length); // FIXME + for( i = 0; i < 3; i++ ) + length += v[i] * v[i]; + length = sqrt( length ); // FIXME return length; } void VectorAngles( const float *forward, float *angles ) { - float tmp, yaw, pitch; - - if (forward[1] == 0 && forward[0] == 0) + float tmp, yaw, pitch; + + if( forward[1] == 0 && forward[0] == 0 ) { yaw = 0; - if (forward[2] > 0) + if( forward[2] > 0 ) pitch = 90; else pitch = 270; } else { - yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); - if (yaw < 0) + 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) + 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; } -float VectorNormalize (float *v) +float VectorNormalize( float *v ) { - float length, ilength; + float length, ilength; - length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); // FIXME + length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + length = sqrt( length ); // FIXME - if (length) + if( length ) { - ilength = 1/length; + ilength = 1 / length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } - - return length; + return length; } -void VectorInverse ( float *v ) +void VectorInverse( float *v ) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } -void VectorScale (const float *in, float scale, float *out) +void VectorScale( const float *in, float scale, float *out ) { - out[0] = in[0]*scale; - out[1] = in[1]*scale; - out[2] = in[2]*scale; + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; } -void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +void VectorMA( const float *veca, float scale, const float *vecb, float *vecc ) { - vecc[0] = veca[0] + scale*vecb[0]; - vecc[1] = veca[1] + scale*vecb[1]; - vecc[2] = veca[2] + scale*vecb[2]; + vecc[0] = veca[0] + scale * vecb[0]; + vecc[1] = veca[1] + scale * vecb[1]; + vecc[2] = veca[2] + scale * vecb[2]; } -HSPRITE LoadSprite(const char *pszName) +HSPRITE LoadSprite( const char *pszName ) { int i; - char sz[256]; + char sz[256]; - if (ScreenWidth < 640) + if( ScreenWidth < 640 ) i = 320; else i = 640; - sprintf(sz, pszName, i); + sprintf( sz, pszName, i ); - return SPR_Load(sz); + return SPR_Load( sz ); } - diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h index fdac17cc..ff5f9a91 100644 --- a/cl_dll/util_vector.h +++ b/cl_dll/util_vector.h @@ -22,8 +22,8 @@ #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 unsigned int func_t; // +typedef unsigned int string_t; // from engine's pr_comp.h; typedef float vec_t; // needed before including progdefs.h //========================================================= @@ -33,21 +33,21 @@ typedef float vec_t; // needed before including progdefs.h class Vector2D { public: - inline Vector2D(void) { } - inline Vector2D(float X, float Y) { 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 (float)sqrt(x*x + y*y ); } + inline Vector2D( void ) { } + inline Vector2D( float X, float Y ) { 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 Vector2D Normalize ( void ) const + inline float Length( void ) const { return (float)sqrt(x*x + y*y ); } + + inline Vector2D Normalize( void ) const { Vector2D vec2; float flLen = Length(); - if ( flLen == 0 ) + if( flLen == 0 ) { return Vector2D( (float)0, (float)0 ); } @@ -61,61 +61,66 @@ public: 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; } +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] +{ //which is a vec_t[3] public: // Construction/destruction - inline Vector(void) { } - inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + inline Vector( void ) { } + inline Vector( float X, float Y, float Z ) { 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 = v.x; y = v.y; z = v.z; } + inline Vector( float rgfl[3] ) { 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); } + 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 (float)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 + inline void CopyToArray( float* rgfl ) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } + inline float Length( void ) const { return (float)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); // ???? + if( flLen == 0 ) return Vector( 0, 0, 1); // ???? flLen = 1 / flLen; - return Vector(x * flLen, y * flLen, z * flLen); + return Vector( x * flLen, y * flLen, z * flLen ); } - inline Vector2D Make2D ( void ) const + inline Vector2D Make2D( void ) const { - Vector2D Vec2; + Vector2D Vec2; Vec2.x = x; Vec2.y = y; return Vec2; } - inline float Length2D(void) const { return (float)sqrt(x*x + y*y); } + + inline float Length2D( void ) const + { + return (float)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 ); } + +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 ); } #define vec3_t Vector diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index d0b87c53..401f2c68 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -29,11 +29,11 @@ // Spectator Mode extern "C" { - float vecNewViewAngles[3]; - int iHasNewViewAngles; - float vecNewViewOrigin[3]; - int iHasNewViewOrigin; - int iIsSpectator; + float vecNewViewAngles[3]; + int iHasNewViewAngles; + float vecNewViewOrigin[3]; + int iHasNewViewOrigin; + int iIsSpectator; } #ifndef M_PI @@ -47,19 +47,19 @@ extern "C" void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); - void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); - int PM_GetVisEntInfo( int ent ); - int PM_GetPhysEntInfo( int ent ); - void InterpolateAngles( float * start, float * end, float * output, float frac ); - void NormalizeAngles( float * angles ); - float Distance(const float * v1, const float * v2); - float AngleBetweenVectors( const float * v1, const float * v2 ); + void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert ); + int PM_GetVisEntInfo( int ent ); + int PM_GetPhysEntInfo( int ent ); + void InterpolateAngles( float * start, float * end, float * output, float frac ); + void NormalizeAngles( float * angles ); + float Distance( const float * v1, const float * v2 ); + float AngleBetweenVectors( const float * v1, const float * v2 ); - float vJumpOrigin[3]; - float vJumpAngles[3]; + float vJumpOrigin[3]; + float vJumpAngles[3]; } -void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void V_DropPunchAngle( float frametime, float *ev_punchangle ); void VectorAngles( const float *forward, float *angles ); #include "r_studioint.h" @@ -82,12 +82,12 @@ extern cvar_t *cl_vsmoothing; #define CAM_MODE_RELAX 1 #define CAM_MODE_FOCUS 2 -vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; -float v_frametime, v_lastDistance; -float v_cameraRelaxAngle = 5.0f; -float v_cameraFocusAngle = 35.0f; -int v_cameraMode = CAM_MODE_FOCUS; -qboolean v_resetCamera = 1; +vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; +float v_frametime, v_lastDistance; +float v_cameraRelaxAngle = 5.0f; +float v_cameraFocusAngle = 35.0f; +int v_cameraMode = CAM_MODE_FOCUS; +qboolean v_resetCamera = 1; vec3_t ev_punchangle; @@ -120,21 +120,21 @@ float v_idlescale; // used by TFC for concussion grenade effect void V_NormalizeAngles( float *angles ) { int i; + // Normalize angles - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - if ( angles[i] > 180.0 ) + if( angles[i] > 180.0 ) { angles[i] -= 360.0; } - else if ( angles[i] < -180.0 ) + else if( angles[i] < -180.0 ) { angles[i] += 360.0; } } } - =================== V_InterpolateAngles @@ -148,22 +148,22 @@ void V_InterpolateAngles( float *start, float *end, float *output, float frac ) int i; float ang1, ang2; float d; - + V_NormalizeAngles( start ); V_NormalizeAngles( end ); - for ( i = 0 ; i < 3 ; i++ ) + for( i = 0 ; i < 3 ; i++ ) { ang1 = start[i]; ang2 = end[i]; d = ang2 - ang1; - if ( d > 180 ) + if( d > 180 ) { d -= 360; } - else if ( d < -180 ) - { + else if( d < -180 ) + { d += 360; } @@ -174,16 +174,15 @@ void V_InterpolateAngles( float *start, float *end, float *output, float frac ) } */ // Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear -float V_CalcBob ( struct ref_params_s *pparams ) +float V_CalcBob( struct ref_params_s *pparams ) { - static double bobtime; - static float bob; - float cycle; - static float lasttime; + static double bobtime; + static float bob; + float cycle; + static float lasttime; vec3_t vel; - - if ( pparams->onground == -1 || + if( pparams->onground == -1 || pparams->time == lasttime ) { // just use old value @@ -195,8 +194,8 @@ float V_CalcBob ( struct ref_params_s *pparams ) bobtime += pparams->frametime; cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; cycle /= cl_bobcycle->value; - - if ( cycle < cl_bobup->value ) + + if( cycle < cl_bobup->value ) { cycle = M_PI * cycle / cl_bobup->value; } @@ -215,7 +214,6 @@ float V_CalcBob ( struct ref_params_s *pparams ) bob = min( bob, 4 ); bob = max( bob, -7 ); return bob; - } /* @@ -224,25 +222,25 @@ V_CalcRoll Used by view and sv_user =============== */ -float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +float V_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 ); - + 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) + if( side < rollspeed ) { side = side * value / rollspeed; } - else + else { side = value; } @@ -251,15 +249,14 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspe typedef struct pitchdrift_s { - float pitchvel; - int nodrift; - float driftmove; - double laststop; + float pitchvel; + int nodrift; + float driftmove; + double laststop; } pitchdrift_t; static pitchdrift_t pd; - /* =============== V_DriftPitch @@ -282,21 +279,21 @@ mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. V_CalcGunAngle ================== */ -void V_CalcGunAngle ( struct ref_params_s *pparams ) +void V_CalcGunAngle( struct ref_params_s *pparams ) { cl_entity_t *viewent; - + viewent = gEngfuncs.GetViewModel(); - if ( !viewent ) + if( !viewent ) return; - viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; - viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - + viewent->angles[ROLL] -= v_idlescale * sin( pparams->time * v_iroll_cycle.value ) * v_iroll_level.value; + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. - viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); - viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + viewent->angles[PITCH] -= v_idlescale * sin( pparams->time * v_ipitch_cycle.value ) * ( v_ipitch_level.value * 0.5 ); + viewent->angles[YAW] -= v_idlescale * sin( pparams->time * v_iyaw_cycle.value ) * v_iyaw_level.value; VectorCopy( viewent->angles, viewent->curstate.angles ); VectorCopy( viewent->angles, viewent->latched.prevangles ); @@ -309,14 +306,13 @@ V_AddIdle Idle swaying ============== */ -void V_AddIdle ( struct ref_params_s *pparams ) +void V_AddIdle( struct ref_params_s *pparams ) { - pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; - pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; - pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + pparams->viewangles[ROLL] += v_idlescale * sin( pparams->time * v_iroll_cycle.value ) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin( pparams->time * v_ipitch_cycle.value ) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin( pparams->time * v_iyaw_cycle.value ) * v_iyaw_level.value; } - /* ============== V_CalcViewRoll @@ -324,20 +320,20 @@ V_CalcViewRoll Roll is induced by movement and damage ============== */ -void V_CalcViewRoll ( struct ref_params_s *pparams ) +void V_CalcViewRoll( struct ref_params_s *pparams ) { - float side; + float side; cl_entity_t *viewentity; - + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( !viewentity ) + if( !viewentity ) return; - side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + side = V_CalcRoll( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); pparams->viewangles[ROLL] += side; - if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + if( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) { // only roll the view if the player is dead and the viewheight[2] is nonzero // this is so deadcam in multiplayer will work. @@ -346,26 +342,25 @@ void V_CalcViewRoll ( struct ref_params_s *pparams ) } } - /* ================== V_CalcIntermissionRefdef ================== */ -void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +void V_CalcIntermissionRefdef( struct ref_params_s *pparams ) { - cl_entity_t *ent, *view; - float old; + cl_entity_t *ent, *view; + float old; // ent is the player model ( visible when out of body ) ent = gEngfuncs.GetLocalPlayer(); - + // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); - VectorCopy ( pparams->simorg, pparams->vieworg ); - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + VectorCopy( pparams->simorg, pparams->vieworg ); + VectorCopy( pparams->cl_viewangles, pparams->viewangles ); view->model = NULL; @@ -373,9 +368,9 @@ void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) old = v_idlescale; v_idlescale = 1; - V_AddIdle ( pparams ); + V_AddIdle( pparams ); - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { // in HLTV we must go to 'intermission' position by ourself VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); @@ -394,11 +389,11 @@ void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) typedef struct { - float Origins[ ORIGIN_BACKUP ][3]; - float OriginTime[ ORIGIN_BACKUP ]; + float Origins[ORIGIN_BACKUP][3]; + float OriginTime[ORIGIN_BACKUP]; - float Angles[ ORIGIN_BACKUP ][3]; - float AngleTime[ ORIGIN_BACKUP ]; + float Angles[ORIGIN_BACKUP][3]; + float AngleTime[ORIGIN_BACKUP]; int CurrentOrigin; int CurrentAngle; @@ -410,13 +405,13 @@ V_CalcRefdef ================== */ -void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +void V_CalcNormalRefdef( struct ref_params_s *pparams ) { - cl_entity_t *ent, *view; - int i; - vec3_t angles; - float bob, waterOffset; - static viewinterp_t ViewInterp; + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; static float oldz = 0; static float lasttime; @@ -424,7 +419,7 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) vec3_t camAngles, camForward, camRight, camUp; cl_entity_t *pwater; - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); } @@ -433,20 +428,20 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) // ent is the player model ( visible when out of body ) ent = gEngfuncs.GetLocalPlayer(); } - + // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); // transform the view offset by the model's matrix to get the offset from // model origin for the view - bob = V_CalcBob ( pparams ); + bob = V_CalcBob( pparams ); // refresh position - VectorCopy ( pparams->simorg, pparams->vieworg ); - pparams->vieworg[2] += ( bob ); + VectorCopy( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += bob ; VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + VectorCopy( pparams->cl_viewangles, pparams->viewangles ); gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); @@ -455,28 +450,27 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) // dissapear when viewed with the eye exactly on it. // FIXME, we send origin at 1/128 now, change this? // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis - - pparams->vieworg[0] += 1.0/32; - pparams->vieworg[1] += 1.0/32; - pparams->vieworg[2] += 1.0/32; + pparams->vieworg[0] += 1.0 / 32; + pparams->vieworg[1] += 1.0 / 32; + pparams->vieworg[2] += 1.0 / 32; // Check for problems around water, move the viewer artificially if necessary // -- this prevents drawing errors in GL due to waves waterOffset = 0; - if ( pparams->waterlevel >= 2 ) + if( pparams->waterlevel >= 2 ) { - int contents, waterDist, waterEntity; - vec3_t point; + int contents, waterDist, waterEntity; + vec3_t point; waterDist = cl_waterdist->value; - if ( pparams->hardware ) + if( pparams->hardware ) { waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); - if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + if( waterEntity >= 0 && waterEntity < pparams->max_entities ) { pwater = gEngfuncs.GetEntityByIndex( waterEntity ); - if ( pwater && ( pwater->model != NULL ) ) + if( pwater && ( pwater->model != NULL ) ) { waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height } @@ -486,58 +480,58 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) { waterEntity = 0; // Don't need this in software } - + VectorCopy( pparams->vieworg, point ); // Eyes are above water, make sure we're above the waves - if ( pparams->waterlevel == 2 ) + if( pparams->waterlevel == 2 ) { point[2] -= waterDist; - for ( i = 0; i < waterDist; i++ ) + for( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents > CONTENTS_WATER ) + if( contents > CONTENTS_WATER ) break; point[2] += 1; } - waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + waterOffset = ( point[2] + waterDist ) - pparams->vieworg[2]; } else { // eyes are under water. Make sure we're far enough under point[2] += waterDist; - for ( i = 0; i < waterDist; i++ ) + for( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); - if ( contents <= CONTENTS_WATER ) + if( contents <= CONTENTS_WATER ) break; point[2] -= 1; } - waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + waterOffset = ( point[2] - waterDist ) - pparams->vieworg[2]; } } pparams->vieworg[2] += waterOffset; - - V_CalcViewRoll ( pparams ); - - V_AddIdle ( pparams ); + + V_CalcViewRoll( pparams ); + + V_AddIdle( pparams ); // offsets VectorCopy( pparams->cl_viewangles, angles ); - AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + AngleVectors( angles, pparams->forward, pparams->right, pparams->up ); // don't allow cheats in multiplayer - if ( pparams->maxclients <= 1 ) + if( pparams->maxclients <= 1 ) { - for ( i=0 ; i<3 ; i++ ) + for( i = 0; i < 3; i++ ) { pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; } } - + // Treating cam_ofs[2] as the distance if( CL_IsThirdPerson() ) { @@ -548,39 +542,39 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) CL_CameraOffset( (float *)&ofs ); VectorCopy( ofs, camAngles ); - camAngles[ ROLL ] = 0; + camAngles[ROLL] = 0; AngleVectors( camAngles, camForward, camRight, camUp ); - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + pparams->vieworg[i] += -ofs[2] * camForward[i]; } } - + // Give gun our viewangles - VectorCopy ( pparams->cl_viewangles, view->angles ); - + VectorCopy( pparams->cl_viewangles, view->angles ); + // set up gun position - V_CalcGunAngle ( pparams ); + V_CalcGunAngle( pparams ); // Use predicted origin as view origin. - VectorCopy ( pparams->simorg, view->origin ); - view->origin[2] += ( waterOffset ); + VectorCopy( pparams->simorg, view->origin ); + view->origin[2] += waterOffset; VectorAdd( view->origin, pparams->viewheight, view->origin ); // Let the viewmodel shake at about 10% of the amplitude gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + view->origin[i] += bob * 0.4 * pparams->forward[i]; } view->origin[2] += bob; // throw in a little tilt. - view->angles[YAW] -= bob * 0.5; - view->angles[ROLL] -= bob * 1; + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; view->angles[PITCH] -= bob * 0.3; // pushing the view origin down off of the same X/Z plane as the ent's origin will give the @@ -590,46 +584,46 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) // fudge position around to keep amount of weapon visible // roughly equal with different FOV - if (pparams->viewsize == 110) + if( pparams->viewsize == 110 ) { view->origin[2] += 1; } - else if (pparams->viewsize == 100) + else if( pparams->viewsize == 100 ) { view->origin[2] += 2; } - else if (pparams->viewsize == 90) + else if( pparams->viewsize == 90 ) { view->origin[2] += 1; } - else if (pparams->viewsize == 80) + else if( pparams->viewsize == 80 ) { view->origin[2] += 0.5; } // Add in the punchangle, if any - VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + VectorAdd( pparams->viewangles, pparams->punchangle, pparams->viewangles ); // Include client side punch, too - VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + VectorAdd( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles ); - V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + V_DropPunchAngle( pparams->frametime, (float *)&ev_punchangle ); // smooth out stair step ups #if 1 - if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + if( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0 ) { float steptime; - + steptime = pparams->time - lasttime; - if (steptime < 0) - //FIXME I_Error ("steptime < 0"); + if( steptime < 0 ) + //FIXME I_Error( "steptime < 0" ); steptime = 0; oldz += steptime * 150; - if (oldz > pparams->simorg[2]) + if( oldz > pparams->simorg[2] ) oldz = pparams->simorg[2]; - if (pparams->simorg[2] - oldz > 18) + if( pparams->simorg[2] - oldz > 18 ) oldz = pparams->simorg[2]- 18; pparams->vieworg[2] += oldz - pparams->simorg[2]; view->origin[2] += oldz - pparams->simorg[2]; @@ -639,17 +633,16 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) oldz = pparams->simorg[2]; } #endif - { static float lastorg[3]; vec3_t delta; VectorSubtract( pparams->simorg, lastorg, delta ); - if ( Length( delta ) != 0.0 ) + if( Length( delta ) != 0.0 ) { - VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); - ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + VectorCopy( pparams->simorg, ViewInterp.Origins[ViewInterp.CurrentOrigin & ORIGIN_MASK] ); + ViewInterp.OriginTime[ViewInterp.CurrentOrigin & ORIGIN_MASK] = pparams->time; ViewInterp.CurrentOrigin++; VectorCopy( pparams->simorg, lastorg ); @@ -657,27 +650,27 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) } // Smooth out whole view in multiplayer when on trains, lifts - if ( cl_vsmoothing && cl_vsmoothing->value && + if( cl_vsmoothing && cl_vsmoothing->value && ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) { int foundidx; float t; - if ( cl_vsmoothing->value < 0.0 ) + if( cl_vsmoothing->value < 0.0 ) { gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); } t = pparams->time - cl_vsmoothing->value; - for ( i = 1; i < ORIGIN_MASK; i++ ) + for( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentOrigin - 1 - i; - if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + if( ViewInterp.OriginTime[foundidx & ORIGIN_MASK] <= t ) break; } - if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + if( i < ORIGIN_MASK && ViewInterp.OriginTime[foundidx & ORIGIN_MASK] != 0.0 ) { // Interpolate vec3_t delta; @@ -685,23 +678,22 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) double dt; vec3_t neworg; - dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; - if ( dt > 0.0 ) + dt = ViewInterp.OriginTime[( foundidx + 1 ) & ORIGIN_MASK] - ViewInterp.OriginTime[foundidx & ORIGIN_MASK]; + if( dt > 0.0 ) { - frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = ( t - ViewInterp.OriginTime[foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); - VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); - VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + VectorSubtract( ViewInterp.Origins[( foundidx + 1 ) & ORIGIN_MASK], ViewInterp.Origins[foundidx & ORIGIN_MASK], delta ); + VectorMA( ViewInterp.Origins[foundidx & ORIGIN_MASK], frac, delta, neworg ); // Dont interpolate large changes - if ( Length( delta ) < 64 ) + if( Length( delta ) < 64 ) { VectorSubtract( neworg, pparams->simorg, delta ); VectorAdd( pparams->simorg, delta, pparams->simorg ); VectorAdd( pparams->vieworg, delta, pparams->vieworg ); VectorAdd( view->origin, delta, view->origin ); - } } } @@ -710,34 +702,34 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) // Store off v_angles before munging for third person v_angles = pparams->viewangles; v_lastAngles = pparams->viewangles; -// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! - if ( CL_IsThirdPerson() ) + //v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! + if( CL_IsThirdPerson() ) { - VectorCopy( camAngles, pparams->viewangles); - float pitch = camAngles[ 0 ]; + VectorCopy( camAngles, pparams->viewangles ); + float pitch = camAngles[0]; // Normalize angles - if ( pitch > 180 ) + if( pitch > 180 ) pitch -= 360.0; - else if ( pitch < -180 ) + else if( pitch < -180 ) pitch += 360; // Player pitch is inverted pitch /= -3.0; // Slam local player's pitch value - ent->angles[ 0 ] = pitch; - ent->curstate.angles[ 0 ] = pitch; - ent->prevstate.angles[ 0 ] = pitch; - ent->latched.prevangles[ 0 ] = pitch; + ent->angles[0] = pitch; + ent->curstate.angles[0] = pitch; + ent->prevstate.angles[0] = pitch; + ent->latched.prevangles[0] = pitch; } // override all previous settings if the viewent isn't the client - if ( pparams->viewentity > pparams->maxclients ) + if( pparams->viewentity > pparams->maxclients ) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); - if ( viewentity ) + if( viewentity ) { VectorCopy( viewentity->origin, pparams->vieworg ); VectorCopy( viewentity->angles, pparams->viewangles ); @@ -754,46 +746,46 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) { - float absd,frac,d,threshhold; - + float absd, frac, d, threshhold; + NormalizeAngles( startAngle ); NormalizeAngles( endAngle ); - for ( int i = 0 ; i < 3 ; i++ ) + for( int i = 0; i < 3; i++ ) { d = endAngle[i] - startAngle[i]; - if ( d > 180.0f ) + if( d > 180.0f ) { d -= 360.0f; } - else if ( d < -180.0f ) - { + else if( d < -180.0f ) + { d += 360.0f; } - absd = fabs(d); + absd = fabs( d ); - if ( absd > 0.01f ) + if( absd > 0.01f ) { frac = degreesPerSec * v_frametime; threshhold= degreesPerSec / 4; - if ( absd < threshhold ) + if( absd < threshhold ) { float h = absd / threshhold; h *= h; - frac*= h; // slow down last degrees + frac *= h; // slow down last degrees } - if ( frac > absd ) + if( frac > absd ) { finalAngle[i] = endAngle[i]; } else { - if ( d>0) + if( d > 0 ) finalAngle[i] = startAngle[i] + frac; else finalAngle[i] = startAngle[i] - frac; @@ -803,7 +795,6 @@ void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * fi { finalAngle[i] = endAngle[i]; } - } NormalizeAngles( finalAngle ); @@ -812,88 +803,88 @@ void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * fi // Get the origin of the Observer based around the target's position and angles void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) { - vec3_t vecEnd; - vec3_t forward; - vec3_t vecStart; - pmtrace_t * trace; + vec3_t vecEnd; + vec3_t forward; + vec3_t vecStart; + pmtrace_t *trace; int maxLoops = 8; int ignoreent = -1; // first, ignore no entity - - cl_entity_t * ent = NULL; - + + cl_entity_t *ent = NULL; + // Trace back from the target using the player's view angles - AngleVectors(angles, forward, NULL, NULL); - - VectorScale(forward,-1,forward); + AngleVectors( angles, forward, NULL, NULL ); + + VectorScale( forward, -1, forward ); VectorCopy( origin, vecStart ); - VectorMA(vecStart, distance , forward, vecEnd); + VectorMA( vecStart, distance , forward, vecEnd ); - while ( maxLoops > 0) + while( maxLoops > 0 ) { trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); // WARNING! trace->ent is is the number in physent list not the normal entity number - if ( trace->ent <= 0) + if( trace->ent <= 0) break; // we hit the world or nothing, stop trace ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); - if ( ent == NULL ) + if( ent == NULL ) break; // hit non-player solid BSP , stop here - if ( ent->curstate.solid == SOLID_BSP && !ent->player ) + if( ent->curstate.solid == SOLID_BSP && !ent->player ) break; // if close enought to end pos, stop, otherwise continue trace - if( Distance(trace->endpos, vecEnd ) < 1.0f ) + if( Distance( trace->endpos, vecEnd ) < 1.0f ) { break; } else { ignoreent = trace->ent; // ignore last hit entity - VectorCopy( trace->endpos, vecStart); + VectorCopy( trace->endpos, vecStart ); } maxLoops--; - } + } -/* if ( ent ) +/* if( ent ) { - gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); + gEngfuncs.Con_Printf( "Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); } */ VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); - v_lastDistance = Distance(trace->endpos, origin); // real distance without offset + v_lastDistance = Distance( trace->endpos, origin ); // real distance without offset } -/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) +/*void V_GetDeathCam( cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin ) { - float newAngle[3]; float newOrigin[3]; + float newAngle[3]; float newOrigin[3]; float distance = 168.0f; - v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back + v_lastDistance += v_frametime * 96.0f; // move unit per seconds back - if ( v_resetCamera ) + if( v_resetCamera ) v_lastDistance = 64.0f; - if ( distance > v_lastDistance ) + if( distance > v_lastDistance ) distance = v_lastDistance; - VectorCopy(ent1->origin, newOrigin); + VectorCopy( ent1->origin, newOrigin ); - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player + if( ent1->player ) + newOrigin[2] += 17; // head level of living player // get new angle towards second target - if ( ent2 ) + if( ent2 ) { VectorSubtract( ent2->origin, ent1->origin, newAngle ); VectorAngles( newAngle, newAngle ); @@ -909,70 +900,68 @@ void V_GetChaseOrigin( float * angles, float * origin, float distance, float * r // and smooth view V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); - + V_GetChaseOrigin( angle, newOrigin, distance, origin ); - VectorCopy(angle, v_lastAngles); + VectorCopy( angle, v_lastAngles ); }*/ -void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) +void V_GetSingleTargetCam( cl_entity_t * ent1, float * angle, float * origin ) { - float newAngle[3]; float newOrigin[3]; - - int flags = gHUD.m_Spectator.m_iObserverFlags; + float newAngle[3]; float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; // see is target is a dead player - qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); - - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + qboolean deadPlayer = ent1->player && ( ent1->curstate.solid == SOLID_NOT ); + + float dfactor = ( flags & DRC_FLAG_DRAMATIC ) ? -1.0f : 1.0f; float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - + // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - else if ( deadPlayer ) - distance*=1.5f; + if( flags & DRC_FLAG_FINAL ) + distance *= 2.0f; + else if( deadPlayer ) + distance *= 1.5f; // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + v_lastDistance += v_frametime * 32.0f; // move unit per seconds back - if ( distance > v_lastDistance ) + if( distance > v_lastDistance ) distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - if ( ent1->player ) + VectorCopy( ent1->origin, newOrigin ); + + if( ent1->player ) { - if ( deadPlayer ) - newOrigin[2]+= 2; //laying on ground + if( deadPlayer ) + newOrigin[2] += 2; //laying on ground else - newOrigin[2]+= 17; // head level of living player - + newOrigin[2] += 17; // head level of living player } else newOrigin[2]+= 8; // object, tricky, must be above bomb in CS // we have no second target, choose view direction based on // show front of primary target - VectorCopy(ent1->angles, newAngle); + VectorCopy( ent1->angles, newAngle ); // show dead players from front, normal players back - if ( flags & DRC_FLAG_FACEPLAYER ) - newAngle[1]+= 180.0f; + if( flags & DRC_FLAG_FACEPLAYER ) + newAngle[1] += 180.0f; - - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + newAngle[0] += 12.5f * dfactor; // lower angle if dramatic // if final scene (bomb), show from real high pos - if ( flags & DRC_FLAG_FINAL ) + if( flags & DRC_FLAG_FINAL ) newAngle[0] = 22.5f; // choose side of object/player - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; + if( flags & DRC_FLAG_SIDE ) + newAngle[1] += 22.5f; else - newAngle[1]-=22.5f; + newAngle[1] -= 22.5f; V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); @@ -980,60 +969,60 @@ void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) V_GetChaseOrigin( angle, newOrigin, distance, origin ); } -float MaxAngleBetweenAngles( float * a1, float * a2 ) +float MaxAngleBetweenAngles( float *a1, float *a2 ) { float d, maxd = 0.0f; NormalizeAngles( a1 ); NormalizeAngles( a2 ); - for ( int i = 0 ; i < 3 ; i++ ) + for( int i = 0; i < 3; i++ ) { d = a2[i] - a1[i]; - if ( d > 180 ) + if( d > 180 ) { d -= 360; } - else if ( d < -180 ) + else if( d < -180 ) { d += 360; } - d = fabs(d); + d = fabs( d ); - if ( d > maxd ) - maxd=d; + if( d > maxd ) + maxd = d; } return maxd; } -void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +void V_GetDoubleTargetsCam( cl_entity_t *ent1, cl_entity_t *ent2, float *angle, float *origin ) { - float newAngle[3]; float newOrigin[3]; float tempVec[3]; + float newAngle[3], newOrigin[3], tempVec[3]; - int flags = gHUD.m_Spectator.m_iObserverFlags; + int flags = gHUD.m_Spectator.m_iObserverFlags; - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + float dfactor = ( flags & DRC_FLAG_DRAMATIC ) ? -1.0f : 1.0f; float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - - // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - - // let v_lastDistance float smoothly away - v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - if ( distance > v_lastDistance ) + // go away in final scenes or if player just died + if( flags & DRC_FLAG_FINAL ) + distance *= 2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance += v_frametime * 32.0f; // move unit per seconds back + + if( distance > v_lastDistance ) distance = v_lastDistance; - VectorCopy(ent1->origin, newOrigin); + VectorCopy( ent1->origin, newOrigin ); - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player + if( ent1->player ) + newOrigin[2] += 17; // head level of living player else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + newOrigin[2] += 8; // object, tricky, must be above bomb in CS // get new angle towards second target VectorSubtract( ent2->origin, ent1->origin, newAngle ); @@ -1042,21 +1031,21 @@ void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle newAngle[0] = -newAngle[0]; // set angle diffrent in Dramtaic scenes - newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic - - if ( flags & DRC_FLAG_SIDE ) - newAngle[1]+=22.5f; + newAngle[0] += 12.5f * dfactor; // lower angle if dramatic + + if( flags & DRC_FLAG_SIDE ) + newAngle[1] += 22.5f; else - newAngle[1]-=22.5f; + newAngle[1] -= 22.5f; float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); - if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) + if( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) { // difference is to small and we are in relax camera mode, keep viewangles - VectorCopy(v_lastAngles, newAngle ); + VectorCopy( v_lastAngles, newAngle ); } - else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) + else if( ( d < v_cameraRelaxAngle ) && ( v_cameraMode == CAM_MODE_FOCUS ) ) { // we catched up with our target, relax again v_cameraMode = CAM_MODE_RELAX; @@ -1068,7 +1057,7 @@ void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle } // and smooth view, if not a scene cut - if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) + if( v_resetCamera || ( v_cameraMode == CAM_MODE_RELAX ) ) { VectorCopy( newAngle, angle ); } @@ -1080,8 +1069,8 @@ void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); // move position up, if very close at target - if ( v_lastDistance < 64.0f ) - origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); + if( v_lastDistance < 64.0f ) + origin[2] += 16.0f * ( 1.0f - ( v_lastDistance / 64.0f ) ); // calculate angle to second target VectorSubtract( ent2->origin, origin, tempVec ); @@ -1089,27 +1078,23 @@ void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle tempVec[0] = -tempVec[0]; /* take middle between two viewangles - InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ - - - + InterpolateAngles( newAngle, tempVec, newAngle, 0.5f ); */ } -void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +void V_GetDirectedChasePosition(cl_entity_t *ent1, cl_entity_t *ent2,float *angle, float *origin) { - - if ( v_resetCamera ) + if( v_resetCamera ) { v_lastDistance = 4096.0f; // v_cameraMode = CAM_MODE_FOCUS; } - if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) + if( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && ( ent1->curstate.solid == SOLID_NOT ) ) ) { // we have no second target or player just died - V_GetSingleTargetCam(ent1, angle, origin); + V_GetSingleTargetCam( ent1, angle, origin ); } - else if ( ent2 ) + else if( ent2 ) { // keep both target in view V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); @@ -1121,77 +1106,74 @@ void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * // keep last good viewangle float newOrigin[3]; - int flags = gHUD.m_Spectator.m_iObserverFlags; + int flags = gHUD.m_Spectator.m_iObserverFlags; - float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + float dfactor = ( flags & DRC_FLAG_DRAMATIC ) ? -1.0f : 1.0f; float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; - + // go away in final scenes or if player just died - if ( flags & DRC_FLAG_FINAL ) - distance*=2.0f; - + if( flags & DRC_FLAG_FINAL ) + distance *= 2.0f; + // let v_lastDistance float smoothly away v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back - if ( distance > v_lastDistance ) + if( distance > v_lastDistance ) distance = v_lastDistance; - - VectorCopy(ent1->origin, newOrigin); - if ( ent1->player ) - newOrigin[2]+= 17; // head level of living player + VectorCopy( ent1->origin, newOrigin ); + + if( ent1->player ) + newOrigin[2] += 17; // head level of living player else - newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + newOrigin[2] += 8; // object, tricky, must be above bomb in CS V_GetChaseOrigin( angle, newOrigin, distance, origin ); } - VectorCopy(angle, v_lastAngles); + VectorCopy( angle, v_lastAngles ); } -void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) +void V_GetChasePos( int target, float *cl_angles, float *origin, float *angles ) { - cl_entity_t * ent = NULL; - - if ( target ) + cl_entity_t *ent = NULL; + + if( target ) { ent = gEngfuncs.GetEntityByIndex( target ); - }; - - if (!ent) - { - // just copy a save in-map position - VectorCopy ( vJumpAngles, angles ); - VectorCopy ( vJumpOrigin, origin ); - return; } - - - if ( gHUD.m_Spectator.m_autoDirector->value ) + if( !ent ) { - if ( g_iUser3 ) + // just copy a save in-map position + VectorCopy( vJumpAngles, angles ); + VectorCopy( vJumpOrigin, origin ); + return; + } + + if( gHUD.m_Spectator.m_autoDirector->value ) + { + if( g_iUser3 ) V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), angles, origin ); else - V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, + V_GetDirectedChasePosition( ent, (cl_entity_t*)0xFFFFFFFF, angles, origin ); } else { - if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) + if( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) { - VectorCopy ( ent->angles, angles); - angles[0]*=-1; + VectorCopy( ent->angles, angles); + angles[0] *= -1; } else - VectorCopy ( cl_angles, angles); + VectorCopy( cl_angles, angles ); + VectorCopy( ent->origin, origin ); - VectorCopy ( ent->origin, origin); - - origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset + origin[2] += 28; // DEFAULT_VIEWHEIGHT - some offset V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); } @@ -1204,10 +1186,9 @@ void V_ResetChaseCam() v_resetCamera = true; } - -void V_GetInEyePos(int target, float * origin, float * angles ) +void V_GetInEyePos( int target, float *origin, float *angles ) { - if ( !target) + if( !target ) { // just copy a save in-map position VectorCopy ( vJumpAngles, angles ); @@ -1215,126 +1196,125 @@ void V_GetInEyePos(int target, float * origin, float * angles ) return; }; + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( target ); - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); - - if ( !ent ) + if( !ent ) return; - VectorCopy ( ent->origin, origin ); - VectorCopy ( ent->angles, angles ); + VectorCopy( ent->origin, origin ); + VectorCopy( ent->angles, angles ); - angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + angles[PITCH] *= -3.0f; // see CL_ProcessEntityUpdate() - if ( ent->curstate.solid == SOLID_NOT ) + if( ent->curstate.solid == SOLID_NOT ) { angles[ROLL] = 80; // dead view angle - origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + origin[2] += -8 ; // PM_DEAD_VIEWHEIGHT } - else if (ent->curstate.usehull == 1 ) - origin[2]+= 12; // VEC_DUCK_VIEW; + else if( ent->curstate.usehull == 1 ) + origin[2] += 12; // VEC_DUCK_VIEW; else // exacty eye position can't be caluculated since it depends on // client values like cl_bobcycle, this offset matches the default values - origin[2]+= 28; // DEFAULT_VIEWHEIGHT + origin[2] += 28; // DEFAULT_VIEWHEIGHT } -void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) +void V_GetMapFreePosition( float *cl_angles, float *origin, float *angles ) { vec3_t forward; vec3_t zScaledTarget; - VectorCopy(cl_angles, angles); + VectorCopy( cl_angles, angles ); // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + angles[0] = 51.25f + 38.75f * ( angles[0] / 90.0f ); zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; - zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); - + zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * ( ( 90.0f - angles[0] ) / 90.0f ); - AngleVectors(angles, forward, NULL, NULL); + AngleVectors( angles, forward, NULL, NULL ); - VectorNormalize(forward); + VectorNormalize( forward ); - VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); + VectorMA( zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward, origin ); } -void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) +void V_GetMapChasePosition( int target, float *cl_angles, float *origin, float *angles ) { vec3_t forward; - if ( target ) + if( target ) { - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( target ); - if ( gHUD.m_Spectator.m_autoDirector->value ) + if( gHUD.m_Spectator.m_autoDirector->value ) { // this is done to get the angles made by director mode - V_GetChasePos(target, cl_angles, origin, angles); - VectorCopy(ent->origin, origin); - + V_GetChasePos( target, cl_angles, origin, angles ); + VectorCopy( ent->origin, origin ); + // keep fix chase angle horizontal angles[0] = 45.0f; } else { - VectorCopy(cl_angles, angles); - VectorCopy(ent->origin, origin); + VectorCopy( cl_angles, angles ); + VectorCopy( ent->origin, origin ); // modify angles since we don't wanna see map's bottom - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + angles[0] = 51.25f + 38.75f * ( angles[0] / 90.0f ); } } else { // keep out roaming position, but modify angles - VectorCopy(cl_angles, angles); - angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + VectorCopy( cl_angles, angles ); + angles[0] = 51.25f + 38.75f * ( angles[0] / 90.0f ); } - origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); + origin[2] *= ( ( 90.0f - angles[0] ) / 90.0f ); angles[2] = 0.0f; // don't roll angle (if chased player is dead) - AngleVectors(angles, forward, NULL, NULL); + AngleVectors( angles, forward, NULL, NULL ); - VectorNormalize(forward); + VectorNormalize( forward ); - VectorMA(origin, -1536, forward, origin); + VectorMA( origin, -1536, forward, origin ); } -int V_FindViewModelByWeaponModel(int weaponindex) +int V_FindViewModelByWeaponModel( int weaponindex ) { - - static char * modelmap[][2] = { - { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, - { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, - { "models/p_egon.mdl", "models/v_egon.mdl" }, - { "models/p_gauss.mdl", "models/v_gauss.mdl" }, - { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, - { "models/p_grenade.mdl", "models/v_grenade.mdl" }, - { "models/p_hgun.mdl", "models/v_hgun.mdl" }, - { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, - { "models/p_357.mdl", "models/v_357.mdl" }, - { "models/p_rpg.mdl", "models/v_rpg.mdl" }, - { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, - { "models/p_squeak.mdl", "models/v_squeak.mdl" }, - { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, - { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, - { "models/p_satchel.mdl", "models/v_satchel.mdl" }, - { NULL, NULL } }; + static char *modelmap[][2] = + { + { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, + { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, + { "models/p_egon.mdl", "models/v_egon.mdl" }, + { "models/p_gauss.mdl", "models/v_gauss.mdl" }, + { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, + { "models/p_grenade.mdl", "models/v_grenade.mdl" }, + { "models/p_hgun.mdl", "models/v_hgun.mdl" }, + { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, + { "models/p_357.mdl", "models/v_357.mdl" }, + { "models/p_rpg.mdl", "models/v_rpg.mdl" }, + { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, + { "models/p_squeak.mdl", "models/v_squeak.mdl" }, + { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, + { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl" }, + { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { NULL, NULL } + }; struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); - if ( weaponModel ) + if( weaponModel ) { int len = strlen( weaponModel->name ); int i = 0; - while ( modelmap[i][0] != NULL ) + while( modelmap[i][0] != NULL ) { - if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) + if( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) { return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); } @@ -1345,71 +1325,68 @@ int V_FindViewModelByWeaponModel(int weaponindex) } else return 0; - } - /* ================== V_CalcSpectatorRefdef ================== */ -void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) +void V_CalcSpectatorRefdef( struct ref_params_s * pparams ) { - static vec3_t velocity ( 0.0f, 0.0f, 0.0f); + static vec3_t velocity( 0.0f, 0.0f, 0.0f ); static int lastWeaponModelIndex = 0; static int lastViewModelIndex = 0; - - cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); - + + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + pparams->onlyClientDraw = false; // refresh position - VectorCopy ( pparams->simorg, v_sim_org ); + VectorCopy( pparams->simorg, v_sim_org ); // get old values - VectorCopy ( pparams->cl_viewangles, v_cl_angles ); - VectorCopy ( pparams->viewangles, v_angles ); - VectorCopy ( pparams->vieworg, v_origin ); + VectorCopy( pparams->cl_viewangles, v_cl_angles ); + VectorCopy( pparams->viewangles, v_angles ); + VectorCopy( pparams->vieworg, v_origin ); - if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) + if( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) { // calculate player velocity float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; - if ( timeDiff > 0 ) + if( timeDiff > 0 ) { vec3_t distance; - VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); - VectorScale(distance, 1/timeDiff, distance ); + VectorSubtract( ent->prevstate.origin, ent->curstate.origin, distance ); + VectorScale( distance, 1 / timeDiff, distance ); - velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; - velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; - velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; - - VectorCopy(velocity, pparams->simvel); + velocity[0] = velocity[0] * 0.9f + distance[0] * 0.1f; + velocity[1] = velocity[1] * 0.9f + distance[1] * 0.1f; + velocity[2] = velocity[2] * 0.9f + distance[2] * 0.1f; + + VectorCopy( velocity, pparams->simvel ); } // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) - if ( gEngfuncs.IsSpectateOnly() ) + if( gEngfuncs.IsSpectateOnly() ) { V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); pparams->health = 1; - cl_entity_t * gunModel = gEngfuncs.GetViewModel(); + cl_entity_t *gunModel = gEngfuncs.GetViewModel(); - if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) + if( lastWeaponModelIndex != ent->curstate.weaponmodel ) { // weapon model changed - lastWeaponModelIndex = ent->curstate.weaponmodel; lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); - if ( lastViewModelIndex ) + if( lastViewModelIndex ) { - gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation + gEngfuncs.pfnWeaponAnim( 0, 0 ); // reset weapon animation } else { @@ -1419,7 +1396,7 @@ void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) } } - if ( lastViewModelIndex ) + if( lastViewModelIndex ) { gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); gunModel->curstate.modelindex = lastViewModelIndex; @@ -1435,109 +1412,102 @@ void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) else { // only get viewangles from entity - VectorCopy ( ent->angles, pparams->cl_viewangles ); - pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + VectorCopy( ent->angles, pparams->cl_viewangles ); + pparams->cl_viewangles[PITCH] *= -3.0f; // see CL_ProcessEntityUpdate() } } v_frametime = pparams->frametime; - if ( pparams->nextView == 0 ) + if( pparams->nextView == 0 ) { // first renderer cycle, full screen - - switch ( g_iUser1 ) + switch( g_iUser1 ) { - case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); - break; - - case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); - VectorCopy (v_sim_org, v_origin); - break; - - case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); - break; - - case OBS_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case OBS_MAP_CHASE : pparams->onlyClientDraw = true; - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; + case OBS_CHASE_LOCKED: + V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + case OBS_CHASE_FREE: + V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + case OBS_ROAMING: + VectorCopy( v_cl_angles, v_angles ); + VectorCopy( v_sim_org, v_origin ); + break; + case OBS_IN_EYE: + V_CalcNormalRefdef( pparams ); + break; + case OBS_MAP_FREE: + pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + case OBS_MAP_CHASE: + pparams->onlyClientDraw = true; + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; } - if ( gHUD.m_Spectator.m_pip->value ) + if( gHUD.m_Spectator.m_pip->value ) pparams->nextView = 1; // force a second renderer view gHUD.m_Spectator.m_iDrawCycle = 0; - } else { // second renderer cycle, inset window - // set inset parameters - pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window - pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); - pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); - pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); - pparams->nextView = 0; // on further view + pparams->viewport[0] = XRES( gHUD.m_Spectator.m_OverviewData.insetWindowX ); // change viewport to inset window + pparams->viewport[1] = YRES( gHUD.m_Spectator.m_OverviewData.insetWindowY ); + pparams->viewport[2] = XRES( gHUD.m_Spectator.m_OverviewData.insetWindowWidth ); + pparams->viewport[3] = YRES( gHUD.m_Spectator.m_OverviewData.insetWindowHeight ); + pparams->nextView = 0; // on further view // override some settings in certain modes - switch ( (int)gHUD.m_Spectator.m_pip->value ) + switch( (int)gHUD.m_Spectator.m_pip->value ) { - case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); - break; - - case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); - break; - - case INSET_MAP_FREE : pparams->onlyClientDraw = true; - V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); - break; - - case INSET_MAP_CHASE : pparams->onlyClientDraw = true; - - if ( g_iUser1 == OBS_ROAMING ) - V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); - else - V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); - - break; + case INSET_CHASE_FREE: + V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + case INSET_IN_EYE: + V_CalcNormalRefdef( pparams ); + break; + case INSET_MAP_FREE: + pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + case INSET_MAP_CHASE: + pparams->onlyClientDraw = true; + if( g_iUser1 == OBS_ROAMING ) + V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); + else + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; } gHUD.m_Spectator.m_iDrawCycle = 1; } // write back new values into pparams - VectorCopy ( v_cl_angles, pparams->cl_viewangles ); - VectorCopy ( v_angles, pparams->viewangles ) - VectorCopy ( v_origin, pparams->vieworg ); - + VectorCopy( v_cl_angles, pparams->cl_viewangles ); + VectorCopy( v_angles, pparams->viewangles ) + VectorCopy( v_origin, pparams->vieworg ); } - - void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) { // intermission / finale rendering - if ( pparams->intermission ) - { - V_CalcIntermissionRefdef ( pparams ); - } - else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode + if( pparams->intermission ) { - V_CalcSpectatorRefdef ( pparams ); + V_CalcIntermissionRefdef( pparams ); } - else if ( !pparams->paused ) + else if( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode { - V_CalcNormalRefdef ( pparams ); + V_CalcSpectatorRefdef( pparams ); + } + else if( !pparams->paused ) + { + V_CalcNormalRefdef( pparams ); } - /* // Example of how to overlay the whole screen with red at 50 % alpha #define SF_TEST @@ -1564,14 +1534,14 @@ V_DropPunchAngle ============= */ -void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +void V_DropPunchAngle( float frametime, float *ev_punchangle ) { - float len; - - len = VectorNormalize ( ev_punchangle ); - len -= (10.0 + len * 0.5) * frametime; + float len; + + len = VectorNormalize( ev_punchangle ); + len -= ( 10.0 + len * 0.5 ) * frametime; len = max( len, 0.0 ); - VectorScale ( ev_punchangle, len, ev_punchangle ); + VectorScale( ev_punchangle, len, ev_punchangle ); } /* @@ -1583,7 +1553,7 @@ Client side punch effect */ void V_PunchAxis( int axis, float punch ) { - ev_punchangle[ axis ] = punch; + ev_punchangle[axis] = punch; } /* @@ -1591,24 +1561,22 @@ void V_PunchAxis( int axis, float punch ) V_Init ============= */ -void V_Init (void) +void V_Init( void ) { + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); - scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); - scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); - scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); - v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); - v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); - - cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) - cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) - cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); - cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); - cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); + cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); } - //#define TRACE_TEST #if defined( TRACE_TEST ) @@ -1618,19 +1586,19 @@ extern float in_fov; CalcFov ==================== */ -float CalcFov (float fov_x, float width, float height) +float CalcFov( float fov_x, float width, float height ) { - float a; - float x; + float a; + float x; - if (fov_x < 1 || fov_x > 179) + if( fov_x < 1 || fov_x > 179 ) fov_x = 90; // error, set to 90 - x = width/tan(fov_x/360*M_PI); + x = width / tan( fov_x / 360 * M_PI ); - a = atan (height/x); + a = atan ( height / x ); - a = a*360/M_PI; + a = a * 360 / M_PI; return a; } @@ -1667,18 +1635,18 @@ void V_Move( int mx, int my ) newangles = v_angles; - newangles[ YAW ] -= dX; - newangles[ PITCH ] += dY; + newangles[YAW] -= dX; + newangles[PITCH] += dY; // Now rotate v_forward around that point - AngleVectors ( newangles, forward, right, up ); + AngleVectors( newangles, forward, right, up ); farpoint = v_origin + 8192 * forward; // Trace - tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + tr = *( gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 ) ); - if ( tr.fraction != 1.0 && tr.ent != 0 ) + if( tr.fraction != 1.0 && tr.ent != 0 ) { hitent = PM_GetPhysEntInfo( tr.ent ); PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); @@ -1688,5 +1656,4 @@ void V_Move( int mx, int my ) hitent = -1; } } - #endif diff --git a/cl_dll/view.h b/cl_dll/view.h index 1afbe38e..c0aa0e8f 100644 --- a/cl_dll/view.h +++ b/cl_dll/view.h @@ -11,5 +11,4 @@ void V_StartPitchDrift( void ); void V_StopPitchDrift( void ); - -#endif // !VIEWH \ No newline at end of file +#endif // !VIEWH From 811d1fb20cd38c3ed57ed3382cdd712917c931a0 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 3 Jul 2016 18:48:16 +0500 Subject: [PATCH 046/227] Move tf_defs.h to cl_dll/tfc directory. --- cl_dll/{ => tfc}/tf_defs.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cl_dll/{ => tfc}/tf_defs.h (100%) diff --git a/cl_dll/tf_defs.h b/cl_dll/tfc/tf_defs.h similarity index 100% rename from cl_dll/tf_defs.h rename to cl_dll/tfc/tf_defs.h From 7b24b6a6db3deaf50c73820e0c7d24fdd1d94b02 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 3 Jul 2016 18:59:31 +0500 Subject: [PATCH 047/227] Move GameStudioModelRenderer_Sample to cl_dll/examples directory. --- cl_dll/{ => examples}/GameStudioModelRenderer_Sample.cpp | 0 cl_dll/{ => examples}/GameStudioModelRenderer_Sample.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cl_dll/{ => examples}/GameStudioModelRenderer_Sample.cpp (100%) rename cl_dll/{ => examples}/GameStudioModelRenderer_Sample.h (100%) diff --git a/cl_dll/GameStudioModelRenderer_Sample.cpp b/cl_dll/examples/GameStudioModelRenderer_Sample.cpp similarity index 100% rename from cl_dll/GameStudioModelRenderer_Sample.cpp rename to cl_dll/examples/GameStudioModelRenderer_Sample.cpp diff --git a/cl_dll/GameStudioModelRenderer_Sample.h b/cl_dll/examples/GameStudioModelRenderer_Sample.h similarity index 100% rename from cl_dll/GameStudioModelRenderer_Sample.h rename to cl_dll/examples/GameStudioModelRenderer_Sample.h From 31a84015ef7b3177cc7f8828d6ba9fb2186d8df0 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 21 Jul 2016 20:38:30 +0000 Subject: [PATCH 048/227] Skip gauss idle animation on client --- dlls/gauss.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 2830c9a9..78ad6493 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -583,8 +583,9 @@ void CGauss::WeaponIdle( void ) iAnim = GAUSS_FIDGET; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } +#ifndef CLIENT_DLL SendWeaponAnim( iAnim ); - +#endif } } From a52fda0b19960c3339b2d6574c7358673e82cf13 Mon Sep 17 00:00:00 2001 From: a1batross Date: Thu, 28 Jul 2016 22:46:39 +0600 Subject: [PATCH 049/227] Don't write viewangles to engine while dead(fix of rotating corpses). Don't let any movement during intermission --- cl_dll/input_xash3d.cpp | 85 +++++++++++++++++++++++++---------------- cl_dll/view.cpp | 35 +++++++++++++---- 2 files changed, 80 insertions(+), 40 deletions(-) diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index dd621d19..128d6fa4 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -54,6 +54,8 @@ float rel_pitch; #define IMPULSE_DOWN 2 #define IMPULSE_UP 4 +bool CL_IsDead(); +Vector dead_viewangles(0, 0, 0); void IN_ToggleButtons( float forwardmove, float sidemove ) { @@ -152,9 +154,17 @@ void IN_ClientLookEvent( float relyaw, float relpitch ) void IN_Move( float frametime, usercmd_t *cmd ) { Vector viewangles; - gEngfuncs.GetViewAngles( viewangles ); bool fLadder = false; - if( cl_laddermode->value !=2 ) fLadder = gEngfuncs.GetLocalPlayer()->curstate.movetype == MOVETYPE_FLY; + + if( gHUD.m_iIntermission ) + return; // we can't move during intermission + + if( cl_laddermode->value != 2 ) + { + cl_entity_t *pplayer = gEngfuncs.GetLocalPlayer(); + if( pplayer ) + fLadder = pplayer->curstate.movetype == MOVETYPE_FLY; + } //if(ac_forwardmove || ac_sidemove) //gEngfuncs.Con_Printf("Move: %f %f %f %f\n", ac_forwardmove, ac_sidemove, rel_pitch, rel_yaw); #if 0 @@ -163,39 +173,49 @@ void IN_Move( float frametime, usercmd_t *cmd ) V_StopPitchDrift(); } #endif - if( !gHUD.m_iIntermission ) + if( CL_IsDead() ) { - if( gHUD.GetSensitivity() != 0 ) - { - rel_yaw *= gHUD.GetSensitivity(); - rel_pitch *= gHUD.GetSensitivity(); - } - else - { - rel_yaw *= sensitivity->value; - rel_pitch *= sensitivity->value; - } - - viewangles[YAW] += rel_yaw; - if( fLadder ) - { - if( cl_laddermode->value == 1 ) - viewangles[YAW] -= ac_sidemove * 5; - ac_sidemove = 0; - } - if(gHUD.m_MOTD.m_bShow) - gHUD.m_MOTD.scroll += rel_pitch; - else - viewangles[PITCH] += rel_pitch; - if (viewangles[PITCH] > cl_pitchdown->value) - viewangles[PITCH] = cl_pitchdown->value; - if (viewangles[PITCH] < -cl_pitchup->value) - viewangles[PITCH] = -cl_pitchup->value; + viewangles = dead_viewangles; // HACKHACK: see below } - float rgfl[3]; - viewangles.CopyToArray( rgfl ); - gEngfuncs.SetViewAngles( rgfl ); + else + { + gEngfuncs.GetViewAngles( viewangles ); + } + if( gHUD.GetSensitivity() != 0 ) + { + rel_yaw *= gHUD.GetSensitivity(); + rel_pitch *= gHUD.GetSensitivity(); + } + else + { + rel_yaw *= sensitivity->value; + rel_pitch *= sensitivity->value; + } + viewangles[YAW] += rel_yaw; + if( fLadder ) + { + if( cl_laddermode->value == 1 ) + viewangles[YAW] -= ac_sidemove * 5; + ac_sidemove = 0; + } + if(gHUD.m_MOTD.m_bShow) + gHUD.m_MOTD.scroll += rel_pitch; + else + viewangles[PITCH] += rel_pitch; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + // HACKHACK: change viewangles directly in viewcode, + // so viewangles when player is dead will not be changed on server + if( !CL_IsDead() ) + { + gEngfuncs.SetViewAngles( viewangles ); + } + + dead_viewangles = viewangles; // keep them actual if( ac_movecount ) { IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); @@ -206,7 +226,6 @@ void IN_Move( float frametime, usercmd_t *cmd ) cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; } - } ac_sidemove = ac_forwardmove = rel_pitch = rel_yaw = 0; diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index d0b87c53..2253a784 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -78,6 +78,7 @@ extern cvar_t *cl_forwardspeed; extern cvar_t *chase_active; extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; extern cvar_t *cl_vsmoothing; +extern Vector dead_viewangles; #define CAM_MODE_RELAX 1 #define CAM_MODE_FOCUS 2 @@ -434,7 +435,7 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) ent = gEngfuncs.GetLocalPlayer(); } - // view is the weapon model (only visible from inside body ) + // view is the weapon model (only visible from inside body) view = gEngfuncs.GetViewModel(); // transform the view offset by the model's matrix to get the offset from @@ -446,7 +447,14 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) pparams->vieworg[2] += ( bob ); VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); - VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + if( pparams->health <= 0 ) + { + VectorCopy( dead_viewangles, pparams->viewangles ); + } + else + { + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + } gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); @@ -525,7 +533,14 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) V_AddIdle ( pparams ); // offsets - VectorCopy( pparams->cl_viewangles, angles ); + if ( pparams->health <= 0 ) + { + VectorCopy( dead_viewangles, angles ); + } + else + { + VectorCopy( pparams->cl_viewangles, angles ); + } AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); @@ -559,8 +574,14 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) } // Give gun our viewangles - VectorCopy ( pparams->cl_viewangles, view->angles ); - + if ( pparams->health <= 0 ) + { + VectorCopy( dead_viewangles, view->angles ); + } + else + { + VectorCopy ( pparams->cl_viewangles, view->angles ); + } // set up gun position V_CalcGunAngle ( pparams ); @@ -611,7 +632,7 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); // Include client side punch, too - VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles ); V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); @@ -623,7 +644,7 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams ) steptime = pparams->time - lasttime; if (steptime < 0) - //FIXME I_Error ("steptime < 0"); + //FIXME I_Error ("steptime < 0"); steptime = 0; oldz += steptime * 150; From 5890ff41eef0cf16da1369ae99b83a10c1b8ed10 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 31 Jul 2016 18:48:50 +0500 Subject: [PATCH 050/227] Server format. --- dlls/activity.h | 9 +- dlls/aflock.cpp | 431 +++--- dlls/agrunt.cpp | 628 +++++---- dlls/airtank.cpp | 44 +- dlls/animating.cpp | 147 +- dlls/animation.cpp | 280 ++-- dlls/animation.h | 2 - dlls/apache.cpp | 447 ++++--- dlls/barnacle.cpp | 218 +-- dlls/barney.cpp | 446 +++---- dlls/basemonster.h | 438 +++--- dlls/bigmomma.cpp | 488 ++++--- dlls/bloater.cpp | 92 +- dlls/bmodels.cpp | 504 ++++--- dlls/bullsquid.cpp | 839 ++++++------ dlls/buttons.cpp | 790 ++++++----- dlls/cbase.cpp | 340 ++--- dlls/cbase.h | 377 +++--- dlls/cdll_dll.h | 13 +- dlls/client.cpp | 989 +++++++------- dlls/client.h | 23 +- dlls/combat.cpp | 778 +++++------ dlls/controller.cpp | 527 ++++---- dlls/crossbow.cpp | 220 ++- dlls/crowbar.cpp | 152 +-- dlls/defaultai.cpp | 896 ++++++------- dlls/doors.cpp | 853 ++++++------ dlls/doors.h | 7 +- dlls/effects.cpp | 1040 +++++++------- dlls/effects.h | 234 +++- dlls/egon.cpp | 192 ++- dlls/enginecallback.h | 8 +- dlls/explode.cpp | 92 +- dlls/explode.h | 7 +- dlls/exportdef.h | 10 +- dlls/flyingmonster.cpp | 102 +- dlls/flyingmonster.h | 4 +- dlls/func_break.cpp | 475 +++---- dlls/func_break.h | 54 +- dlls/func_tank.cpp | 433 +++--- dlls/game.cpp | 639 +++++---- dlls/game.h | 40 +- dlls/gamerules.cpp | 181 ++- dlls/gamerules.h | 18 +- dlls/gargantua.cpp | 490 ++++--- dlls/gauss.cpp | 237 ++-- dlls/genericmonster.cpp | 56 +- dlls/ggrenade.cpp | 203 +-- dlls/globals.cpp | 2 +- dlls/glock.cpp | 93 +- dlls/gman.cpp | 72 +- dlls/h_ai.cpp | 90 +- dlls/h_battery.cpp | 102 +- dlls/h_cycler.cpp | 205 +-- dlls/h_export.cpp | 23 +- dlls/handgrenade.cpp | 59 +- dlls/hassassin.cpp | 534 ++++---- dlls/headcrab.cpp | 223 ++-- dlls/healthkit.cpp | 134 +- dlls/hgrunt.cpp | 1345 ++++++++++--------- dlls/hornet.cpp | 170 +-- dlls/hornet.h | 29 +- dlls/hornetgun.cpp | 64 +- dlls/houndeye.cpp | 501 ++++--- dlls/ichthyosaur.cpp | 381 +++--- dlls/islave.cpp | 347 +++-- dlls/items.cpp | 126 +- dlls/items.h | 14 +- dlls/lights.cpp | 95 +- dlls/monstermaker.cpp | 84 +- dlls/monsters.cpp | 1315 +++++++++--------- dlls/monsterstate.cpp | 66 +- dlls/mortar.cpp | 142 +- dlls/mpstubb.cpp | 122 +- dlls/multiplay_gamerules.cpp | 487 ++++--- dlls/nihilanth.cpp | 664 ++++----- dlls/nodes.cpp | 2378 +++++++++++++++++---------------- dlls/osprey.cpp | 282 ++-- dlls/pathcorner.cpp | 189 ++- dlls/plane.cpp | 14 +- dlls/plane.h | 15 +- dlls/player.cpp | 2149 +++++++++++++++-------------- dlls/playermonster.cpp | 44 +- dlls/python.cpp | 118 +- dlls/rat.cpp | 36 +- dlls/roach.cpp | 297 ++-- dlls/rpg.cpp | 203 ++- dlls/satchel.cpp | 170 +-- dlls/schedule.cpp | 383 +++--- dlls/scientist.cpp | 789 +++++------ dlls/scripted.cpp | 470 +++---- dlls/shotgun.cpp | 164 +-- dlls/singleplay_gamerules.cpp | 43 +- dlls/skill.cpp | 14 +- dlls/sound.cpp | 1011 +++++++------- dlls/spectator.cpp | 40 +- dlls/spectator.h | 10 +- dlls/squadmonster.cpp | 256 ++-- dlls/squadmonster.h | 58 +- dlls/squeakgrenade.cpp | 261 ++-- dlls/stats.cpp | 74 +- dlls/subs.cpp | 215 ++- dlls/talkmonster.cpp | 749 ++++++----- dlls/teamplay_gamerules.cpp | 166 +-- dlls/teamplay_gamerules.h | 4 +- dlls/tentacle.cpp | 421 +++--- dlls/trains.h | 96 +- dlls/triggers.cpp | 918 ++++++------- dlls/tripmine.cpp | 171 +-- dlls/turret.cpp | 732 +++++----- dlls/util.cpp | 940 +++++++------ dlls/vector.h | 62 +- dlls/world.cpp | 306 ++--- dlls/xen.cpp | 212 +-- dlls/zombie.cpp | 132 +- game_shared/bitvec.h | 105 +- game_shared/voice_gamemgr.cpp | 121 +- game_shared/voice_gamemgr.h | 46 +- pm_shared/pm_debug.h | 7 +- pm_shared/pm_info.h | 3 +- pm_shared/pm_materials.h | 3 +- pm_shared/pm_math.c | 354 +++-- pm_shared/pm_movevars.h | 3 +- pm_shared/pm_shared.c | 1827 ++++++++++++------------- pm_shared/pm_shared.h | 9 +- 125 files changed, 20171 insertions(+), 19881 deletions(-) diff --git a/dlls/activity.h b/dlls/activity.h index b467e5c7..58b2d8cd 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -16,7 +16,6 @@ #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, @@ -97,13 +96,11 @@ typedef enum { ACT_FLINCH_RIGHTLEG } Activity; - -typedef struct { - int type; +typedef struct +{ + int type; char *name; } activity_map_t; extern activity_map_t activity_map[]; - - #endif //ACTIVITY_H diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index 9bf03d5e..b27b8d4d 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -14,13 +14,14 @@ ****/ //========================================================= //========================================================= + #include "extdll.h" #include "util.h" #include "cbase.h" #include "monsters.h" #include "squadmonster.h" -#define AFLOCK_MAX_RECRUIT_RADIUS 1024 +#define AFLOCK_MAX_RECRUIT_RADIUS 1024 #define AFLOCK_FLY_SPEED 125 #define AFLOCK_TURN_RATE 75 #define AFLOCK_ACCELERATE 10 @@ -38,18 +39,18 @@ public: void KeyValue( KeyValueData *pkvd ); void SpawnFlock( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; // Sounds are shared by the flock - static void PrecacheFlockSounds( void ); + static void PrecacheFlockSounds( void ); - int m_cFlockSize; - float m_flFlockRadius; + int m_cFlockSize; + float m_flFlockRadius; }; -TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = +TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = { DEFINE_FIELD( CFlockingFlyerFlock, m_cFlockSize, FIELD_INTEGER ), DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), @@ -81,13 +82,13 @@ public: BOOL FPathBlocked( void ); //void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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 ); + int InSquad( void ) { return m_pSquadLeader != NULL; } + int SquadCount( void ); void SquadRemove( CFlockingFlyer *pRemove ); void SquadUnlink( void ); void SquadAdd( CFlockingFlyer *pAdd ); @@ -95,22 +96,22 @@ public: 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; + 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[] = +TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = { DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ), DEFINE_FIELD( CFlockingFlyer, m_pSquadNext, FIELD_CLASSPTR ), @@ -123,59 +124,59 @@ TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = 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 + //DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save }; IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ) //========================================================= //========================================================= -void CFlockingFlyerFlock :: KeyValue( KeyValueData *pkvd ) +void CFlockingFlyerFlock::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "iFlockSize")) + if( FStrEq( pkvd->szKeyName, "iFlockSize" ) ) { - m_cFlockSize = atoi(pkvd->szValue); + m_cFlockSize = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "flFlockRadius")) + else if( FStrEq( pkvd->szKeyName, "flFlockRadius" ) ) { - m_flFlockRadius = atof(pkvd->szValue); + m_flFlockRadius = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } } //========================================================= //========================================================= -void CFlockingFlyerFlock :: Spawn( ) +void CFlockingFlyerFlock::Spawn() { - Precache( ); + Precache(); SpawnFlock(); - REMOVE_ENTITY(ENT(pev)); // dump the spawn ent + REMOVE_ENTITY( ENT( pev ) ); // dump the spawn ent } //========================================================= //========================================================= -void CFlockingFlyerFlock :: Precache( ) +void CFlockingFlyerFlock::Precache() { - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); + //PRECACHE_MODEL( "models/aflock.mdl" ); + PRECACHE_MODEL( "models/boid.mdl "); PrecacheFlockSounds(); } -void CFlockingFlyerFlock :: PrecacheFlockSounds( void ) +void CFlockingFlyerFlock::PrecacheFlockSounds( void ) { - PRECACHE_SOUND("boid/boid_alert1.wav" ); - PRECACHE_SOUND("boid/boid_alert2.wav" ); + PRECACHE_SOUND( "boid/boid_alert1.wav" ); + PRECACHE_SOUND( "boid/boid_alert2.wav" ); - PRECACHE_SOUND("boid/boid_idle1.wav" ); - PRECACHE_SOUND("boid/boid_idle2.wav" ); + PRECACHE_SOUND( "boid/boid_idle1.wav" ); + PRECACHE_SOUND( "boid/boid_idle2.wav" ); } //========================================================= //========================================================= -void CFlockingFlyerFlock :: SpawnFlock( void ) +void CFlockingFlyerFlock::SpawnFlock( void ) { float R = m_flFlockRadius; int iCount; @@ -184,15 +185,15 @@ void CFlockingFlyerFlock :: SpawnFlock( void ) pLeader = pBoid = NULL; - for ( iCount = 0 ; iCount < m_cFlockSize ; iCount++ ) + for( iCount = 0; iCount < m_cFlockSize; iCount++ ) { pBoid = GetClassPtr( (CFlockingFlyer *)NULL ); - if ( !pLeader ) + if( !pLeader ) { // make this guy the leader. pLeader = pBoid; - + pLeader->m_pSquadLeader = pLeader; pLeader->m_pSquadNext = NULL; } @@ -202,18 +203,18 @@ void CFlockingFlyerFlock :: SpawnFlock( void ) vecSpot.z = RANDOM_FLOAT( 0, 16 ); vecSpot = pev->origin + vecSpot; - UTIL_SetOrigin(pBoid->pev, 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->angles = pev->angles; + pBoid->pev->frame = 0; pBoid->pev->nextthink = gpGlobals->time + 0.2; - pBoid->SetThink( &CFlockingFlyer :: IdleThink ); + pBoid->SetThink( &CFlockingFlyer::IdleThink ); - if ( pBoid != pLeader ) + if( pBoid != pLeader ) { pLeader->SquadAdd( pBoid ); } @@ -222,11 +223,11 @@ void CFlockingFlyerFlock :: SpawnFlock( void ) //========================================================= //========================================================= -void CFlockingFlyer :: Spawn( ) +void CFlockingFlyer::Spawn() { - Precache( ); + Precache(); SpawnCommonCode(); - + pev->frame = 0; pev->nextthink = gpGlobals->time + 0.1; SetThink( &CFlockingFlyer::IdleThink ); @@ -234,52 +235,60 @@ void CFlockingFlyer :: Spawn( ) //========================================================= //========================================================= -void CFlockingFlyer :: Precache( ) +void CFlockingFlyer::Precache() { - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); + //PRECACHE_MODEL( "models/aflock.mdl" ); + PRECACHE_MODEL( "models/boid.mdl" ); CFlockingFlyerFlock::PrecacheFlockSounds(); } //========================================================= //========================================================= -void CFlockingFlyer :: MakeSound( void ) +void CFlockingFlyer::MakeSound( void ) { - if ( m_flAlertTime > gpGlobals->time ) + 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; + 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 ) ) + 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; + 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 ) +void CFlockingFlyer::Killed( entvars_t *pevAttacker, int iGib ) { CFlockingFlyer *pSquad; - + pSquad = (CFlockingFlyer *)m_pSquadLeader; - while ( pSquad ) + while( pSquad ) { pSquad->m_flAlertTime = gpGlobals->time + 15; pSquad = (CFlockingFlyer *)pSquad->m_pSquadNext; } - if ( m_pSquadLeader ) + if( m_pSquadLeader ) { m_pSquadLeader->SquadRemove( this ); } @@ -289,18 +298,18 @@ void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) pev->framerate = 0; pev->effects = EF_NOINTERP; - UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); + 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 ) +void CFlockingFlyer::FallHack( void ) { - if ( pev->flags & FL_ONGROUND ) + if( pev->flags & FL_ONGROUND ) { - if ( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) + if( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) { pev->flags &= ~FL_ONGROUND; pev->nextthink = gpGlobals->time + 0.1; @@ -315,56 +324,59 @@ void CFlockingFlyer :: FallHack( void ) //========================================================= //========================================================= -void CFlockingFlyer :: SpawnCommonCode( ) +void CFlockingFlyer::SpawnCommonCode() { - pev->deadflag = DEAD_NO; - pev->classname = MAKE_STRING("monster_flyer"); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; + 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; + 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"); + //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)); + //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 ( ) +void CFlockingFlyer::BoidAdvanceFrame() { - float flapspeed = (pev->speed - pev->armorvalue) / AFLOCK_ACCELERATE; + 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; + 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); + pev->avelocity.x = -( pev->angles.x + flapspeed * 5 ); // bank - pev->avelocity.z = - (pev->angles.z + pev->avelocity.y); + pev->avelocity.z = -( pev->angles.z + pev->avelocity.y ); - // pev->framerate = flapspeed; + // pev->framerate = flapspeed; StudioFrameAdvance( 0.1 ); } //========================================================= //========================================================= -void CFlockingFlyer :: IdleThink( void ) +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() ) ) ) + if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { SetThink( &CFlockingFlyer::Start ); pev->nextthink = gpGlobals->time + 0.1; @@ -374,11 +386,11 @@ void CFlockingFlyer :: IdleThink( void ) //========================================================= // Start - player enters the pvs, so get things going. //========================================================= -void CFlockingFlyer :: Start( void ) +void CFlockingFlyer::Start( void ) { pev->nextthink = gpGlobals->time + 0.1; - if ( IsLeader() ) + if( IsLeader() ) { SetThink( &CFlockingFlyer::FlockLeaderThink ); } @@ -386,24 +398,22 @@ void CFlockingFlyer :: Start( void ) { SetThink( &CFlockingFlyer::FlockFollowerThink ); } - /* - Vector vecTakeOff; - vecTakeOff = Vector ( 0 , 0 , 0 ); + 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); + 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( ); + SetActivity( ACT_FLY ); + ResetSequenceInfo(); + BoidAdvanceFrame(); pev->speed = AFLOCK_FLY_SPEED;// no delay! } @@ -411,9 +421,9 @@ void CFlockingFlyer :: Start( void ) //========================================================= // Leader boid calls this to form a flock from surrounding boids //========================================================= -void CFlockingFlyer :: FormFlock( void ) +void CFlockingFlyer::FormFlock( void ) { - if ( !InSquad() ) + if( !InSquad() ) { // I am my own leader m_pSquadLeader = this; @@ -421,15 +431,15 @@ void CFlockingFlyer :: FormFlock( void ) 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 ) + 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" ) ) + if( FClassnameIs ( pRecruit->pev, "monster_flyer" ) ) { squadCount++; SquadAdd( (CFlockingFlyer *)pRecruit ); @@ -445,18 +455,18 @@ void CFlockingFlyer :: FormFlock( void ) //========================================================= // Searches for boids that are too close and pushes them away //========================================================= -void CFlockingFlyer :: SpreadFlock( ) +void CFlockingFlyer::SpreadFlock() { - Vector vecDir; - float flSpeed;// holds vector magnitude while we fiddle with the direction - + Vector vecDir; + float flSpeed;// holds vector magnitude while we fiddle with the direction + CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) + while( pList ) { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) + if( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) { // push the other away - vecDir = ( pList->pev->origin - pev->origin ); + vecDir = pList->pev->origin - pev->origin; vecDir = vecDir.Normalize(); // store the magnitude of the other boid's velocity, and normalize it so we @@ -476,19 +486,19 @@ void CFlockingFlyer :: SpreadFlock( ) // // This function should **ONLY** be called when Caller's velocity is normalized!! //========================================================= -void CFlockingFlyer :: SpreadFlock2 ( ) +void CFlockingFlyer::SpreadFlock2() { - Vector vecDir; - + Vector vecDir; + CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) + while( pList ) { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) + if( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) { - vecDir = ( pev->origin - pList->pev->origin ); + vecDir = pev->origin - pList->pev->origin; vecDir = vecDir.Normalize(); - pev->velocity = (pev->velocity + vecDir); + pev->velocity = pev->velocity + vecDir; } pList = pList->m_pSquadNext; @@ -498,14 +508,14 @@ void CFlockingFlyer :: SpreadFlock2 ( ) //========================================================= // FBoidPathBlocked - returns TRUE if there is an obstacle ahead //========================================================= -BOOL CFlockingFlyer :: FPathBlocked( ) +BOOL CFlockingFlyer::FPathBlocked() { - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - BOOL fBlocked; + TraceResult tr; + Vector vecDist;// used for general measurements + Vector vecDir;// used for general measurements + BOOL fBlocked; - if ( m_flFakeBlockedTime > gpGlobals->time ) + if( m_flFakeBlockedTime > gpGlobals->time ) { m_flLastBlockedTime = gpGlobals->time; return TRUE; @@ -518,32 +528,32 @@ BOOL CFlockingFlyer :: FPathBlocked( ) 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) + 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) + 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) + 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 ) + 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); + m_flFakeBlockedTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); } return fBlocked; @@ -552,25 +562,24 @@ BOOL CFlockingFlyer :: FPathBlocked( ) //========================================================= // Leader boids use this think every tenth //========================================================= -void CFlockingFlyer :: FlockLeaderThink( void ) +void CFlockingFlyer::FlockLeaderThink( void ) { - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - int cProcessed = 0;// keep track of how many other boids we've processed - float flLeftSide; - float flRightSide; - + TraceResult tr; + Vector vecDist;// used for general measurements + Vector vecDir;// used for general measurements + int cProcessed = 0;// keep track of how many other boids we've processed + float flLeftSide; + float flRightSide; pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors ( pev->angles ); + + UTIL_MakeVectors( pev->angles ); // is the way ahead clear? - if ( !FPathBlocked () ) + if( !FPathBlocked () ) { // if the boid is turning, stop the trend. - if ( m_fTurning ) + if( m_fTurning ) { m_fTurning = FALSE; pev->avelocity.y = 0; @@ -578,12 +587,12 @@ void CFlockingFlyer :: FlockLeaderThink( void ) m_fPathBlocked = FALSE; - if (pev->speed <= AFLOCK_FLY_SPEED ) - pev->speed+= 5; + if( pev->speed <= AFLOCK_FLY_SPEED ) + pev->speed += 5; pev->velocity = gpGlobals->v_forward * pev->speed; - BoidAdvanceFrame( ); + BoidAdvanceFrame(); return; } @@ -591,25 +600,25 @@ void CFlockingFlyer :: FlockLeaderThink( void ) // 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 + 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); + 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); + 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 ) + if( flRightSide > flLeftSide ) { pev->avelocity.y = -AFLOCK_TURN_RATE; m_fTurning = TRUE; } // default to left turn :) - else if ( flLeftSide > flRightSide ) + else if( flLeftSide > flRightSide ) { pev->avelocity.y = AFLOCK_TURN_RATE; m_fTurning = TRUE; @@ -619,7 +628,7 @@ void CFlockingFlyer :: FlockLeaderThink( void ) // equidistant. Pick randomly between left and right. m_fTurning = TRUE; - if ( RANDOM_LONG( 0, 1 ) == 0 ) + if( RANDOM_LONG( 0, 1 ) == 0 ) { pev->avelocity.y = AFLOCK_TURN_RATE; } @@ -629,47 +638,47 @@ void CFlockingFlyer :: FlockLeaderThink( void ) } } } - SpreadFlock( ); + 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 ) + 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) ) + if( FBitSet( pev->flags, FL_ONGROUND ) ) { - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1 ) ); + UTIL_SetOrigin( pev, pev->origin + Vector( 0, 0, 1 ) ); pev->velocity.z = 0; } - if ( m_flFlockNextSoundTime < gpGlobals->time ) + 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 ) +void CFlockingFlyer::FlockFollowerThink( void ) { - TraceResult tr; - Vector vecDist; - Vector vecDir; - Vector vecDirToLeader; - float flDistToLeader; + TraceResult tr; + Vector vecDist; + Vector vecDir; + Vector vecDirToLeader; + float flDistToLeader; pev->nextthink = gpGlobals->time + 0.1; - if ( IsLeader() || !InSquad() ) + if( IsLeader() || !InSquad() ) { // the leader has been killed and this flyer suddenly finds himself the leader. SetThink( &CFlockingFlyer::FlockLeaderThink ); @@ -685,16 +694,16 @@ void CFlockingFlyer :: FlockFollowerThink( void ) // // We can see the leader, so try to catch up to it // - if ( FInViewCone ( m_pSquadLeader ) ) + if( FInViewCone ( m_pSquadLeader ) ) { // if we're too far away, speed up - if ( flDistToLeader > AFLOCK_TOO_FAR ) + 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 ) + else if( flDistToLeader < AFLOCK_TOO_CLOSE ) { m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; } @@ -711,23 +720,23 @@ void CFlockingFlyer :: FlockFollowerThink( void ) 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 ) + 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 ) + if( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 ) { m_flGoalSpeed = AFLOCK_FLY_SPEED * 2; } - if ( pev->speed < m_flGoalSpeed ) + if( pev->speed < m_flGoalSpeed ) { pev->speed += AFLOCK_ACCELERATE; } - else if ( pev->speed > m_flGoalSpeed ) + else if( pev->speed > m_flGoalSpeed ) { pev->speed -= AFLOCK_ACCELERATE; } @@ -737,13 +746,13 @@ void CFlockingFlyer :: FlockFollowerThink( void ) BoidAdvanceFrame( ); } -/* +/* // Is this boid's course blocked? - if ( FBoidPathBlocked (pev) ) + if( FBoidPathBlocked( pev ) ) { // course is still blocked from last time. Just keep flying along adjusted // velocity - if ( m_fCourseAdjust ) + if( m_fCourseAdjust ) { pev->velocity = m_vecAdjustedVelocity * pev->speed; return; @@ -751,24 +760,24 @@ void CFlockingFlyer :: FlockFollowerThink( void ) 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( vecDir ); - UTIL_MakeVectors ( pev->angles ); + 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); + 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); + 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 ) + if( flRightSide > flLeftSide ) { m_vecAdjustedVelocity = gpGlobals->v_right; } @@ -790,10 +799,10 @@ void CFlockingFlyer :: FlockFollowerThink( void ) // SquadUnlink(), Unlink the squad pointers. // //========================================================= -void CFlockingFlyer :: SquadUnlink( void ) +void CFlockingFlyer::SquadUnlink( void ) { m_pSquadLeader = NULL; - m_pSquadNext = NULL; + m_pSquadNext = NULL; } //========================================================= @@ -801,9 +810,9 @@ void CFlockingFlyer :: SquadUnlink( void ) // SquadAdd(), add pAdd to my squad // //========================================================= -void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) +void CFlockingFlyer::SquadAdd( CFlockingFlyer *pAdd ) { - ASSERT( pAdd!=NULL ); + ASSERT( pAdd != NULL ); ASSERT( !pAdd->InSquad() ); ASSERT( this->IsLeader() ); @@ -818,27 +827,27 @@ void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) // If I am pRemove, promote m_pSquadNext to leader // //========================================================= -void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) +void CFlockingFlyer::SquadRemove( CFlockingFlyer *pRemove ) { - ASSERT( pRemove!=NULL ); + ASSERT( pRemove != NULL ); ASSERT( this->IsLeader() ); ASSERT( pRemove->m_pSquadLeader == this ); - if ( SquadCount() > 2 ) + if( SquadCount() > 2 ) { // Removing the leader, promote m_pSquadNext to leader - if ( pRemove == this ) + if( pRemove == this ) { CFlockingFlyer *pLeader = m_pSquadNext; - + // copy the enemy LKP to the new leader pLeader->m_vecEnemyLKP = m_vecEnemyLKP; - if ( pLeader ) + if( pLeader ) { CFlockingFlyer *pList = pLeader; - while ( pList ) + while( pList ) { pList->m_pSquadLeader = pLeader; pList = pList->m_pSquadNext; @@ -852,7 +861,7 @@ void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) CFlockingFlyer *pList = this; // Find the node before pRemove - while ( pList->m_pSquadNext != pRemove ) + while( pList->m_pSquadNext != pRemove ) { // assert to test valid list construction ASSERT( pList->m_pSquadNext != NULL ); @@ -878,11 +887,11 @@ void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) // callable from leaders & followers // //========================================================= -int CFlockingFlyer :: SquadCount( void ) +int CFlockingFlyer::SquadCount( void ) { CFlockingFlyer *pList = m_pSquadLeader; int squadCount = 0; - while ( pList ) + while( pList ) { squadCount++; pList = pList->m_pSquadNext; @@ -896,12 +905,12 @@ int CFlockingFlyer :: SquadCount( void ) // SquadDisband(), Unlink all squad members // //========================================================= -void CFlockingFlyer :: SquadDisband( void ) +void CFlockingFlyer::SquadDisband( void ) { CFlockingFlyer *pList = m_pSquadLeader; CFlockingFlyer *pNext; - while ( pList ) + while( pList ) { pNext = pList->m_pSquadNext; pList->SquadUnlink(); diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index 2612dc47..97804f68 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -64,8 +64,6 @@ int iAgruntMuzzleFlash; #define AGRUNT_AE_LEFT_PUNCH ( 12 ) #define AGRUNT_AE_RIGHT_PUNCH ( 13 ) - - #define AGRUNT_MELEE_DIST 100 class CAGrunt : public CSquadMonster @@ -73,9 +71,9 @@ class CAGrunt : public CSquadMonster public: void Spawn( void ); void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); + void SetYawSpeed( void ); + int Classify( void ); + int ISoundMask( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); void SetObjectCollisionBox( void ) { @@ -83,26 +81,26 @@ public: 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 ); + 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); + 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 ); + void StopTalking( void ); BOOL ShouldSpeak( void ); CUSTOM_SCHEDULES - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; static const char *pAttackHitSounds[]; static const char *pAttackMissSounds[]; @@ -112,20 +110,20 @@ public: static const char *pIdleSounds[]; static const char *pAlertSounds[]; - BOOL m_fCanHornetAttack; - float m_flNextHornetAttackCheck; + 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; + float m_flNextSpeakTime; + float m_flNextWordTime; + int m_iLastWord; }; LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ) -TYPEDESCRIPTION CAGrunt::m_SaveData[] = +TYPEDESCRIPTION CAGrunt::m_SaveData[] = { DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), @@ -137,14 +135,14 @@ TYPEDESCRIPTION CAGrunt::m_SaveData[] = IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ) -const char *CAGrunt::pAttackHitSounds[] = +const char *CAGrunt::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CAGrunt::pAttackMissSounds[] = +const char *CAGrunt::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", @@ -193,42 +191,39 @@ const char *CAGrunt::pAlertSounds[] = // IRelationship - overridden because Human Grunts are // Alien Grunt's nemesis. //========================================================= -int CAGrunt::IRelationship ( CBaseEntity *pTarget ) +int CAGrunt::IRelationship( CBaseEntity *pTarget ) { - if ( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) + if( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) { return R_NM; } - return CSquadMonster :: IRelationship( pTarget ); + return CSquadMonster::IRelationship( pTarget ); } //========================================================= // ISoundMask //========================================================= -int CAGrunt :: ISoundMask ( void ) +int CAGrunt::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; + 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) +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))) + if( ptr->iHitgroup == 10 && ( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) ) ) { // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + if( pev->dmgtime != gpGlobals->time || ( RANDOM_LONG( 0, 10 ) < 1 ) ) { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2 ) ); pev->dmgtime = gpGlobals->time; } - if ( RANDOM_LONG( 0, 1 ) == 0 ) + if( RANDOM_LONG( 0, 1 ) == 0 ) { Vector vecTracerDir = vecDir; @@ -251,12 +246,12 @@ void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecD } flDamage -= 20; - if (flDamage <= 0) + 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. + SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); } @@ -268,7 +263,7 @@ void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecD //========================================================= void CAGrunt::StopTalking( void ) { - m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); + m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG( 0, 10 ); } //========================================================= @@ -276,15 +271,15 @@ void CAGrunt::StopTalking( void ) //========================================================= BOOL CAGrunt::ShouldSpeak( void ) { - if ( m_flNextSpeakTime > gpGlobals->time ) + if( m_flNextSpeakTime > gpGlobals->time ) { // my time to talk is still in the future. return FALSE; } - if ( pev->spawnflags & SF_MONSTER_GAG ) + if( pev->spawnflags & SF_MONSTER_GAG ) { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) + 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 @@ -301,26 +296,26 @@ BOOL CAGrunt::ShouldSpeak( void ) //========================================================= // PrescheduleThink //========================================================= -void CAGrunt :: PrescheduleThink ( void ) +void CAGrunt::PrescheduleThink( void ) { - if ( ShouldSpeak() ) + if( ShouldSpeak() ) { - if ( m_flNextWordTime < gpGlobals->time ) + if( m_flNextWordTime < gpGlobals->time ) { int num = -1; do { - num = RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, pIdleSounds[num], 1.0, ATTN_NORM ); // is this word our last? - if ( RANDOM_LONG( 1, 10 ) <= 1 ) + if( RANDOM_LONG( 1, 10 ) <= 1 ) { // stop talking. StopTalking(); @@ -336,39 +331,39 @@ void CAGrunt :: PrescheduleThink ( void ) //========================================================= // DieSound //========================================================= -void CAGrunt :: DeathSound ( void ) +void CAGrunt::DeathSound( void ) { StopTalking(); - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, pDieSounds[RANDOM_LONG( 0, ARRAYSIZE( pDieSounds ) - 1 )], 1.0, ATTN_NORM ); } //========================================================= // AlertSound //========================================================= -void CAGrunt :: AlertSound ( void ) +void CAGrunt::AlertSound( void ) { StopTalking(); - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, pAlertSounds[RANDOM_LONG( 0, ARRAYSIZE( pAlertSounds ) - 1 )], 1.0, ATTN_NORM ); } //========================================================= // AttackSound //========================================================= -void CAGrunt :: AttackSound ( void ) +void CAGrunt::AttackSound( void ) { StopTalking(); - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAttackSounds[RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM ); } //========================================================= // PainSound //========================================================= -void CAGrunt :: PainSound ( void ) +void CAGrunt::PainSound( void ) { - if ( m_flNextPainTime > gpGlobals->time ) + if( m_flNextPainTime > gpGlobals->time ) { return; } @@ -377,33 +372,35 @@ void CAGrunt :: PainSound ( void ) StopTalking(); - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM ); + 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 +// Classify - indicates this monster's place in the // relationship table. //========================================================= -int CAGrunt :: Classify ( void ) +int CAGrunt::Classify( void ) { - return CLASS_ALIEN_MILITARY; + return CLASS_ALIEN_MILITARY; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CAGrunt :: SetYawSpeed ( void ) +void CAGrunt::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_TURN_LEFT: case ACT_TURN_RIGHT: ys = 110; break; - default: ys = 100; + default: + ys = 100; + break; } pev->yaw_speed = ys; @@ -415,7 +412,7 @@ void CAGrunt :: SetYawSpeed ( void ) // // Returns number of events handled, 0 if none. //========================================================= -void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CAGrunt::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -430,7 +427,7 @@ void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) Vector vecDirToEnemy; Vector angDir; - if (HasConditions( bits_COND_SEE_ENEMY)) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); angDir = UTIL_VecToAngles( vecDirToEnemy ); @@ -446,7 +443,7 @@ void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) pev->effects = EF_MUZZLEFLASH; // make angles +-180 - if (angDir.x > 180) + if( angDir.x > 180 ) { angDir.x = angDir.x - 360; } @@ -468,102 +465,111 @@ void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ) ) + + 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; + 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 ) + if( pHornetMonster ) { pHornetMonster->m_hEnemy = m_hEnemy; } } break; - case AGRUNT_AE_LEFT_FOOT: - switch (RANDOM_LONG(0,1)) + 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; + 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)) + 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; + 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 ) + + 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() ) + 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) ); + 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. + 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) ); + 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 ) + 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() ) + 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) ); + 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. + 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) ); + 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; @@ -573,27 +579,26 @@ void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CAGrunt :: Spawn() +void CAGrunt::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/agrunt.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + 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; + 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); + m_HackedGunPos = Vector( 24, 64, 48 ); + m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG( 0, 10 ); MonsterInit(); } @@ -601,40 +606,40 @@ void CAGrunt :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CAGrunt :: Precache() +void CAGrunt::Precache() { int i; - PRECACHE_MODEL("models/agrunt.mdl"); + PRECACHE_MODEL( "models/agrunt.mdl" ); - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); + 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( pAttackMissSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[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( pDieSounds ); i++ ) + PRECACHE_SOUND( (char *)pDieSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[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( pAttackSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[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 //========================================================= @@ -642,20 +647,20 @@ void CAGrunt :: Precache() //========================================================= // Fail Schedule //========================================================= -Task_t tlAGruntFail[] = +Task_t tlAGruntFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slAGruntFail[] = +Schedule_t slAGruntFail[] = { { tlAGruntFail, - ARRAYSIZE ( tlAGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | + ARRAYSIZE( tlAGruntFail ), + bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1, 0, "AGrunt Fail" @@ -665,20 +670,20 @@ Schedule_t slAGruntFail[] = //========================================================= // Combat Fail Schedule //========================================================= -Task_t tlAGruntCombatFail[] = +Task_t tlAGruntCombatFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slAGruntCombatFail[] = +Schedule_t slAGruntCombatFail[] = { { tlAGruntCombatFail, - ARRAYSIZE ( tlAGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | + ARRAYSIZE( tlAGruntCombatFail ), + bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1, 0, "AGrunt Combat Fail" @@ -690,24 +695,23 @@ Schedule_t slAGruntCombatFail[] = // hiding in cover or the enemy has moved out of sight. // Should we look around in this schedule? //========================================================= -Task_t tlAGruntStandoff[] = +Task_t tlAGruntStandoff[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, }; -Schedule_t slAGruntStandoff[] = +Schedule_t slAGruntStandoff[] = { { tlAGruntStandoff, - ARRAYSIZE ( tlAGruntStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | + 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" } @@ -716,17 +720,17 @@ Schedule_t slAGruntStandoff[] = //========================================================= // Suppress //========================================================= -Task_t tlAGruntSuppressHornet[] = +Task_t tlAGruntSuppressHornet[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, }; Schedule_t slAGruntSuppress[] = { { tlAGruntSuppressHornet, - ARRAYSIZE ( tlAGruntSuppressHornet ), + ARRAYSIZE( tlAGruntSuppressHornet ), 0, 0, "AGrunt Suppress Hornet", @@ -736,70 +740,68 @@ Schedule_t slAGruntSuppress[] = //========================================================= // primary range attacks //========================================================= -Task_t tlAGruntRangeAttack1[] = +Task_t tlAGruntRangeAttack1[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, }; -Schedule_t slAGruntRangeAttack1[] = +Schedule_t slAGruntRangeAttack1[] = { - { + { tlAGruntRangeAttack1, - ARRAYSIZE ( tlAGruntRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | + ARRAYSIZE( tlAGruntRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | bits_COND_HEAVY_DAMAGE, - 0, "AGrunt Range Attack1" }, }; -Task_t tlAGruntHiddenRangeAttack1[] = +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 }, + { 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[] = +Schedule_t slAGruntHiddenRangeAttack[] = { - { + { tlAGruntHiddenRangeAttack1, - ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_HEAVY_DAMAGE | + 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! +// Take cover from enemy! Tries lateral cover before node +// cover! //========================================================= -Task_t tlAGruntTakeCoverFromEnemy[] = +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 }, + { 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[] = +Schedule_t slAGruntTakeCoverFromEnemy[] = { - { + { tlAGruntTakeCoverFromEnemy, - ARRAYSIZE ( tlAGruntTakeCoverFromEnemy ), + ARRAYSIZE( tlAGruntTakeCoverFromEnemy ), bits_COND_NEW_ENEMY, 0, "AGruntTakeCoverFromEnemy" @@ -809,36 +811,36 @@ Schedule_t slAGruntTakeCoverFromEnemy[] = //========================================================= // Victory dance! //========================================================= -Task_t tlAGruntVictoryDance[] = +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 }, + { 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[] = +Schedule_t slAGruntVictoryDance[] = { - { + { tlAGruntVictoryDance, - ARRAYSIZE ( tlAGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlAGruntVictoryDance ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "AGruntVictoryDance" @@ -847,24 +849,23 @@ Schedule_t slAGruntVictoryDance[] = //========================================================= //========================================================= -Task_t tlAGruntThreatDisplay[] = +Task_t tlAGruntThreatDisplay[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, }; -Schedule_t slAGruntThreatDisplay[] = +Schedule_t slAGruntThreatDisplay[] = { - { + { tlAGruntThreatDisplay, - ARRAYSIZE ( tlAGruntThreatDisplay ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlAGruntThreatDisplay ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, - - bits_SOUND_PLAYER | - bits_SOUND_COMBAT | + bits_SOUND_PLAYER | + bits_SOUND_COMBAT | bits_SOUND_WORLD, "AGruntThreatDisplay" }, @@ -890,9 +891,9 @@ IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ) // because they can use their smart weapons against unseen // enemies. Base class doesn't attack anyone it can't see. //========================================================= -BOOL CAGrunt :: FCanCheckAttacks ( void ) +BOOL CAGrunt::FCanCheckAttacks( void ) { - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + if( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) { return TRUE; } @@ -906,9 +907,9 @@ BOOL CAGrunt :: FCanCheckAttacks ( void ) // CheckMeleeAttack1 - alien grunts zap the crap out of // any enemy that gets too close. //========================================================= -BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) +BOOL CAGrunt::CheckMeleeAttack1( float flDot, float flDist ) { - if ( HasConditions ( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) + if( HasConditions( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) { return TRUE; } @@ -922,33 +923,33 @@ BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) // 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 ) +BOOL CAGrunt::CheckRangeAttack1( float flDot, float flDist ) { - if ( gpGlobals->time < m_flNextHornetAttackCheck ) + if( gpGlobals->time < m_flNextHornetAttackCheck ) { return m_fCanHornetAttack; } - if ( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) + if( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) { - TraceResult tr; + 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); + //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() ) + 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; @@ -957,100 +958,97 @@ BOOL CAGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) //========================================================= // StartTask //========================================================= -void CAGrunt :: StartTask ( Task_t *pTask ) +void CAGrunt::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + 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 ) ) + if( BuildRoute( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else { - ALERT ( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); + 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 ) + if( pEnemyMonsterPtr ) { - Vector vecCenter; - TraceResult tr; - BOOL fSkip; + 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 ) + 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 ); + MakeIdealYaw( pev->origin + gpGlobals->v_right * 128 ); fSkip = TRUE; TaskComplete(); } - - if ( !fSkip ) + + if( !fSkip ) { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) + 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 ); + MakeIdealYaw( pev->origin - gpGlobals->v_right * 128 ); fSkip = TRUE; TaskComplete(); } } - - if ( !fSkip ) + + if( !fSkip ) { - UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) + 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 ); + MakeIdealYaw( pev->origin + gpGlobals->v_right * 256 ); fSkip = TRUE; TaskComplete(); } } - - if ( !fSkip ) + + if( !fSkip ) { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) + 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 ); + MakeIdealYaw( pev->origin - gpGlobals->v_right * 256 ); fSkip = TRUE; TaskComplete(); } } - - if ( !fSkip ) + + if( !fSkip ) { TaskFail(); } } else { - ALERT ( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); + ALERT( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); TaskFail(); } break; - default: - CSquadMonster :: StartTask ( pTask ); + CSquadMonster::StartTask( pTask ); break; } } @@ -1061,128 +1059,120 @@ void CAGrunt :: StartTask ( Task_t *pTask ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CAGrunt :: GetSchedule ( void ) +Schedule_t *CAGrunt::GetSchedule( void ) { - if ( HasConditions(bits_COND_HEAR_SOUND) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) { // dangerous sound nearby! return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } } - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: { // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } - if ( HasConditions(bits_COND_NEW_ENEMY) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { return GetScheduleOfType( SCHED_WAKE_ANGRY ); } // zap player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { AttackSound();// this is a total hack. Should be parto f the schedule - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + 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 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) + if( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) { - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); + return GetScheduleOfType( SCHED_CHASE_ENEMY ); } - return GetScheduleOfType ( SCHED_STANDOFF ); + return GetScheduleOfType( SCHED_STANDOFF ); } break; default: break; } - return CSquadMonster :: GetSchedule(); + return CSquadMonster::GetSchedule(); } //========================================================= //========================================================= -Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) +Schedule_t *CAGrunt::GetScheduleOfType( int Type ) { switch( Type ) { case SCHED_TAKE_COVER_FROM_ENEMY: - return &slAGruntTakeCoverFromEnemy[ 0 ]; + return &slAGruntTakeCoverFromEnemy[0]; break; - case SCHED_RANGE_ATTACK1: - if ( HasConditions( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { //normal attack - return &slAGruntRangeAttack1[ 0 ]; + return &slAGruntRangeAttack1[0]; } else { // attack an unseen enemy - // return &slAGruntHiddenRangeAttack[ 0 ]; - return &slAGruntRangeAttack1[ 0 ]; + // return &slAGruntHiddenRangeAttack[0]; + return &slAGruntRangeAttack1[0]; } break; - case SCHED_AGRUNT_THREAT_DISPLAY: - return &slAGruntThreatDisplay[ 0 ]; + return &slAGruntThreatDisplay[0]; break; - case SCHED_AGRUNT_SUPPRESS: - return &slAGruntSuppress[ 0 ]; + return &slAGruntSuppress[0]; break; - case SCHED_STANDOFF: - return &slAGruntStandoff[ 0 ]; + return &slAGruntStandoff[0]; break; - case SCHED_VICTORY_DANCE: - return &slAGruntVictoryDance[ 0 ]; + return &slAGruntVictoryDance[0]; break; - case SCHED_FAIL: // no fail schedule specified, so pick a good generic one. { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { // 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 &slAGruntCombatFail[0]; } - return &slAGruntFail[ 0 ]; + return &slAGruntFail[0]; } break; - } - return CSquadMonster :: GetScheduleOfType( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } - diff --git a/dlls/airtank.cpp b/dlls/airtank.cpp index ddfe51e9..5858e353 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -26,54 +26,54 @@ class CAirtank : public CGrenade void Precache( void ); void EXPORT TankThink( void ); void EXPORT TankTouch( CBaseEntity *pOther ); - int BloodColor( void ) { return DONT_BLEED; }; + int BloodColor( void ) { return DONT_BLEED; }; void Killed( entvars_t *pevAttacker, int iGib ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_state; + int m_state; }; LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ) -TYPEDESCRIPTION CAirtank::m_SaveData[] = +TYPEDESCRIPTION CAirtank::m_SaveData[] = { DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ), }; IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ) -void CAirtank :: Spawn( void ) +void CAirtank::Spawn( void ) { - Precache( ); + 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)); + 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; + 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"); + PRECACHE_MODEL( "models/w_oxygen.mdl" ); + PRECACHE_SOUND( "doors/aliendoor3.wav" ); } -void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) +void CAirtank::Killed( entvars_t *pevAttacker, int iGib ) { pev->owner = ENT( pevAttacker ); @@ -91,21 +91,21 @@ void CAirtank::TankThink( void ) void CAirtank::TankTouch( CBaseEntity *pOther ) { - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) return; - if (!m_state) + if( !m_state ) { // "no oxygen" sound - EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 1.0, ATTN_NORM ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "doors/aliendoor3.wav", 1.0, ATTN_NORM ); // recharge airtank in 30 seconds pev->nextthink = gpGlobals->time + 30; diff --git a/dlls/animating.cpp b/dlls/animating.cpp index fdfd93f8..95e8b86b 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -26,7 +26,7 @@ #include "animation.h" #include "saverestore.h" -TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = +TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = { DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ), DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ), @@ -41,29 +41,29 @@ 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 ) +float CBaseAnimating::StudioFrameAdvance( float flInterval ) { - if (flInterval == 0.0) + if( flInterval == 0.0 ) { - flInterval = (gpGlobals->time - pev->animtime); - if (flInterval <= 0.001) + flInterval = gpGlobals->time - pev->animtime; + if( flInterval <= 0.001 ) { pev->animtime = gpGlobals->time; return 0.0; } } - if (! pev->animtime) + 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( pev->frame < 0.0 || pev->frame >= 256.0 ) { - if (m_fSequenceLoops) - pev->frame -= (int)(pev->frame / 256.0) * 256.0; + if( m_fSequenceLoops ) + pev->frame -= (int)( pev->frame / 256.0 ) * 256.0; else - pev->frame = (pev->frame < 0.0) ? 0 : 255; + pev->frame = ( pev->frame < 0.0 ) ? 0 : 255; m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents } @@ -73,10 +73,10 @@ float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) //========================================================= // LookupActivity //========================================================= -int CBaseAnimating :: LookupActivity ( int activity ) +int CBaseAnimating::LookupActivity( int activity ) { ASSERT( activity != 0 ); - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return ::LookupActivity( pmodel, pev, activity ); } @@ -87,30 +87,30 @@ int CBaseAnimating :: LookupActivity ( int activity ) // Get activity with highest 'weight' // //========================================================= -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) +int CBaseAnimating::LookupActivityHeaviest( int activity ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return ::LookupActivityHeaviest( pmodel, pev, activity ); } //========================================================= //========================================================= -int CBaseAnimating :: LookupSequence ( const char *label ) +int CBaseAnimating::LookupSequence( const char *label ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return ::LookupSequence( pmodel, label ); } //========================================================= //========================================================= -void CBaseAnimating :: ResetSequenceInfo ( ) +void CBaseAnimating::ResetSequenceInfo() { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); - m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0); + m_fSequenceLoops = ( ( GetSequenceFlags() & STUDIO_LOOPING ) != 0 ); pev->animtime = gpGlobals->time; pev->framerate = 1.0; m_fSequenceFinished = FALSE; @@ -119,9 +119,9 @@ void CBaseAnimating :: ResetSequenceInfo ( ) //========================================================= //========================================================= -BOOL CBaseAnimating :: GetSequenceFlags( ) +BOOL CBaseAnimating::GetSequenceFlags() { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return ::GetSequenceFlags( pmodel, pev ); } @@ -129,13 +129,13 @@ BOOL CBaseAnimating :: GetSequenceFlags( ) //========================================================= // DispatchAnimEvents //========================================================= -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) +void CBaseAnimating::DispatchAnimEvents( float flInterval ) { MonsterEvent_t event; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); - if ( !pmodel ) + if( !pmodel ) { ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); return; @@ -145,17 +145,17 @@ void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) flInterval = 0.1; // FIX: this still sometimes hits events twice - float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate; + 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) + if( flEnd >= 256 || flEnd <= 0.0 ) m_fSequenceFinished = TRUE; int index = 0; - while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) + while( ( index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) { HandleAnimEvent( &event ); } @@ -163,18 +163,18 @@ void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) //========================================================= //========================================================= -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) +float CBaseAnimating::SetBoneController( int iController, float flValue ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return SetController( pmodel, pev, iController, flValue ); } //========================================================= //========================================================= -void CBaseAnimating :: InitBoneControllers ( void ) +void CBaseAnimating::InitBoneControllers( void ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); SetController( pmodel, pev, 0, 0.0 ); SetController( pmodel, pev, 1, 0.0 ); @@ -184,38 +184,38 @@ void CBaseAnimating :: InitBoneControllers ( void ) //========================================================= //========================================================= -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) +float CBaseAnimating::SetBlending( int iBlender, float flValue ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); return ::SetBlending( pmodel, pev, iBlender, flValue ); } //========================================================= //========================================================= -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) +void CBaseAnimating::GetBonePosition( int iBone, Vector &origin, Vector &angles ) { - GET_BONE_POSITION( ENT(pev), iBone, origin, angles ); + GET_BONE_POSITION( ENT( pev ), iBone, origin, angles ); } //========================================================= //========================================================= -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) +void CBaseAnimating::GetAttachment( int iAttachment, Vector &origin, Vector &angles ) { - GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles ); + GET_ATTACHMENT( ENT( pev ), iAttachment, origin, angles ); } //========================================================= //========================================================= -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) +int CBaseAnimating::FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if (piDir == NULL) + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); + + if( piDir == NULL ) { int iDir; int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); - if (iDir != 1) + if( iDir != 1 ) return -1; else return sequence; @@ -226,80 +226,80 @@ int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, in //========================================================= //========================================================= -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) +void CBaseAnimating::GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) +void CBaseAnimating::SetBodygroup( int iGroup, int iValue ) { - ::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue ); + ::SetBodygroup( GET_MODEL_PTR( ENT( pev ) ), pev, iGroup, iValue ); } -int CBaseAnimating :: GetBodygroup( int iGroup ) +int CBaseAnimating::GetBodygroup( int iGroup ) { - return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup ); + return ::GetBodygroup( GET_MODEL_PTR( ENT( pev ) ), pev, iGroup ); } -int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs ) +int CBaseAnimating::ExtractBbox( int sequence, float *mins, float *maxs ) { - return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); + return ::ExtractBbox( GET_MODEL_PTR( ENT( pev ) ), sequence, mins, maxs ); } //========================================================= //========================================================= -void CBaseAnimating :: SetSequenceBox( void ) +void CBaseAnimating::SetSequenceBox( void ) { Vector mins, maxs; // Get sequence bbox - if ( ExtractBbox( pev->sequence, mins, maxs ) ) + if( ExtractBbox( pev->sequence, mins, maxs ) ) { // expand box for rotation // find min / max for rotations - float yaw = pev->angles.y * (M_PI / 180.0); - + 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); + 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++ ) + for( int i = 0; i <= 1; i++ ) { base.x = bounds[i].x; - for ( int j = 0; j <= 1; j++ ) + for( int j = 0; j <= 1; j++ ) { base.y = bounds[j].y; - for ( int k = 0; k <= 1; k++ ) + 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; + + // 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) + + if( transformed.x < rmin.x ) rmin.x = transformed.x; - if (transformed.x > rmax.x) + if( transformed.x > rmax.x ) rmax.x = transformed.x; - if (transformed.y < rmin.y) + if( transformed.y < rmin.y ) rmin.y = transformed.y; - if (transformed.y > rmax.y) + if( transformed.y > rmax.y ) rmax.y = transformed.y; - if (transformed.z < rmin.z) + if( transformed.z < rmin.z ) rmin.z = transformed.z; - if (transformed.z > rmax.z) + if( transformed.z > rmax.z ) rmax.z = transformed.z; } } @@ -309,4 +309,3 @@ void CBaseAnimating :: SetSequenceBox( void ) UTIL_SetSize( pev, rmin, rmax ); } } - diff --git a/dlls/animation.cpp b/dlls/animation.cpp index c59edc90..86cb78ae 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -12,12 +12,13 @@ * without written permission from Valve LLC. * ****/ + #include #include #include typedef int BOOL; -#define TRUE 1 +#define TRUE 1 #define FALSE 0 // hack into header files that we can ship @@ -56,22 +57,22 @@ extern globalvars_t *gpGlobals; int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return 0; - mstudioseqdesc_t *pseqdesc; + 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]; + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ); - maxs[0] = pseqdesc[ sequence ].bbmax[0]; - maxs[1] = pseqdesc[ sequence ].bbmax[1]; - maxs[2] = pseqdesc[ sequence ].bbmax[2]; + 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; } @@ -79,23 +80,23 @@ int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) int LookupActivity( void *pmodel, entvars_t *pev, int activity ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return 0; - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ); int weighttotal = 0; int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) + for( int i = 0; i < pstudiohdr->numseq; i++ ) { - if (pseqdesc[i].activity == activity) + if( pseqdesc[i].activity == activity ) { weighttotal += pseqdesc[i].actweight; - if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight) + if( !weighttotal || RANDOM_LONG( 0, weighttotal - 1 ) < pseqdesc[i].actweight ) seq = i; } } @@ -106,22 +107,22 @@ int LookupActivity( void *pmodel, entvars_t *pev, int activity ) int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr ) + if( !pstudiohdr ) return 0; - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ); int weight = 0; int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) + for( int i = 0; i < pstudiohdr->numseq; i++ ) { - if (pseqdesc[i].activity == activity) + if( pseqdesc[i].activity == activity ) { - if ( pseqdesc[i].actweight > weight ) + if( pseqdesc[i].actweight > weight ) { weight = pseqdesc[i].actweight; seq = i; @@ -132,36 +133,36 @@ int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) return seq; } -void GetEyePosition ( void *pmodel, float *vecEyePosition ) +void GetEyePosition( void *pmodel, float *vecEyePosition ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr ) + if( !pstudiohdr ) { - ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); + ALERT( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); return; } - VectorCopy ( pstudiohdr->eyeposition, vecEyePosition ); + VectorCopy( pstudiohdr->eyeposition, vecEyePosition ); } int LookupSequence( void *pmodel, const char *label ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return 0; - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ); - for (int i = 0; i < pstudiohdr->numseq; i++) + for( int i = 0; i < pstudiohdr->numseq; i++ ) { - if (stricmp( pseqdesc[i].label, label ) == 0) + if( stricmp( pseqdesc[i].label, label ) == 0 ) return i; } @@ -170,7 +171,7 @@ int LookupSequence( void *pmodel, const char *label ) int IsSoundEvent( int eventNumber ) { - if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) + if( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) return 1; return 0; } @@ -178,36 +179,36 @@ int IsSoundEvent( int eventNumber ) void SequencePrecache( void *pmodel, const char *pSequenceName ) { int index = LookupSequence( pmodel, pSequenceName ); - if ( index >= 0 ) + if( index >= 0 ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || index >= pstudiohdr->numseq ) + if( !pstudiohdr || index >= pstudiohdr->numseq ) return; - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + index; + pevent = (mstudioevent_t *)( (byte *)pstudiohdr + pseqdesc->eventindex ); - for (int i = 0; i < pseqdesc->numevents; i++) + for( int i = 0; i < pseqdesc->numevents; i++ ) { // Don't send client-side events to the server AI - if ( pevent[i].event >= EVENT_CLIENT ) + 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( IsSoundEvent( pevent[i].event ) ) { - if ( !strlen(pevent[i].options) ) + 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) ) ); + PRECACHE_SOUND( (char *)( gpGlobals->pStringBase + ALLOC_STRING( pevent[i].options ) ) ); } } } @@ -216,27 +217,27 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return; - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - if (pev->sequence >= pstudiohdr->numseq) + if( pev->sequence >= pstudiohdr->numseq ) { *pflFrameRate = 0.0; *pflGroundSpeed = 0.0; return; } - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence; - if (pseqdesc->numframes > 1) + 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); + *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 { @@ -248,13 +249,13 @@ void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float * int GetSequenceFlags( void *pmodel, entvars_t *pev ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) + if( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) return 0; - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence; return pseqdesc->flags; } @@ -262,25 +263,25 @@ int GetSequenceFlags( void *pmodel, entvars_t *pev ) 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 ) + if( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) return 0; int events = 0; - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence; + pevent = (mstudioevent_t *)( (byte *)pstudiohdr + pseqdesc->eventindex ); - if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) + if( pseqdesc->numevents == 0 || index > pseqdesc->numevents ) return 0; - if (pseqdesc->numframes > 1) + if( pseqdesc->numframes > 1 ) { - flStart *= (pseqdesc->numframes - 1) / 256.0; + flStart *= ( pseqdesc->numframes - 1 ) / 256.0; flEnd *= (pseqdesc->numframes - 1) / 256.0; } else @@ -289,14 +290,14 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve flEnd = 1.0; } - for (; index < pseqdesc->numevents; index++) + for( ; index < pseqdesc->numevents; index++ ) { // Don't send client-side events to the server AI - if ( pevent[index].event >= EVENT_CLIENT ) + 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) ) + 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; @@ -310,119 +311,122 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu { studiohdr_t *pstudiohdr; int i; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return flValue; - mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); + mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)( (byte *)pstudiohdr + pstudiohdr->bonecontrollerindex ); // find first controller that matches the index - for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) + for( i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++ ) { - if (pbonecontroller->index == iController) + if( pbonecontroller->index == iController ) break; } - if (i >= pstudiohdr->numbonecontrollers) + if( i >= pstudiohdr->numbonecontrollers ) return flValue; // wrap 0..360 if it's a rotational controller - - if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + if( pbonecontroller->type & ( STUDIO_XR | STUDIO_YR | STUDIO_ZR ) ) { // ugly hack, invert value if end < start - if (pbonecontroller->end < pbonecontroller->start) + if( pbonecontroller->end < pbonecontroller->start ) flValue = -flValue; // does the controller not wrap? - if (pbonecontroller->start + 359.0 >= pbonecontroller->end) + if( pbonecontroller->start + 359.0 >= pbonecontroller->end ) { - if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) + if( flValue > ( ( pbonecontroller->start + pbonecontroller->end ) / 2.0 ) + 180 ) flValue = flValue - 360; - if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) + 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; + 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 = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); + int setting = 255 * ( flValue - pbonecontroller->start ) / ( pbonecontroller->end - pbonecontroller->start ); - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; + 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; + 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) + if( !pstudiohdr ) return flValue; - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence; - if (pseqdesc->blendtype[iBlender] == 0) + if( pseqdesc->blendtype[iBlender] == 0 ) return flValue; - if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + if( pseqdesc->blendtype[iBlender] & ( STUDIO_XR | STUDIO_YR | STUDIO_ZR ) ) { // ugly hack, invert value if end < start - if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender]) + if( pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender] ) flValue = -flValue; // does the controller not wrap? - if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender]) + if( pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender] ) { - if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180) + 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) + if( flValue < ( ( pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender] ) / 2.0 ) - 180 ) flValue = flValue + 360; } } - int setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]); + int setting = 255 * ( flValue - pseqdesc->blendstart[iBlender] ) / ( pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender] ); - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; + 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]; + 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) + if( !pstudiohdr ) return iGoalAnim; - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); + 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) + if( pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0 ) { return iGoalAnim; } - int iEndNode; + int iEndNode; // ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode ); - if (*piDir > 0) + if( *piDir > 0 ) { iEndNode = pseqdesc[iEndingAnim].exitnode; } @@ -431,32 +435,32 @@ int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) iEndNode = pseqdesc[iEndingAnim].entrynode; } - if (iEndNode == pseqdesc[iGoalAnim].entrynode) + if( iEndNode == pseqdesc[iGoalAnim].entrynode ) { *piDir = 1; return iGoalAnim; } - byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex); + byte *pTransition = ( (byte *)pstudiohdr + pstudiohdr->transitionindex ); - int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)]; + int iInternNode = pTransition[( iEndNode - 1 ) * pstudiohdr->numtransitions + ( pseqdesc[iGoalAnim].entrynode - 1 )]; - if (iInternNode == 0) + if( iInternNode == 0 ) return iGoalAnim; int i; // look for someone going - for (i = 0; i < pstudiohdr->numseq; i++) + for( i = 0; i < pstudiohdr->numseq; i++ ) { - if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode) + if( pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode ) { *piDir = 1; return i; } - if (pseqdesc[i].nodeflags) + if( pseqdesc[i].nodeflags ) { - if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode) + if( pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode ) { *piDir = -1; return i; @@ -471,41 +475,41 @@ int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) { studiohdr_t *pstudiohdr; - + pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) + if( !pstudiohdr ) return; - if (iGroup > pstudiohdr->numbodyparts) + if( iGroup > pstudiohdr->numbodyparts ) return; - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)( (byte *)pstudiohdr + pstudiohdr->bodypartindex ) + iGroup; - if (iValue >= pbodypart->nummodels) + if( iValue >= pbodypart->nummodels ) return; - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; + int iCurrent = ( pev->body / pbodypart->base ) % pbodypart->nummodels; - pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); + 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) + if( !pstudiohdr ) return 0; - if (iGroup > pstudiohdr->numbodyparts) + if( iGroup > pstudiohdr->numbodyparts ) return 0; - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)( (byte *)pstudiohdr + pstudiohdr->bodypartindex ) + iGroup; - if (pbodypart->nummodels <= 1) + if( pbodypart->nummodels <= 1 ) return 0; - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; + int iCurrent = ( pev->body / pbodypart->base ) % pbodypart->nummodels; return iCurrent; } diff --git a/dlls/animation.h b/dlls/animation.h index 174bd712..384c1e98 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -42,6 +42,4 @@ int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); // From /engine/studio.h #define STUDIO_LOOPING 0x0001 - - #endif //ANIMATION_H diff --git a/dlls/apache.cpp b/dlls/apache.cpp index 53998388..b64a8bae 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -29,21 +29,21 @@ extern DLL_GLOBAL int g_iSkillLevel; class CApache : public CBaseMonster { - int Save( CSave &save ); - int Restore( CRestore &restore ); + 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; } + 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); + pev->absmin = pev->origin + Vector( -300, -300, -172 ); + pev->absmax = pev->origin + Vector( 300, 300, 8 ); } void EXPORT HuntThink( void ); @@ -57,9 +57,9 @@ class CApache : public CBaseMonster 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); + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); int m_iRockets; float m_flForce; @@ -91,7 +91,7 @@ class CApache : public CBaseMonster LINK_ENTITY_TO_CLASS( monster_apache, CApache ) -TYPEDESCRIPTION CApache::m_SaveData[] = +TYPEDESCRIPTION CApache::m_SaveData[] = { DEFINE_FIELD( CApache, m_iRockets, FIELD_INTEGER ), DEFINE_FIELD( CApache, m_flForce, FIELD_FLOAT ), @@ -104,10 +104,10 @@ TYPEDESCRIPTION CApache::m_SaveData[] = 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_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 ), @@ -115,30 +115,30 @@ TYPEDESCRIPTION CApache::m_SaveData[] = IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ) -void CApache :: Spawn( void ) +void CApache::Spawn( void ) { - Precache( ); + Precache(); // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; - SET_MODEL(ENT(pev), "models/apache.mdl"); + 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; + pev->takedamage = DAMAGE_AIM; + pev->health = gSkillData.apacheHealth; m_flFieldOfView = -0.707; // 270 degrees pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0, 0xFF); + ResetSequenceInfo(); + pev->frame = RANDOM_LONG( 0, 0xFF ); InitBoneControllers(); - if (pev->spawnflags & SF_WAITFORTRIGGER) + if( pev->spawnflags & SF_WAITFORTRIGGER ) { SetUse( &CApache::StartupUse ); } @@ -154,22 +154,22 @@ void CApache :: Spawn( void ) void CApache::Precache( void ) { - PRECACHE_MODEL("models/apache.mdl"); + 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( "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"); + PRECACHE_SOUND( "weapons/mortarhit.wav" ); m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" ); - PRECACHE_SOUND("turret/tu_fire1.wav"); + PRECACHE_SOUND( "turret/tu_fire1.wav" ); - PRECACHE_MODEL("sprites/lgtning.spr"); + PRECACHE_MODEL( "sprites/lgtning.spr" ); - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); + m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" ); UTIL_PrecacheOther( "hvr_rocket" ); @@ -177,7 +177,7 @@ void CApache::Precache( void ) void CApache::NullThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.5; } @@ -189,21 +189,21 @@ void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP SetUse( NULL ); } -void CApache :: Killed( entvars_t *pevAttacker, int iGib ) +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" ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, "apache/ap_rotor2.wav" ); - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); + 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) + if( pev->spawnflags & SF_NOWRECKAGE ) { m_flNextRocket = gpGlobals->time + 4.0; } @@ -213,42 +213,42 @@ void CApache :: Killed( entvars_t *pevAttacker, int iGib ) } } -void CApache :: DyingThink( void ) +void CApache::DyingThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; pev->avelocity = pev->avelocity * 1.02; // still falling? - if (m_flNextRocket > gpGlobals->time ) + 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_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( 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_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 + WRITE_BYTE( 10 ); // framerate MESSAGE_END(); - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + Vector vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); + WRITE_BYTE( TE_BREAKMODEL ); // position WRITE_COORD( vecSpot.x ); @@ -278,7 +278,6 @@ void CApache :: DyingThink( void ) WRITE_BYTE( 30 );// 3.0 seconds // flags - WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); @@ -289,7 +288,7 @@ void CApache :: DyingThink( void ) } else { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + Vector vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -299,7 +298,7 @@ void CApache :: DyingThink( void ) WRITE_COORD( vecSpot.z + 300 ); WRITE_SHORT( g_sModelIndexFireball ); WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate + WRITE_BYTE( 8 ); // framerate MESSAGE_END(); */ @@ -313,7 +312,7 @@ void CApache :: DyingThink( void ) WRITE_BYTE( 120 ); // scale * 10 WRITE_BYTE( 255 ); // brightness MESSAGE_END(); - + // big smoke MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_SMOKE ); @@ -322,17 +321,17 @@ void CApache :: DyingThink( void ) WRITE_COORD( vecSpot.z + 512 ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 5 ); // framerate + 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.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 @@ -347,14 +346,14 @@ void CApache :: DyingThink( void ) WRITE_BYTE( 0 ); // speed MESSAGE_END(); - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); + 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)) + 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) ); + // 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; @@ -363,14 +362,14 @@ void CApache :: DyingThink( void ) } // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + 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); + WRITE_COORD( vecSpot.z + 64 ); // size WRITE_COORD( 400 ); @@ -378,12 +377,12 @@ void CApache :: DyingThink( void ) WRITE_COORD( 128 ); // velocity - WRITE_COORD( 0 ); + WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 200 ); // randomization - WRITE_BYTE( 30 ); + WRITE_BYTE( 30 ); // Model WRITE_SHORT( m_iBodyGibs ); //model id# @@ -395,7 +394,6 @@ void CApache :: DyingThink( void ) WRITE_BYTE( 200 );// 10.0 seconds // flags - WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); @@ -407,19 +405,19 @@ void CApache :: DyingThink( void ) void CApache::FlyTouch( CBaseEntity *pOther ) { // bounce if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) + if( pOther->pev->solid == SOLID_BSP ) { - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); // UNDONE, do a real bounce - pev->velocity = pev->velocity + tr.vecPlaneNormal * (pev->velocity.Length() + 200); + 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) + if( pOther->pev->solid == SOLID_BSP ) { SetTouch( NULL ); m_flNextRocket = gpGlobals->time; @@ -427,22 +425,22 @@ void CApache::CrashTouch( CBaseEntity *pOther ) } } -void CApache :: GibMonster( void ) +void CApache::GibMonster( void ) { - // EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); + // EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200 ); } -void CApache :: HuntThink( void ) +void CApache::HuntThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - ShowDamage( ); + ShowDamage(); - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target + if( m_pGoalEnt == NULL && !FStringNull( pev->target ) )// this monster has a target { m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); - if (m_pGoalEnt) + if( m_pGoalEnt ) { m_posDesired = m_pGoalEnt->pev->origin; UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); @@ -450,25 +448,25 @@ void CApache :: HuntThink( void ) } } - // if (m_hEnemy == NULL) + // if( m_hEnemy == NULL ) { Look( 4092 ); - m_hEnemy = BestVisibleEnemy( ); + m_hEnemy = BestVisibleEnemy(); } // generic speed up - if (m_flGoalSpeed < 800) + if( m_flGoalSpeed < 800 ) m_flGoalSpeed += 5; - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); - if (FVisible( m_hEnemy )) + if( FVisible( m_hEnemy ) ) { - if (m_flLastSeen < gpGlobals->time - 5) + if( m_flLastSeen < gpGlobals->time - 5 ) m_flPrevSeen = gpGlobals->time; m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->Center( ); + m_posTarget = m_hEnemy->Center(); } else { @@ -476,23 +474,23 @@ void CApache :: HuntThink( void ) } } - m_vecTarget = (m_posTarget - pev->origin).Normalize(); + m_vecTarget = ( m_posTarget - pev->origin ).Normalize(); - float flLength = (pev->origin - m_posDesired).Length(); + float flLength = ( pev->origin - m_posDesired ).Length(); - if (m_pGoalEnt) + if( m_pGoalEnt ) { // ALERT( at_console, "%.0f\n", flLength ); - if (flLength < 128) + if( flLength < 128 ) { m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); - if (m_pGoalEnt) + 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(); + flLength = ( pev->origin - m_posDesired ).Length(); } } } @@ -501,17 +499,17 @@ void CApache :: HuntThink( void ) m_posDesired = pev->origin; } - if (flLength > 250) // 500 + 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) + // 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( ); + m_vecDesired = ( m_posTarget - pev->origin ).Normalize(); } else { - m_vecDesired = (m_posDesired - pev->origin).Normalize( ); + m_vecDesired = ( m_posDesired - pev->origin ).Normalize(); } } else @@ -519,100 +517,100 @@ void CApache :: HuntThink( void ) m_vecDesired = m_vecGoal; } - Flight( ); + 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( ( m_flLastSeen + 1 > gpGlobals->time ) && ( m_flPrevSeen + 2 < gpGlobals->time ) ) { - if (FireGun( )) + if( FireGun() ) { // slow down if we're fireing - if (m_flGoalSpeed > 400) + if( m_flGoalSpeed > 400 ) m_flGoalSpeed = 400; } // don't fire rockets and gun on easy mode - if (g_iSkillLevel == SKILL_EASY) + if( g_iSkillLevel == SKILL_EASY ) m_flNextRocket = gpGlobals->time + 10.0; } UTIL_MakeAimVectors( pev->angles ); - Vector vecEst = (gpGlobals->v_forward * 800 + pev->velocity).Normalize( ); + 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) + if( ( m_iRockets % 2 ) == 1 ) { - FireRocket( ); + FireRocket(); m_flNextRocket = gpGlobals->time + 0.5; - if (m_iRockets <= 0) + 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) + 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_flLastSeen + 60 > gpGlobals->time ) { - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { // make sure it's a good shot - if (DotProduct( m_vecTarget, vecEst) > .965) + 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( ); + 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( ); + if( ( tr.vecEndPos - m_posTarget ).Length() < 512 ) + FireRocket(); } } } } -void CApache :: Flight( void ) +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); + 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( flSide < 0 ) { - if (pev->avelocity.y < 60) + if( pev->avelocity.y < 60 ) { - pev->avelocity.y += 8; // 9 * (3.0/2.0); + pev->avelocity.y += 8; // 9 * ( 3.0 / 2.0 ); } } else { - if (pev->avelocity.y > -60) + if( pev->avelocity.y > -60 ) { - pev->avelocity.y -= 8; // 9 * (3.0/2.0); + 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); + 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); + 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; @@ -622,7 +620,7 @@ void CApache :: Flight( void ) 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) + if( flDir < 0 ) flSpeed = -flSpeed; float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); @@ -631,73 +629,72 @@ void CApache :: Flight( void ) float flSlip = -DotProduct( m_posDesired - vecEst, gpGlobals->v_right ); // fly sideways - if (flSlip > 0) + if( flSlip > 0 ) { - if (pev->angles.z > -30 && pev->avelocity.z > -15) + 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) + 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); + 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) + if( m_flForce < 80 && vecEst.z < m_posDesired.z ) { m_flForce += 12; } - else if (m_flForce > 30) + else if( m_flForce > 30 ) { - if (vecEst.z > m_posDesired.z) + 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) + 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) + 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) + 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) + 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 ); + // 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) + 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 ); + 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 } @@ -707,50 +704,58 @@ void CApache :: Flight( void ) pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) + if( pPlayer ) { + float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, ( pPlayer->pev->origin - pev->origin ).Normalize() ); - float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); + pitch = (int)( 100 + pitch / 50.0 ); - pitch = (int)(100 + pitch / 50.0); - - if (pitch > 250) + if( pitch > 250 ) pitch = 250; - if (pitch < 50) + if( pitch < 50 ) pitch = 50; - if (pitch == 100) + if( pitch == 100 ) pitch = 101; - float flVol = (m_flForce / 100.0) + .1; - if (flVol > 1.0) + 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_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); + // 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 ) +void CApache::FireRocket( void ) { static float side = 1.0; static int count; - if (m_iRockets <= 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); + Vector vecSrc = pev->origin + 1.5 * ( gpGlobals->v_forward * 21 + gpGlobals->v_right * 70 * side + gpGlobals->v_up * -79 ); - switch( m_iRockets % 5) + 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; + 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 ); @@ -764,7 +769,7 @@ void CApache :: FireRocket( void ) MESSAGE_END(); CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); - if (pRocket) + if( pRocket ) pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; m_iRockets--; @@ -772,14 +777,14 @@ void CApache :: FireRocket( void ) side = - side; } -BOOL CApache :: FireGun( ) +BOOL CApache::FireGun() { UTIL_MakeAimVectors( pev->angles ); - + Vector posGun, angGun; GetAttachment( 1, posGun, angGun ); - Vector vecTarget = (m_posTarget - posGun).Normalize( ); + Vector vecTarget = ( m_posTarget - posGun ).Normalize(); Vector vecOut; @@ -787,25 +792,25 @@ BOOL CApache :: FireGun( ) vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); - Vector angles = UTIL_VecToAngles (vecOut); + Vector angles = UTIL_VecToAngles( vecOut ); angles.x = -angles.x; - if (angles.y > 180) + if( angles.y > 180 ) angles.y = angles.y - 360; - if (angles.y < -180) + if( angles.y < -180 ) angles.y = angles.y + 360; - if (angles.x > 180) + if( angles.x > 180 ) angles.x = angles.x - 360; - if (angles.x < -180) + if( angles.x < -180 ) angles.x = angles.x + 360; - if (angles.x > m_angGun.x) + if( angles.x > m_angGun.x ) m_angGun.x = min( angles.x, m_angGun.x + 12 ); - if (angles.x < m_angGun.x) + if( angles.x < m_angGun.x ) m_angGun.x = max( angles.x, m_angGun.x - 12 ); - if (angles.y > m_angGun.y) + if( angles.y > m_angGun.y ) m_angGun.y = min( angles.y, m_angGun.y + 12 ); - if (angles.y < m_angGun.y) + if( angles.y < m_angGun.y ) m_angGun.y = max( angles.y, m_angGun.y - 12 ); m_angGun.y = SetBoneController( 0, m_angGun.y ); @@ -813,28 +818,28 @@ BOOL CApache :: FireGun( ) Vector posBarrel, angBarrel; GetAttachment( 0, posBarrel, angBarrel ); - Vector vecGun = (posBarrel - posGun).Normalize( ); + Vector vecGun = ( posBarrel - posGun ).Normalize(); - if (DotProduct( vecGun, vecTarget ) > 0.98) + 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); + 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) + if( !m_pBeam ) { m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 80 ); - m_pBeam->PointEntInit( pev->origin, entindex( ) ); + m_pBeam->PointEntInit( pev->origin, entindex() ); m_pBeam->SetEndAttachment( 1 ); m_pBeam->SetColor( 255, 180, 96 ); m_pBeam->SetBrightness( 192 ); } - if (flNext < gpGlobals->time) + if( flNext < gpGlobals->time ) { flNext = gpGlobals->time + 0.5; m_pBeam->SetStartPos( tr.vecEndPos ); @@ -844,7 +849,7 @@ BOOL CApache :: FireGun( ) } else { - if (m_pBeam) + if( m_pBeam ) { UTIL_Remove( m_pBeam ); m_pBeam = NULL; @@ -853,9 +858,9 @@ BOOL CApache :: FireGun( ) return FALSE; } -void CApache :: ShowDamage( void ) +void CApache::ShowDamage( void ) { - if (m_iDoSmokePuff > 0 || RANDOM_LONG(0,99) > pev->health) + if( m_iDoSmokePuff > 0 || RANDOM_LONG( 0, 99 ) > pev->health ) { MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_SMOKE ); @@ -863,26 +868,26 @@ void CApache :: ShowDamage( void ) 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( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 WRITE_BYTE( 12 ); // framerate MESSAGE_END(); } - if (m_iDoSmokePuff > 0) + if( m_iDoSmokePuff > 0 ) m_iDoSmokePuff--; } -int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +int CApache::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if (pevInflictor->owner == edict()) + if( pevInflictor->owner == edict() ) return 0; - if (bitsDamageType & DMG_BLAST) + if( bitsDamageType & DMG_BLAST ) { flDamage *= 2; } /* - if ( (bitsDamageType & DMG_BULLET) && flDamage > 50) + if( ( bitsDamageType & DMG_BULLET ) && flDamage > 50 ) { // clip bullet damage at 50 flDamage = 50; @@ -890,23 +895,23 @@ int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa */ // ALERT( at_console, "%.0f\n", flDamage ); - return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int 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))) + 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) + 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); + m_iDoSmokePuff = 3 + ( flDamage / 5.0 ); } else { @@ -923,9 +928,9 @@ class CApacheHVR : public CGrenade void EXPORT IgniteThink( void ); void EXPORT AccelerateThink( void ); - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; int m_iTrail; Vector m_vecForward; @@ -933,23 +938,23 @@ class CApacheHVR : public CGrenade LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ) -TYPEDESCRIPTION CApacheHVR::m_SaveData[] = +TYPEDESCRIPTION CApacheHVR::m_SaveData[] = { -// DEFINE_FIELD( CApacheHVR, m_iTrail, FIELD_INTEGER ), // Dont' save, precache + //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 ) +void CApacheHVR::Spawn( void ) { - Precache( ); + 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)); + 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 ); @@ -964,14 +969,14 @@ void CApacheHVR :: Spawn( void ) pev->dmg = 150; } -void CApacheHVR :: Precache( void ) +void CApacheHVR::Precache( void ) { - PRECACHE_MODEL("models/HVR.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); + PRECACHE_MODEL( "models/HVR.mdl" ); + m_iTrail = PRECACHE_MODEL( "sprites/smoke.spr" ); + PRECACHE_SOUND("weapons/rocket1.wav"); } -void CApacheHVR :: IgniteThink( void ) +void CApacheHVR::IgniteThink( void ) { // pev->movetype = MOVETYPE_TOSS; @@ -979,21 +984,19 @@ void CApacheHVR :: IgniteThink( void ) pev->effects |= EF_LIGHT; // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); + 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_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 @@ -1001,10 +1004,10 @@ void CApacheHVR :: IgniteThink( void ) pev->nextthink = gpGlobals->time + 0.1; } -void CApacheHVR :: AccelerateThink( void ) +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) + 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; @@ -1012,7 +1015,7 @@ void CApacheHVR :: AccelerateThink( void ) // accelerate float flSpeed = pev->velocity.Length(); - if (flSpeed < 1800) + if( flSpeed < 1800 ) { pev->velocity = pev->velocity + m_vecForward * 200; } diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp index 9570dbbe..1e2aa785 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -36,23 +36,23 @@ class CBarnacle : public CBaseMonster public: void Spawn( void ); void Precache( void ); - CBaseEntity *TongueTouchEnt ( float *pflLength ); - int Classify ( void ); + CBaseEntity *TongueTouchEnt( float *pflLength ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - void EXPORT BarnacleThink ( void ); - void EXPORT WaitTillDead ( void ); + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; float m_flAltitude; float m_flCachedLength; // tongue cached length float m_flKillVictimTime; - int m_cGibs; // barnacle loads up on gibs each time it kills something. - BOOL m_fTongueExtended; - BOOL m_fLiftingPrey; + int m_cGibs; // barnacle loads up on gibs each time it kills something. + BOOL m_fTongueExtended; + BOOL m_fLiftingPrey; float m_flTongueAdj; // FIXME: need a custom barnacle model with non-generic hitgroup @@ -68,7 +68,7 @@ public: LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ) -TYPEDESCRIPTION CBarnacle::m_SaveData[] = +TYPEDESCRIPTION CBarnacle::m_SaveData[] = { DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), @@ -85,9 +85,9 @@ IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CBarnacle :: Classify ( void ) +int CBarnacle::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= @@ -96,7 +96,7 @@ int CBarnacle :: Classify ( void ) // // Returns number of events handled, 0 if none. //========================================================= -void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CBarnacle::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -112,40 +112,40 @@ void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CBarnacle :: Spawn() +void CBarnacle::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/barnacle.mdl"); - UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); + 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; + 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_flCachedLength = 32; // mins.z - m_cGibs = 0; - m_fLiftingPrey = FALSE; - m_flTongueAdj = -100; + m_cGibs = 0; + m_fLiftingPrey = FALSE; + m_flTongueAdj = -100; InitBoneControllers(); - SetActivity ( ACT_IDLE ); + SetActivity( ACT_IDLE ); SetThink( &CBarnacle::BarnacleThink ); pev->nextthink = gpGlobals->time + 0.5; - UTIL_SetOrigin ( pev, pev->origin ); + UTIL_SetOrigin( pev, pev->origin ); } int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( bitsDamageType & DMG_CLUB ) + if( bitsDamageType & DMG_CLUB ) { flDamage = pev->health; } @@ -155,26 +155,25 @@ int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, floa //========================================================= //========================================================= -void CBarnacle :: BarnacleThink ( void ) +void CBarnacle::BarnacleThink( void ) { CBaseEntity *pTouchEnt; CBaseMonster *pVictim; float flLength; - #ifdef BARNACLE_FIX_VISIBILITY - if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength )) + if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength ) ) { // recalc collision box here to avoid barnacle disappears bug - m_flCachedLength = (m_flAltitude + m_flTongueAdj); + m_flCachedLength = m_flAltitude + m_flTongueAdj; UTIL_SetOrigin( pev, pev->origin ); } #endif pev->nextthink = gpGlobals->time + 0.1; - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { // barnacle has prey. - if ( !m_hEnemy->IsAlive() ) + if( !m_hEnemy->IsAlive() ) { // someone (maybe even the barnacle) killed the prey. Reset barnacle. m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. @@ -182,9 +181,9 @@ void CBarnacle :: BarnacleThink ( void ) return; } - if ( m_fLiftingPrey ) + if( m_fLiftingPrey ) { - if ( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) + if( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) { // crap, someone killed the prey on the way up. m_hEnemy = NULL; @@ -198,43 +197,43 @@ void CBarnacle :: BarnacleThink ( void ) 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); + 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 ) + 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 ); + 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 ) + if( pVictim ) { pVictim->BarnacleVictimBitten( pev ); - SetActivity ( ACT_EAT ); + SetActivity( ACT_EAT ); } } - UTIL_SetOrigin ( m_hEnemy->pev, vecNewEnemyOrigin ); + 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 ) + if( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) { // kill! - if ( pVictim ) + if( pVictim ) { - pVictim->TakeDamage ( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); + pVictim->TakeDamage( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); m_cGibs = 3; } @@ -242,58 +241,69 @@ void CBarnacle :: BarnacleThink ( void ) } // bite prey every once in a while - if ( pVictim && ( RANDOM_LONG(0,49) == 0 ) ) + if( pVictim && ( RANDOM_LONG( 0, 49 ) == 0 ) ) { - switch ( RANDOM_LONG(0,2) ) + 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; + 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( 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 ) + if( m_fSequenceFinished ) { // this is done so barnacle will fidget. SetActivity ( ACT_IDLE ); m_flTongueAdj = -100; } - if ( m_cGibs && RANDOM_LONG(0,99) == 1 ) + if( m_cGibs && RANDOM_LONG( 0, 99 ) == 1 ) { // cough up a gib. CGib::SpawnRandomGibs( pev, 1, 1 ); m_cGibs--; - switch ( RANDOM_LONG(0,2) ) + 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; + 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 ) + if( pTouchEnt != NULL && m_fTongueExtended ) { // tongue is fully extended, and is touching someone. - if ( pTouchEnt->FBecomeProne() ) + if( pTouchEnt->FBecomeProne() ) { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); - SetSequenceByName ( "attack1" ); + SetSequenceByName( "attack1" ); m_flTongueAdj = -20; m_hEnemy = pTouchEnt; @@ -307,13 +317,13 @@ void CBarnacle :: BarnacleThink ( void ) 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); + 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( m_flAltitude < flLength ) { // if tongue is higher than is should be, lower it kind of slowly. m_flAltitude += BARNACLE_PULL_SPEED; @@ -324,45 +334,47 @@ void CBarnacle :: BarnacleThink ( void ) m_flAltitude = flLength; m_fTongueExtended = TRUE; } - } - } // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); - SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) ); + SetBoneController( 0, -( m_flAltitude + m_flTongueAdj ) ); StudioFrameAdvance( 0.1 ); } //========================================================= // Killed. //========================================================= -void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) +void CBarnacle::Killed( entvars_t *pevAttacker, int iGib ) { CBaseMonster *pVictim; pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { pVictim = m_hEnemy->MyMonsterPointer(); - if ( pVictim ) + if( pVictim ) { pVictim->BarnacleVictimReleased(); } } -// CGib::SpawnRandomGibs( pev, 4, 1 ); + //CGib::SpawnRandomGibs( pev, 4, 1 ); - switch ( RANDOM_LONG ( 0, 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; + 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 ); + SetActivity( ACT_DIESIMPLE ); SetBoneController( 0, 0 ); StudioFrameAdvance( 0.1 ); @@ -373,14 +385,14 @@ void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) //========================================================= //========================================================= -void CBarnacle :: WaitTillDead ( void ) +void CBarnacle::WaitTillDead( void ) { pev->nextthink = gpGlobals->time + 0.1; float flInterval = StudioFrameAdvance( 0.1 ); - DispatchAnimEvents ( flInterval ); + DispatchAnimEvents( flInterval ); - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { // death anim finished. StopAnimation(); @@ -391,17 +403,17 @@ void CBarnacle :: WaitTillDead ( void ) //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CBarnacle :: Precache() +void CBarnacle::Precache() { - PRECACHE_MODEL("models/barnacle.mdl"); + 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" ); + 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" ); } //========================================================= @@ -410,15 +422,15 @@ void CBarnacle :: Precache() // of the trace in the int pointer provided. //========================================================= #define BARNACLE_CHECK_SPACING 8 -CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) +CBaseEntity *CBarnacle::TongueTouchEnt( float *pflLength ) { - TraceResult tr; - float length; + 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 ); + 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 ) + if( pflLength ) { *pflLength = length; } @@ -430,13 +442,13 @@ CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) mins.z -= length; CBaseEntity *pList[10]; - int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) ); - if ( count ) + int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, ( FL_CLIENT | FL_MONSTER ) ); + if( count ) { - for ( int i = 0; i < count; i++ ) + 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. + 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]; } diff --git a/dlls/barney.cpp b/dlls/barney.cpp index 6e4e4198..b1c97090 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -38,7 +38,7 @@ #define BARNEY_BODY_GUNHOLSTERED 0 #define BARNEY_BODY_GUNDRAWN 1 -#define BARNEY_BODY_GUNGONE 2 +#define BARNEY_BODY_GUNGONE 2 class CBarney : public CTalkMonster { @@ -46,51 +46,51 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int ISoundMask( void ); + int ISoundMask( void ); void BarneyFirePistol( void ); void AlertSound( void ); - int Classify ( 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; } + 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 ); - + 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 ); + 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; + 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? + 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[] = +TYPEDESCRIPTION CBarney::m_SaveData[] = { DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ), DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ), @@ -104,20 +104,20 @@ IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ) //========================================================= // AI Schedules Specific to this monster //========================================================= -Task_t tlBaFollow[] = +Task_t tlBaFollow[] = { - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, + { TASK_MOVE_TO_TARGET_RANGE, (float)128 }, // Move within 128 of target ent (client) + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, }; -Schedule_t slBaFollow[] = +Schedule_t slBaFollow[] = { { tlBaFollow, - ARRAYSIZE ( tlBaFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + ARRAYSIZE( tlBaFollow ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | bits_COND_HEAR_SOUND | bits_COND_PROVOKED, bits_SOUND_DANGER, @@ -126,44 +126,44 @@ Schedule_t slBaFollow[] = }; //========================================================= -// BarneyDraw- much better looking draw schedule for when +// BarneyDraw - much better looking draw schedule for when // barney knows who he's gonna attack. //========================================================= -Task_t tlBarneyEnemyDraw[] = +Task_t tlBarneyEnemyDraw[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, 0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, 0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, }; -Schedule_t slBarneyEnemyDraw[] = +Schedule_t slBarneyEnemyDraw[] = { { tlBarneyEnemyDraw, - ARRAYSIZE ( tlBarneyEnemyDraw ), + ARRAYSIZE( tlBarneyEnemyDraw ), 0, 0, "Barney Enemy Draw" } }; -Task_t tlBaFaceTarget[] = +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 }, + { 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[] = +Schedule_t slBaFaceTarget[] = { { tlBaFaceTarget, - ARRAYSIZE ( tlBaFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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, @@ -171,33 +171,31 @@ Schedule_t slBaFaceTarget[] = }, }; -Task_t tlIdleBaStand[] = +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 + { 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[] = +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 | + 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_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" }, @@ -213,17 +211,17 @@ DEFINE_CUSTOM_SCHEDULES( CBarney ) IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ) -void CBarney :: StartTask( Task_t *pTask ) +void CBarney::StartTask( Task_t *pTask ) { CTalkMonster::StartTask( pTask ); } -void CBarney :: RunTask( Task_t *pTask ) +void CBarney::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: - if (m_hEnemy != NULL && (m_hEnemy->IsPlayer())) + if( m_hEnemy != NULL && ( m_hEnemy->IsPlayer() ) ) { pev->framerate = 1.5; } @@ -239,14 +237,14 @@ void CBarney :: RunTask( Task_t *pTask ) // ISoundMask - returns a bit mask indicating which types // of sounds this monster regards. //========================================================= -int CBarney :: ISoundMask ( void) +int CBarney::ISoundMask( void) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_DANGER | + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_CARCASS | + bits_SOUND_MEAT | + bits_SOUND_GARBAGE | + bits_SOUND_DANGER | bits_SOUND_PLAYER; } @@ -254,21 +252,21 @@ int CBarney :: ISoundMask ( void) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CBarney :: Classify ( void ) +int CBarney::Classify( void ) { - return CLASS_PLAYER_ALLY; + return CLASS_PLAYER_ALLY; } //========================================================= // ALertSound - barney says "Freeze!" //========================================================= -void CBarney :: AlertSound( void ) +void CBarney::AlertSound( void ) { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { - if ( FOkToSpeak() ) + if( FOkToSpeak() ) { - PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + PlaySentence( "BA_ATTACK", RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE ); } } } @@ -277,7 +275,7 @@ void CBarney :: AlertSound( void ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CBarney :: SetYawSpeed ( void ) +void CBarney::SetYawSpeed( void ) { int ys; @@ -305,20 +303,20 @@ void CBarney :: SetYawSpeed ( void ) //========================================================= // CheckRangeAttack1 //========================================================= -BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CBarney::CheckRangeAttack1( float flDot, float flDist ) { - if ( flDist <= 1024 && flDot >= 0.5 ) + if( flDist <= 1024 && flDot >= 0.5 ) { - if ( gpGlobals->time > m_checkAttackTime ) + 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 ); + 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) ) + if( tr.flFraction == 1.0 || ( tr.pHit != NULL && CBaseEntity::Instance( tr.pHit ) == pEnemy ) ) m_lastAttackCheck = TRUE; else m_lastAttackCheck = FALSE; @@ -333,11 +331,11 @@ BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) // BarneyFirePistol - shoots one round from the pistol at // the enemy barney is facing. //========================================================= -void CBarney :: BarneyFirePistol ( void ) +void CBarney::BarneyFirePistol( void ) { Vector vecShootOrigin; - UTIL_MakeVectors(pev->angles); + UTIL_MakeVectors( pev->angles ); vecShootOrigin = pev->origin + Vector( 0, 0, 55 ); Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); @@ -345,49 +343,46 @@ void CBarney :: BarneyFirePistol ( void ) SetBlending( 0, angDir.x ); pev->effects = EF_MUZZLEFLASH; - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM ); - + 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 ) + 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 ); + 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 ); + 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 ) +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 ); } @@ -396,25 +391,25 @@ void CBarney :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CBarney :: Spawn() +void CBarney::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/barney.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + 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->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; + pev->body = 0; // gun in holster + m_fGunDrawn = FALSE; - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; + m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; MonsterInit(); SetUse( &CTalkMonster::FollowerUse ); @@ -423,21 +418,21 @@ void CBarney :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CBarney :: Precache() +void CBarney::Precache() { - PRECACHE_MODEL("models/barney.mdl"); + PRECACHE_MODEL( "models/barney.mdl" ); - PRECACHE_SOUND("barney/ba_attack1.wav" ); - PRECACHE_SOUND("barney/ba_attack2.wav" ); + 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_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" ); - 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(); @@ -445,35 +440,34 @@ void CBarney :: Precache() } // Init talk data -void CBarney :: TalkInit() -{ +void CBarney::TalkInit() +{ CTalkMonster::TalkInit(); // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "BA_ANSWER"; + 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_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_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_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_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_SMELL] = "BA_SMELL"; - m_szGrp[TLK_WOUND] = "BA_WOUND"; - m_szGrp[TLK_MORTAL] = "BA_MORTAL"; + 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; @@ -481,7 +475,7 @@ void CBarney :: TalkInit() static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) { - Vector vecDir = (reference - pevTest->origin); + Vector vecDir = reference - pevTest->origin; vecDir.z = 0; vecDir = vecDir.Normalize(); Vector forward, angle; @@ -490,30 +484,30 @@ static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL ); // He's facing me, he meant it - if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so + 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) +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 ) + 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) ) + 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 == NULL ) + if( m_hEnemy == NULL ) { // 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 ) ) + if( ( m_afMemory & bits_MEMORY_SUSPICIOUS ) || IsFacing( pevAttacker, pev->origin ) ) { // Alright, now I'm pissed! PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); @@ -528,7 +522,7 @@ int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa Remember( bits_MEMORY_SUSPICIOUS ); } } - else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) + else if( !( m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) { PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); } @@ -536,55 +530,66 @@ int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return ret; } - + //========================================================= // PainSound //========================================================= -void CBarney :: PainSound ( void ) +void CBarney::PainSound( void ) { - if (gpGlobals->time < m_painTime) + if( gpGlobals->time < m_painTime ) return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - switch (RANDOM_LONG(0,2)) + 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; + 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 ) +void CBarney::DeathSound( void ) { - switch (RANDOM_LONG(0,2)) + 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; + 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) +void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - switch( ptr->iHitgroup) + switch( ptr->iHitgroup ) { case HITGROUP_CHEST: case HITGROUP_STOMACH: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) + if (bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_BLAST ) ) { flDamage = flDamage / 2; } break; case 10: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) + if( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) ) { flDamage -= 20; - if (flDamage <= 0) + if( flDamage <= 0 ) { UTIL_Ricochet( ptr->vecEndPos, 1.0 ); flDamage = 0.01; @@ -601,7 +606,7 @@ void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir void CBarney::Killed( entvars_t *pevAttacker, int iGib ) { - if ( pev->body < BARNEY_BODY_GUNGONE ) + if( pev->body < BARNEY_BODY_GUNGONE ) { // drop the gun! Vector vecGunPos; @@ -610,7 +615,7 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib ) pev->body = BARNEY_BODY_GUNGONE; GetAttachment( 0, vecGunPos, vecGunAngles ); - + CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); } @@ -621,41 +626,37 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib ) //========================================================= // AI Schedules Specific to this monster //========================================================= - -Schedule_t* CBarney :: GetScheduleOfType ( int Type ) +Schedule_t *CBarney::GetScheduleOfType( int Type ) { Schedule_t *psched; switch( Type ) { case SCHED_ARM_WEAPON: - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { // 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); + psched = CTalkMonster::GetScheduleOfType( Type ); - if (psched == slIdleStand) + 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); + psched = CTalkMonster::GetScheduleOfType( Type ); - if (psched == slIdleStand) + if( psched == slIdleStand ) { // just look straight ahead. return slIdleBaStand; @@ -673,18 +674,18 @@ Schedule_t* CBarney :: GetScheduleOfType ( int Type ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CBarney :: GetSchedule ( void ) +Schedule_t *CBarney::GetSchedule( void ) { - if ( HasConditions( bits_COND_HEAR_SOUND ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } - if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) + if( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) { PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM ); } @@ -694,36 +695,35 @@ Schedule_t *CBarney :: GetSchedule ( void ) case MONSTERSTATE_COMBAT: { // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } // always act surprized with a new enemy - if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) ) + 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 ) + if( !m_fGunDrawn ) return GetScheduleOfType( SCHED_ARM_WEAPON ); - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) + 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)) + if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { // flinch if hurt return GetScheduleOfType( SCHED_SMALL_FLINCH ); } - if ( m_hEnemy == NULL && IsFollowing() ) + if( m_hEnemy == NULL && IsFollowing() ) { - if ( !m_hTargetEnt->IsAlive() ) + if( !m_hTargetEnt->IsAlive() ) { // UNDONE: Comment about the recently dead player here? StopFollowing( FALSE ); @@ -731,7 +731,7 @@ Schedule_t *CBarney :: GetSchedule ( void ) } else { - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + if( HasConditions( bits_COND_CLIENT_PUSH ) ) { return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); } @@ -739,7 +739,7 @@ Schedule_t *CBarney :: GetSchedule ( void ) } } - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + if( HasConditions( bits_COND_CLIENT_PUSH ) ) { return GetScheduleOfType( SCHED_MOVE_AWAY ); } @@ -750,11 +750,11 @@ Schedule_t *CBarney :: GetSchedule ( void ) default: break; } - + return CTalkMonster::GetSchedule(); } -MONSTERSTATE CBarney :: GetIdealState ( void ) +MONSTERSTATE CBarney::GetIdealState( void ) { return CTalkMonster::GetIdealState(); } @@ -778,11 +778,11 @@ class CDeadBarney : public CBaseMonster { public: void Spawn( void ); - int Classify ( void ) { return CLASS_PLAYER_ALLY; } + int Classify( void ) { return CLASS_PLAYER_ALLY; } void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display -- temporary, don't need to save + int m_iPose;// which sequence to display -- temporary, don't need to save static char *m_szPoses[3]; }; @@ -790,12 +790,12 @@ char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_s void CDeadBarney::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "pose")) + if( FStrEq( pkvd->szKeyName, "pose" ) ) { - m_iPose = atoi(pkvd->szValue); + m_iPose = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else + else CBaseMonster::KeyValue( pkvd ); } @@ -804,23 +804,23 @@ LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ) //========================================================= // ********** DeadBarney SPAWN ********** //========================================================= -void CDeadBarney :: Spawn( ) +void CDeadBarney::Spawn() { - PRECACHE_MODEL("models/barney.mdl"); - SET_MODEL(ENT(pev), "models/barney.mdl"); + 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->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) + if( pev->sequence == -1 ) { - ALERT ( at_console, "Dead barney with bad pose\n" ); + ALERT( at_console, "Dead barney with bad pose\n" ); } // Corpses have less health - pev->health = 8;//gSkillData.barneyHealth; + pev->health = 8;//gSkillData.barneyHealth; MonsterInitDead(); } diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 7a482490..ad05fccf 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -22,314 +22,310 @@ class CBaseMonster : public CBaseToggle { private: - int m_afConditions; + 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; + 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]; - - // 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; - 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 - 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; + int m_LastHitGroup; // the last body region that took damage - 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 + MONSTERSTATE m_MonsterState;// monster's current state + MONSTERSTATE m_IdealMonsterState;// monster should change to this state - 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_iTaskStatus; + Schedule_t *m_pSchedule; + int m_iScheduleIndex; - int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. - int m_afSoundTypes; + 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_vecLastPosition;// monster sometimes wants to return to where it started after an operation. + 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_iHintNode; // this is the hint node that the monster is moving towards or performing active idle on. + int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. + int m_afSoundTypes; - int m_afMemory; + Vector m_vecLastPosition;// monster sometimes wants to return to where it started after an operation. - int m_iMaxHealth;// keeps track of monster's maximum health value (for re-healing, etc) + int m_iHintNode; // this is the hint node that the monster is moving towards or performing active idle on. - Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) + int m_afMemory; - int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) + int m_iMaxHealth;// keeps track of monster's maximum health value (for re-healing, etc) - int m_afCapability;// tells us what a monster can/can't do. + Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) - float m_flNextAttack; // cannot attack again until this time + int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) - int m_bitsDamageType; // what types of damage has monster (player) taken - BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; + int m_afCapability;// tells us what a monster can/can't do. - 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 + float m_flNextAttack; // cannot attack again until this time - int m_failSchedule; // Schedule type to choose if current schedule fails + int m_bitsDamageType; // what types of damage has monster (player) taken + BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; - float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. + 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 - 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_failSchedule; // Schedule type to choose if current schedule fails - 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. + float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. - Vector m_HackedGunPos; // HACK until we can query end of gun + 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; + SCRIPTSTATE m_scriptState; // internal cinematic state + CCineMonster *m_pCine; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; + 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 ); + 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 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 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 ); + virtual BOOL IsAlive( void ) { return ( pev->deadflag != DEAD_DEAD ); } + virtual BOOL ShouldFadeOnDeath( void ); // Basic Monster AI functions - virtual float ChangeYaw ( int speed ); + virtual float ChangeYaw( int speed ); float VecToYaw( Vector vecDir ); - float FlYawDiff ( void ); + 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 ); + 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 ); + 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 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(); } + 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; } + // 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 ); + // 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 ); + 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 Schedule_t *ScheduleFromName( const char *pName ); + static Schedule_t *m_scheduleList[]; - virtual void SentenceStop( void ); + 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 ); - Task_t *GetTask ( void ); - virtual MONSTERSTATE GetIdealState ( void ); - virtual void SetActivity ( Activity NewActivity ); - void SetSequenceByName ( char *szSequence ); - void SetState ( MONSTERSTATE State ); - virtual void ReportAIState( void ); + virtual void SentenceStop( void ); - void CheckAttacks ( CBaseEntity *pTarget, float flDist ); - virtual int CheckEnemy ( CBaseEntity *pEnemy ); - void PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ); - BOOL PopEnemy( void ); + Task_t *GetTask( void ); + virtual MONSTERSTATE GetIdealState( void ); + virtual void SetActivity( Activity NewActivity ); + void SetSequenceByName( char *szSequence ); + void SetState( MONSTERSTATE State ); + virtual void ReportAIState( 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); } + void CheckAttacks( CBaseEntity *pTarget, float flDist ); + virtual int CheckEnemy( CBaseEntity *pEnemy ); + void PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ); + BOOL PopEnemy( void ); - 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 + 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 ); } - 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; } + 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 ); - virtual BOOL FValidateHintType( short sHint ); - int FindHintNode ( void ); - virtual BOOL FCanActiveIdle ( void ); - void SetTurnActivity ( void ); - float FLSoundVolume ( CSound *pSound ); + 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 - 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 ); + virtual BOOL FCanCheckAttacks( void ); + virtual void CheckAmmo( void ) { return; }; + virtual int IgnoreConditions( void ); - // Returns the time when the door will be open - float OpenDoorAndWait( entvars_t *pevDoor ); + 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 int ISoundMask( void ); - virtual CSound* PBestSound ( void ); - virtual CSound* PBestScent ( void ); - virtual float HearingSensitivity( void ) { return 1.0; }; + virtual BOOL FValidateHintType( short sHint ); + int FindHintNode( void ); + virtual BOOL FCanActiveIdle( void ); + void SetTurnActivity( void ); + float FLSoundVolume( CSound *pSound ); - BOOL FBecomeProne ( void ); - virtual void BarnacleVictimBitten( entvars_t *pevBarnacle ); - virtual void BarnacleVictimReleased( void ); + 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 ); - void SetEyePosition ( void ); + // Returns the time when the door will be open + float OpenDoorAndWait( entvars_t *pevDoor ); - BOOL FShouldEat( void );// see if a monster is 'hungry' - void Eat ( float flFullDuration );// make the monster 'full' for a while. + virtual int ISoundMask( void ); + virtual CSound* PBestSound( void ); + virtual CSound* PBestScent( void ); + virtual float HearingSensitivity( void ) { return 1.0; }; - CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); - BOOL FacingIdeal( void ); + BOOL FBecomeProne( void ); + virtual void BarnacleVictimBitten( entvars_t *pevBarnacle ); + virtual void BarnacleVictimReleased( void ); - BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. - BOOL NoFriendlyFire( void ); + void SetEyePosition( void ); - BOOL BBoxFlat( void ); + BOOL FShouldEat( void );// see if a monster is 'hungry' + void Eat( float flFullDuration );// make the monster 'full' for a while. - // PrescheduleThink - virtual void PrescheduleThink( void ) { return; }; + CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); + BOOL FacingIdeal( void ); - 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); + 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 ); + 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 + 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 BodyTarget( const Vector &posSrc ) { return Center() * 0.75 + EyePosition() * 0.25; }; // position to shoot at - virtual Vector GetGunPosition( void ); + 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 ); + 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 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 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 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( ); + BOOL ExitScriptedSequence(); + BOOL CineCleanup(); CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. }; diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index e9b5a988..59f6cae2 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -17,6 +17,7 @@ //========================================================= // monster template //========================================================= + #include "extdll.h" #include "util.h" #include "cbase.h" @@ -44,16 +45,16 @@ public: // Reach delay in pev->speed // Reach sequence in pev->netname - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_preSequence; + int m_preSequence; }; LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ) -TYPEDESCRIPTION CInfoBM::m_SaveData[] = +TYPEDESCRIPTION CInfoBM::m_SaveData[] = { DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), }; @@ -66,29 +67,29 @@ void CInfoBM::Spawn( void ) void CInfoBM::KeyValue( KeyValueData* pkvd ) { - if (FStrEq(pkvd->szKeyName, "radius")) + if( FStrEq( pkvd->szKeyName, "radius" ) ) { - pev->scale = atof(pkvd->szValue); + pev->scale = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "reachdelay")) + else if( FStrEq( pkvd->szKeyName, "reachdelay" ) ) { - pev->speed = atof(pkvd->szValue); + pev->speed = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "reachtarget")) + else if( FStrEq( pkvd->szKeyName, "reachtarget" ) ) { - pev->message = ALLOC_STRING(pkvd->szValue); + pev->message = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "reachsequence")) + else if( FStrEq( pkvd->szKeyName, "reachsequence" ) ) { - pev->netname = ALLOC_STRING(pkvd->szValue); + pev->netname = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "presequence")) + else if( FStrEq( pkvd->szKeyName, "presequence" ) ) { - m_preSequence = ALLOC_STRING(pkvd->szValue); + m_preSequence = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -107,16 +108,16 @@ public: void Touch( CBaseEntity *pOther ); void EXPORT Animate( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_maxFrame; + int m_maxFrame; }; LINK_ENTITY_TO_CLASS( bmortar, CBMortar ) -TYPEDESCRIPTION CBMortar::m_SaveData[] = +TYPEDESCRIPTION CBMortar::m_SaveData[] = { DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), }; @@ -126,43 +127,43 @@ 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_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 +#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 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) +#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: +// UNDONE: // #define BIG_CHILDCLASS "monster_babycrab" @@ -175,36 +176,35 @@ public: 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 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 ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); void LayHeadcrab( void ); int GetNodeSequence( void ) { CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) + if( pTarget ) { return pTarget->pev->netname; // netname holds node sequence } return 0; } - int GetNodePresequence( void ) { CInfoBM *pTarget = (CInfoBM *)(CBaseEntity *)m_hTargetEnt; - if ( pTarget ) + if( pTarget ) { return pTarget->m_preSequence; } @@ -214,7 +214,7 @@ public: float GetNodeDelay( void ) { CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) + if( pTarget ) { return pTarget->pev->speed; // Speed holds node delay } @@ -224,7 +224,7 @@ public: float GetNodeRange( void ) { CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) + if( pTarget ) { return pTarget->pev->scale; // Scale holds node delay } @@ -234,14 +234,14 @@ public: float GetNodeYaw( void ) { CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) + if( pTarget ) { - if ( pTarget->pev->angles.y != 0 ) + 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 ) { @@ -252,7 +252,7 @@ public: BOOL CanLayCrab( void ) { - if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) + if( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) { // Don't spawn crabs inside each other Vector mins = pev->origin - Vector( 32, 32, 0 ); @@ -260,9 +260,9 @@ public: CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); - for ( int i = 0; i < count; i++ ) + for( int i = 0; i < count; i++ ) { - if ( pList[i] != this ) // Don't hurt yourself! + if( pList[i] != this ) // Don't hurt yourself! return FALSE; } return TRUE; @@ -283,9 +283,9 @@ public: 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; static const char *pChildDieSounds[]; static const char *pSackSounds[]; @@ -300,16 +300,16 @@ public: CUSTOM_SCHEDULES private: - float m_nodeTime; - float m_crabTime; - float m_mortarTime; - float m_painSoundTime; - int m_crabCount; + 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[] = +TYPEDESCRIPTION CBigMomma::m_SaveData[] = { DEFINE_FIELD( CBigMomma, m_nodeTime, FIELD_TIME ), DEFINE_FIELD( CBigMomma, m_crabTime, FIELD_TIME ), @@ -320,21 +320,21 @@ TYPEDESCRIPTION CBigMomma::m_SaveData[] = IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ) -const char *CBigMomma::pChildDieSounds[] = +const char *CBigMomma::pChildDieSounds[] = { "gonarch/gon_childdie1.wav", "gonarch/gon_childdie2.wav", "gonarch/gon_childdie3.wav", }; -const char *CBigMomma::pSackSounds[] = +const char *CBigMomma::pSackSounds[] = { "gonarch/gon_sack1.wav", "gonarch/gon_sack2.wav", "gonarch/gon_sack3.wav", }; -const char *CBigMomma::pDeathSounds[] = +const char *CBigMomma::pDeathSounds[] = { "gonarch/gon_die1.wav", }; @@ -381,12 +381,12 @@ const char *CBigMomma::pFootSounds[] = "gonarch/gon_step3.wav", }; -void CBigMomma :: KeyValue( KeyValueData *pkvd ) +void CBigMomma::KeyValue( KeyValueData *pkvd ) { #if 0 - if (FStrEq(pkvd->szKeyName, "volume")) + if( FStrEq( pkvd->szKeyName, "volume" ) ) { - m_volume = atof(pkvd->szValue); + m_volume = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -398,16 +398,16 @@ void CBigMomma :: KeyValue( KeyValueData *pkvd ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CBigMomma :: Classify ( void ) +int CBigMomma::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CBigMomma :: SetYawSpeed ( void ) +void CBigMomma::SetYawSpeed( void ) { int ys; @@ -428,7 +428,7 @@ void CBigMomma :: SetYawSpeed ( void ) // // Returns number of events handled, 0 if none. //========================================================= -void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CBigMomma::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -445,117 +445,101 @@ void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; - int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); + int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER | FL_CLIENT ); CBaseEntity *pHurt = NULL; - for ( int i = 0; i < count && !pHurt; i++ ) + for( int i = 0; i < count && !pHurt; i++ ) { - if ( pList[i] != this ) + if( pList[i] != this ) { - if ( pList[i]->pev->owner != edict() ) + if( pList[i]->pev->owner != edict() ) pHurt = pList[i]; } } - - if ( pHurt ) + + 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; - + 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; - + 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->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) ); + 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 ) + 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 ); + 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; + 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 ); + 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 ) +void CBigMomma::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if ( ptr->iHitgroup != 1 ) + if( ptr->iHitgroup != 1 ) { // didn't hit the sack? - - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + if( pev->dmgtime != gpGlobals->time || ( RANDOM_LONG( 0, 10 ) < 1 ) ) { UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); pev->dmgtime = gpGlobals->time; @@ -563,24 +547,24 @@ void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated } - else if ( gpGlobals->time > m_painSoundTime ) + else if( gpGlobals->time > m_painSoundTime ) { - m_painSoundTime = gpGlobals->time + RANDOM_LONG(1, 3); + 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 ) +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 ) + if( bitsDamageType & DMG_ACID ) flDamage = 0; - if ( !HasMemory(bits_MEMORY_PATH_FINISHED) ) + if( !HasMemory( bits_MEMORY_PATH_FINISHED ) ) { - if ( pev->health <= flDamage ) + if( pev->health <= flDamage ) { pev->health = flDamage + 1; Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); @@ -591,14 +575,14 @@ int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -void CBigMomma :: LayHeadcrab( void ) +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 ) ) + if( HasMemory( bits_MEMORY_CHILDPAIR ) ) { m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); Forget( bits_MEMORY_CHILDPAIR ); @@ -610,18 +594,18 @@ void CBigMomma :: LayHeadcrab( void ) } TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,100), ignore_monsters, edict(), &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) ); + 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 + if( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then m_crabCount--; - if ( IsAlive() ) + if( IsAlive() ) { // Make the "my baby's dead" noise! EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pChildDieSounds ); @@ -631,33 +615,33 @@ void CBigMomma::DeathNotice( entvars_t *pevChild ) 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) ); + 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 ); + MortarSpray( startPos, Vector( 0, 0, 1 ), gSpitSprite, 24 ); } //========================================================= // Spawn //========================================================= -void CBigMomma :: Spawn() +void CBigMomma::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/big_mom.mdl"); + 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; + 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(); } @@ -665,9 +649,9 @@ void CBigMomma :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CBigMomma :: Precache() +void CBigMomma::Precache() { - PRECACHE_MODEL("models/big_mom.mdl"); + PRECACHE_MODEL( "models/big_mom.mdl" ); PRECACHE_SOUND_ARRAY( pChildDieSounds ); PRECACHE_SOUND_ARRAY( pSackSounds ); @@ -682,9 +666,9 @@ void CBigMomma :: Precache() 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_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" ); @@ -693,7 +677,7 @@ void CBigMomma :: Precache() void CBigMomma::Activate( void ) { - if ( m_hTargetEnt == NULL ) + if( m_hTargetEnt == NULL ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up } @@ -703,16 +687,15 @@ void CBigMomma::NodeStart( int iszNextNode ) CBaseEntity *pTarget = NULL; - if ( pev->netname ) + if( pev->netname ) { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->netname) ); + edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->netname ) ); - if ( !FNullEnt(pentTarget) ) + if( !FNullEnt( pentTarget ) ) pTarget = Instance( pentTarget ); } - - if ( !pTarget ) + if( !pTarget ) { ALERT( at_aiconsole, "BM: Finished the path!!\n" ); Remember( bits_MEMORY_PATH_FINISHED ); @@ -728,30 +711,30 @@ void CBigMomma::NodeReach( void ) Forget( bits_MEMORY_ADVANCE_NODE ); - if ( !pTarget ) + if( !pTarget ) return; - if ( pTarget->pev->health ) + if( pTarget->pev->health ) pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; - if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) + if( !HasMemory( bits_MEMORY_FIRED_NODE ) ) { - if ( pTarget->pev->message ) - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); + 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 ) + 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( flDot >= 0.7 ) { - if ( flDist <= BIG_ATTACKDIST ) + if( flDist <= BIG_ATTACKDIST ) return TRUE; } return FALSE; @@ -763,20 +746,19 @@ 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 ) + if( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) { CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy ) + 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 ) + if( pev->movedir != g_vecZero ) return TRUE; } } @@ -786,7 +768,6 @@ BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) //========================================================= // AI Schedules Specific to this monster //========================================================= - enum { SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, @@ -805,44 +786,44 @@ enum TASK_NODE_YAW // Get the best facing direction for this node }; -Task_t tlBigNode[] = +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 }, + { 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[] = +Schedule_t slBigNode[] = { - { + { tlBigNode, - ARRAYSIZE ( tlBigNode ), + ARRAYSIZE( tlBigNode ), 0, 0, "Big Node" }, }; -Task_t tlNodeFail[] = +Task_t tlNodeFail[] = { - { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, }; -Schedule_t slNodeFail[] = +Schedule_t slNodeFail[] = { - { + { tlNodeFail, - ARRAYSIZE ( tlNodeFail ), + ARRAYSIZE( tlNodeFail ), 0, 0, "NodeFail" @@ -863,11 +844,10 @@ Schedule_t *CBigMomma::GetScheduleOfType( int Type ) { case SCHED_BIG_NODE: return slBigNode; - break; - + break; case SCHED_NODE_FAIL: return slNodeFail; - break; + break; } return CBaseMonster::GetScheduleOfType( Type ); @@ -875,9 +855,9 @@ Schedule_t *CBigMomma::GetScheduleOfType( int Type ) BOOL CBigMomma::ShouldGoToNode( void ) { - if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) + if( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) { - if ( m_nodeTime < gpGlobals->time ) + if( m_nodeTime < gpGlobals->time ) return TRUE; } return FALSE; @@ -885,7 +865,7 @@ BOOL CBigMomma::ShouldGoToNode( void ) Schedule_t *CBigMomma::GetSchedule( void ) { - if ( ShouldGoToNode() ) + if( ShouldGoToNode() ) { return GetScheduleOfType( SCHED_BIG_NODE ); } @@ -895,107 +875,99 @@ Schedule_t *CBigMomma::GetSchedule( void ) void CBigMomma::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_FIND_NODE: { CBaseEntity *pTarget = m_hTargetEnt; - if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) + if( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) { - if ( pTarget ) + if( pTarget ) pev->netname = m_hTargetEnt->pev->target; } NodeStart( pev->netname ); TaskComplete(); - ALERT( at_aiconsole, "BM: Found node %s\n", STRING(pev->netname) ); + 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) ); + 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 ) + 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 ) + ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING( sequence ) ); + if( sequence ) { sequence = LookupSequence( STRING( sequence ) ); - if ( sequence != -1 ) + if( sequence != -1 ) { pev->sequence = sequence; pev->frame = 0; - ResetSequenceInfo( ); - ALERT( at_aiconsole, "BM: Sequence %s\n", STRING(GetNodeSequence()) ); + 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) ); + 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() ); + 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 ) + if( !pTarget ) TaskFail(); else { - if ( (pTarget->pev->origin - pev->origin).Length() < GetNodeRange() ) + if( ( pTarget->pev->origin - pev->origin ).Length() < GetNodeRange() ) TaskComplete(); else { Activity act = ACT_WALK; - if ( pTarget->pev->spawnflags & SF_INFOBM_RUN ) + if( pTarget->pev->spawnflags & SF_INFOBM_RUN ) act = ACT_RUN; m_vecMoveGoal = pTarget->pev->origin; - if ( !MoveToTarget( act, 2 ) ) + if( !MoveToTarget( act, 2 ) ) { TaskFail(); } } } } - ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING(pev->netname) ); - + 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 ); + 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; @@ -1007,20 +979,20 @@ void CBigMomma::StartTask( Task_t *pTask ) //========================================================= void CBigMomma::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_MOVE_TO_NODE_RANGE: { float distance; - if ( m_hTargetEnt == NULL ) + if( m_hTargetEnt == NULL ) 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() ) + if( (distance < GetNodeRange() ) || MovementIsComplete() ) { ALERT( at_aiconsole, "BM: Reached node!\n" ); TaskComplete(); @@ -1030,16 +1002,16 @@ void CBigMomma::RunTask( Task_t *pTask ) } break; case TASK_WAIT_NODE: - if ( m_hTargetEnt != NULL && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) + if( m_hTargetEnt != NULL && ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) ) return; - if ( gpGlobals->time > m_flWaitFinished ) + 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 ) + if( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); @@ -1053,21 +1025,21 @@ void CBigMomma::RunTask( Task_t *pTask ) 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; + 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); + 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) + UTIL_TraceLine( vecSpot1, vecApex, dont_ignore_monsters, ENT( pev ), &tr ); + if( tr.flFraction != 1.0 ) { // fail! return g_vecZero; @@ -1076,13 +1048,13 @@ Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot // 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; + 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 = vecSpot2 - vecSpot1; vecGrenadeVel.z = 0; float distance = vecGrenadeVel.Length(); @@ -1103,12 +1075,12 @@ void MortarSpray( const Vector &position, const Vector &direction, int spriteMod { 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_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 @@ -1117,7 +1089,7 @@ void MortarSpray( const Vector &position, const Vector &direction, int spriteMod } // 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 ) +void CBMortar::Spawn( void ) { pev->movetype = MOVETYPE_TOSS; pev->classname = MAKE_STRING( "bmortar" ); @@ -1126,11 +1098,11 @@ void CBMortar:: Spawn( void ) pev->rendermode = kRenderTransAlpha; pev->renderamt = 255; - SET_MODEL(ENT(pev), "sprites/mommaspit.spr"); + 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) ); + 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; @@ -1140,12 +1112,12 @@ void CBMortar::Animate( void ) { pev->nextthink = gpGlobals->time + 0.1; - if ( gpGlobals->time > pev->dmgtime ) + 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++ ) { if ( pev->frame > m_maxFrame ) { @@ -1172,29 +1144,29 @@ CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity void CBMortar::Touch( CBaseEntity *pOther ) { TraceResult tr; - int iPitch; + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - switch ( RANDOM_LONG( 0, 1 ) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); break; } - if ( pOther->IsBSPModel() ) + 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); + UTIL_DecalTrace( &tr, DECAL_MOMMASPLAT ); } else { @@ -1206,7 +1178,7 @@ void CBMortar::Touch( CBaseEntity *pOther ) MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); entvars_t *pevOwner = NULL; - if ( pev->owner ) + if( pev->owner ) pevOwner = VARS(pev->owner); RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); diff --git a/dlls/bloater.cpp b/dlls/bloater.cpp index e6ffcb2a..537c68ad 100644 --- a/dlls/bloater.cpp +++ b/dlls/bloater.cpp @@ -33,7 +33,7 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); void PainSound( void ); @@ -42,8 +42,8 @@ public: void AttackSnd( void ); // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } + 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 ); }; @@ -53,46 +53,46 @@ LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CBloater :: Classify ( void ) +int CBloater::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CBloater :: SetYawSpeed ( void ) +void CBloater::SetYawSpeed( void ) { int ys; ys = 120; #if 0 - switch ( m_Activity ) + switch( m_Activity ) { } #endif pev->yaw_speed = ys; } -int CBloater :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +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 ) +void CBloater::PainSound( void ) { #if 0 - int pitch = 95 + RANDOM_LONG(0,9); + int pitch = 95 + RANDOM_LONG( 0, 9 ); - switch (RANDOM_LONG(0,5)) + switch( RANDOM_LONG( 0, 5 ) ) { case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain1.wav", 1.0, ATTN_NORM, 0, pitch); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_pain2.wav", 1.0, ATTN_NORM, 0, pitch ); break; default: break; @@ -100,58 +100,58 @@ void CBloater :: PainSound( void ) #endif } -void CBloater :: AlertSound( void ) +void CBloater::AlertSound( void ) { #if 0 - int pitch = 95 + RANDOM_LONG(0,9); + int pitch = 95 + RANDOM_LONG( 0, 9 ); - switch (RANDOM_LONG(0,2)) + 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; + 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); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_alert30.wav", 1.0, ATTN_NORM, 0, pitch ); break; } #endif } -void CBloater :: IdleSound( void ) +void CBloater::IdleSound( void ) { #if 0 - int pitch = 95 + RANDOM_LONG(0,9); + int pitch = 95 + RANDOM_LONG( 0, 9 ); - switch (RANDOM_LONG(0,2)) + switch( RANDOM_LONG( 0, 2 ) ) { case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle1.wav", 1.0, ATTN_NORM, 0, pitch); + 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); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_idle3.wav", 1.0, ATTN_NORM, 0, pitch ); break; } #endif } -void CBloater :: AttackSnd( void ) +void CBloater::AttackSnd( void ) { #if 0 - int pitch = 95 + RANDOM_LONG(0,9); + int pitch = 95 + RANDOM_LONG( 0, 9 ); - switch (RANDOM_LONG(0,1)) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack1.wav", 1.0, ATTN_NORM, 0, pitch); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_attack2.wav", 1.0, ATTN_NORM, 0, pitch ); break; } #endif @@ -161,7 +161,7 @@ void CBloater :: AttackSnd( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CBloater::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -171,7 +171,6 @@ void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) AttackSnd(); } break; - default: CBaseMonster::HandleAnimEvent( pEvent ); break; @@ -181,21 +180,21 @@ void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CBloater :: Spawn() +void CBloater::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/floater.mdl"); + 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; + 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(); } @@ -203,12 +202,11 @@ void CBloater :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CBloater :: Precache() +void CBloater::Precache() { - PRECACHE_MODEL("models/floater.mdl"); + PRECACHE_MODEL( "models/floater.mdl" ); } //========================================================= // AI Schedules Specific to this monster //========================================================= - diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index d6fa32b8..ee676679 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -53,29 +53,29 @@ 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 ); + 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; } + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ) -void CFuncWall :: Spawn( void ) +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) ); - + 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 ) +void CFuncWall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( ShouldToggle( useType, (int)(pev->frame)) ) + if( ShouldToggle( useType, (int)( pev->frame ) ) ) pev->frame = 1 - pev->frame; } @@ -84,106 +84,106 @@ void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u 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 ); + 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 ) +void CFuncWallToggle::Spawn( void ) { CFuncWall::Spawn(); - if ( pev->spawnflags & SF_WALL_START_OFF ) + if( pev->spawnflags & SF_WALL_START_OFF ) TurnOff(); } -void CFuncWallToggle :: TurnOff( void ) +void CFuncWallToggle::TurnOff( void ) { pev->solid = SOLID_NOT; pev->effects |= EF_NODRAW; UTIL_SetOrigin( pev, pev->origin ); } -void CFuncWallToggle :: TurnOn( void ) +void CFuncWallToggle::TurnOn( void ) { pev->solid = SOLID_BSP; pev->effects &= ~EF_NODRAW; UTIL_SetOrigin( pev, pev->origin ); } -BOOL CFuncWallToggle :: IsOn( void ) +BOOL CFuncWallToggle::IsOn( void ) { - if ( pev->solid == SOLID_NOT ) + if( pev->solid == SOLID_NOT ) return FALSE; return TRUE; } -void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncWallToggle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int status = IsOn(); - if ( ShouldToggle( useType, status ) ) + if( ShouldToggle( useType, status ) ) { - if ( status ) + if( status ) TurnOff(); else TurnOn(); } } -#define SF_CONVEYOR_VISUAL 0x0001 +#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 ); + 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 ) +void CFuncConveyor::Spawn( void ) { SetMovedir( pev ); CFuncWall::Spawn(); - if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) ) + 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 ) + 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 ) + 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 ) +void CFuncConveyor::UpdateSpeed( float speed ) { // Encode it as an integer with 4 fractional bits - int speedCode = (int)(fabs(speed) * 16.0); + int speedCode = (int)( fabs( speed ) * 16.0 ); - if ( speed < 0 ) + if( speed < 0 ) pev->rendercolor.x = 1; else pev->rendercolor.x = 0; - pev->rendercolor.y = (speedCode >> 8); - pev->rendercolor.z = (speedCode & 0xFF); + pev->rendercolor.y = speedCode >> 8; + pev->rendercolor.z = speedCode & 0xFF; } -void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncConveyor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { pev->speed = -pev->speed; UpdateSpeed( pev->speed ); @@ -201,29 +201,29 @@ public: void Spawn( void ); void EXPORT SloshTouch( CBaseEntity *pOther ); void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ) -void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) +void CFuncIllusionary::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type + if( FStrEq( pkvd->szKeyName, "skin" ) )//skin is used for content type { - pev->skin = atof(pkvd->szValue); + pev->skin = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else CBaseToggle::KeyValue( pkvd ); } -void CFuncIllusionary :: Spawn( void ) +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) ); - + 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. @@ -244,8 +244,8 @@ void CFuncIllusionary :: Spawn( void ) 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 + 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 ) @@ -253,7 +253,7 @@ LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ) void CFuncMonsterClip::Spawn( void ) { CFuncWall::Spawn(); - if ( CVAR_GET_FLOAT("showtriggers") == 0 ) + if( CVAR_GET_FLOAT( "showtriggers" ) == 0 ) pev->effects = EF_NODRAW; pev->flags |= FL_MONSTERCLIP; } @@ -265,28 +265,28 @@ public: // basic functions void Spawn( void ); void Precache( void ); - void EXPORT SpinUp ( void ); - void EXPORT SpinDown ( void ); + void EXPORT SpinUp( void ); + void EXPORT SpinDown( void ); void KeyValue( KeyValueData* pkvd); - void EXPORT HurtTouch ( CBaseEntity *pOther ); + 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 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[]; + 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; + int m_sounds; }; -TYPEDESCRIPTION CFuncRotating::m_SaveData[] = +TYPEDESCRIPTION CFuncRotating::m_SaveData[] = { DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ), DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ), @@ -299,33 +299,33 @@ IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ) LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ) -void CFuncRotating :: KeyValue( KeyValueData* pkvd) +void CFuncRotating::KeyValue( KeyValueData* pkvd ) { - if (FStrEq(pkvd->szKeyName, "fanfriction")) + if( FStrEq( pkvd->szKeyName, "fanfriction" ) ) { - m_flFanFriction = atof(pkvd->szValue)/100; + m_flFanFriction = atof( pkvd->szValue ) / 100; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "Volume")) + else if( FStrEq( pkvd->szKeyName, "Volume" ) ) { - m_flVolume = atof(pkvd->szValue)/10.0; + m_flVolume = atof( pkvd->szValue ) / 10.0; - if (m_flVolume > 1.0) + if( m_flVolume > 1.0 ) m_flVolume = 1.0; - if (m_flVolume < 0.0) + if( m_flVolume < 0.0 ) m_flVolume = 0.0; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "spawnorigin")) + else if( FStrEq( pkvd->szKeyName, "spawnorigin" ) ) { Vector tmp; UTIL_StringToVector( (float *)tmp, pkvd->szValue ); - if ( tmp != g_vecZero ) + if( tmp != g_vecZero ) pev->origin = tmp; } - else if (FStrEq(pkvd->szKeyName, "sounds")) + else if( FStrEq( pkvd->szKeyName, "sounds" ) ) { - m_sounds = atoi(pkvd->szValue); + m_sounds = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -345,147 +345,144 @@ check either the X_AXIS or Y_AXIS box to change that. REVERSE will cause the it to rotate in the opposite direction. */ -void CFuncRotating :: Spawn( ) +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) + 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) ) + if( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) { m_flAttenuation = ATTN_IDLE; } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) + else if( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS ) ) { m_flAttenuation = ATTN_STATIC; } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) + 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 ) + 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); + + 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 + pev->movedir = Vector( 0, 1, 0 ); // y-axis // check for reverse rotation - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) + 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) ) + if( FBitSet( pev->spawnflags, SF_ROTATING_NOT_SOLID ) ) { pev->solid = SOLID_NOT; pev->skin = CONTENTS_EMPTY; - pev->movetype = MOVETYPE_PUSH; + pev->movetype = MOVETYPE_PUSH; } else { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; } - UTIL_SetOrigin(pev, pev->origin); + 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) + if( pev->speed <= 0 ) pev->speed = 0; // Removed this per level designers request. -- JAY - // if (pev->dmg == 0) + // if( pev->dmg == 0 ) // pev->dmg = 2; // instant-use brush? - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { + if( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT ) ) + { SetThink( &CBaseEntity::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) ) + if( FBitSet( pev->spawnflags, SF_BRUSH_HURT ) ) { SetTouch( &CFuncRotating::HurtTouch ); } - - Precache( ); + + Precache(); } -void CFuncRotating :: Precache( void ) +void CFuncRotating::Precache( void ) { - char* szSoundFile = (char*) STRING(pev->message); + char* szSoundFile = (char*)STRING( pev->message ); // set up fan sounds - - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) + if( !FStringNull( pev->message ) && strlen( szSoundFile ) > 0 ) { // if a path is set for a wave, use it + PRECACHE_SOUND( szSoundFile ); - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); + pev->noiseRunning = ALLOC_STRING( szSoundFile ); } else { // otherwise use preset sound - switch (m_sounds) + switch( m_sounds ) { case 1: - PRECACHE_SOUND ("fans/fan1.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); + 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"); + 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"); + 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"); + 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"); + PRECACHE_SOUND( "fans/fan5.wav" ); + pev->noiseRunning = ALLOC_STRING( "fans/fan5.wav" ); break; - case 0: default: - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) + if( !FStringNull( pev->message ) && strlen( szSoundFile ) > 0 ) { - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); + PRECACHE_SOUND( szSoundFile ); + + pev->noiseRunning = ALLOC_STRING( szSoundFile ); break; - } else + } + else { - pev->noiseRunning = ALLOC_STRING("common/null.wav"); + pev->noiseRunning = ALLOC_STRING( "common/null.wav" ); break; } } } - - if (pev->avelocity != g_vecZero ) + + 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 @@ -498,20 +495,20 @@ void CFuncRotating :: Precache( void ) // // Touch - will hurt others based on how fast the brush is spinning // -void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) +void CFuncRotating::HurtTouch( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + entvars_t *pevOther = pOther->pev; // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) + 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; + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); + + pevOther->velocity = ( pevOther->origin - VecBModelOrigin( pev ) ).Normalize() * pev->dmg; } // @@ -521,9 +518,8 @@ void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) #define FANPITCHMIN 30 #define FANPITCHMAX 100 -void CFuncRotating :: RampPitchVol (int fUp) +void CFuncRotating::RampPitchVol( int fUp ) { - Vector vecAVel = pev->avelocity; vec_t vecCur; vec_t vecFinal; @@ -531,40 +527,37 @@ void CFuncRotating :: RampPitchVol (int fUp) float fvol; float fpitch; int pitch; - + // get current angular velocity + vecCur = fabs( vecAVel.x != 0 ? vecAVel.x : ( vecAVel.y != 0 ? vecAVel.y : vecAVel.z ) ); - vecCur = fabs(vecAVel.x != 0 ? vecAVel.x : (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->movedir.x != 0 ? pev->movedir.x : ( pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z ) ); vecFinal *= pev->speed; - vecFinal = fabs(vecFinal); + vecFinal = fabs( 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 + //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; + 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); + 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 ) +void CFuncRotating::SpinUp( void ) { Vector vecAVel;//rotational velocity @@ -579,24 +572,24 @@ void CFuncRotating :: SpinUp( void ) fabs( vecAVel.z ) >= fabs( 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); - + 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); + RampPitchVol( TRUE ); } } // // SpinDown - decelerates a moving func_rotating to a standstill. // -void CFuncRotating :: SpinDown( void ) +void CFuncRotating::SpinDown( void ) { - Vector vecAVel;//rotational velocity + Vector vecAVel;//rotational velocity vec_t vecdir; pev->nextthink = pev->ltime + 0.1; @@ -605,34 +598,34 @@ void CFuncRotating :: SpinDown( void ) vecAVel = pev->avelocity;// cache entity's rotational velocity - if (pev->movedir.x != 0) + if( pev->movedir.x != 0 ) vecdir = pev->movedir.x; - else if (pev->movedir.y != 0) + 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))) + 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, m_pitch); + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING( pev->noiseRunning /* Stop */ ), + 0, 0, SND_STOP, m_pitch ); SetThink( &CFuncRotating::Rotate ); Rotate(); } else { - RampPitchVol(FALSE); + RampPitchVol( FALSE ); } } -void CFuncRotating :: Rotate( void ) +void CFuncRotating::Rotate( void ) { pev->nextthink = pev->ltime + 10; } @@ -640,46 +633,46 @@ void CFuncRotating :: Rotate( void ) //========================================================= // Rotating Use - when a rotating brush is triggered //========================================================= -void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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 ) ) + if( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) ) { // fan is spinning, so stop it. - if ( pev->avelocity != g_vecZero ) + 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); + //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); + 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. + else if( !FBitSet( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush. { - if ( pev->avelocity != g_vecZero ) + 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); - + // 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); + 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 ); @@ -691,36 +684,36 @@ void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller // // RotatingBlocked - An entity has blocked the brush // -void CFuncRotating :: Blocked( CBaseEntity *pOther ) +void CFuncRotating::Blocked( CBaseEntity *pOther ) { - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); + 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 ); + 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; + 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 ) @@ -739,72 +732,72 @@ TYPEDESCRIPTION CPendulum::m_SaveData[] = IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ) -void CPendulum :: KeyValue( KeyValueData *pkvd ) +void CPendulum::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "distance")) + if( FStrEq( pkvd->szKeyName, "distance" ) ) { - m_distance = atof(pkvd->szValue); + m_distance = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "damp")) + else if( FStrEq( pkvd->szKeyName, "damp" ) ) { - m_damp = atof(pkvd->szValue) * 0.001; + m_damp = atof( pkvd->szValue ) * 0.001; pkvd->fHandled = TRUE; } else CBaseEntity::KeyValue( pkvd ); } -void CPendulum :: Spawn( void ) +void CPendulum::Spawn( void ) { // set the axis of rotation - CBaseToggle :: AxisDir( pev ); + CBaseToggle::AxisDir( pev ); - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; + 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) ); + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin( pev, pev->origin ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if ( m_distance == 0 ) + if( m_distance == 0 ) return; - if (pev->speed == 0) + 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_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; + m_center = pev->angles + ( m_distance * 0.5 ) * pev->movedir; - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { + if( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT ) ) + { SetThink( &CBaseEntity::SUB_CallUseToggle ); pev->nextthink = gpGlobals->time + 0.1; } pev->speed = 0; SetUse( &CPendulum::PendulumUse ); - if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) + if( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) { SetTouch( &CPendulum::RopeTouch ); } } -void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary { - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) + if( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) { - float delta; + float delta; - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start ); + delta = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ); pev->avelocity = m_maxSpeed * pev->movedir; - pev->nextthink = pev->ltime + (delta / m_maxSpeed); + pev->nextthink = pev->ltime + ( delta / m_maxSpeed ); SetThink( &CPendulum::Stop ); } else @@ -823,7 +816,7 @@ void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US } } -void CPendulum :: Stop( void ) +void CPendulum::Stop( void ) { pev->angles = m_start; pev->speed = 0; @@ -836,22 +829,22 @@ void CPendulum::Blocked( CBaseEntity *pOther ) m_time = gpGlobals->time; } -void CPendulum :: Swing( void ) +void CPendulum::Swing( void ) { float delta, dt; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center ); + + 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 ) + if( delta > 0 && m_accel > 0 ) pev->speed -= m_accel * dt; // Integrate velocity else pev->speed += m_accel * dt; - if ( pev->speed > m_maxSpeed ) + if( pev->speed > m_maxSpeed ) pev->speed = m_maxSpeed; - else if ( 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; @@ -859,58 +852,59 @@ void CPendulum :: Swing( void ) // Call this again pev->nextthink = pev->ltime + 0.1; - if ( m_damp ) + if( m_damp ) { m_dampSpeed -= m_damp * m_dampSpeed * dt; - if ( m_dampSpeed < 30.0 ) + if( m_dampSpeed < 30.0 ) { pev->angles = m_center; pev->speed = 0; SetThink( NULL ); pev->avelocity = g_vecZero; } - else if ( pev->speed > m_dampSpeed ) + else if( pev->speed > m_dampSpeed ) pev->speed = m_dampSpeed; - else if ( pev->speed < -m_dampSpeed ) + else if( pev->speed < -m_dampSpeed ) pev->speed = -m_dampSpeed; - } } -void CPendulum :: Touch ( CBaseEntity *pOther ) +void CPendulum::Touch( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + entvars_t *pevOther = pOther->pev; - if ( pev->dmg <= 0 ) + if( pev->dmg <= 0 ) return; // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) + if( !pevOther->takedamage ) return; // calculate damage based on rotation speed float damage = pev->dmg * pev->speed * 0.01; - if ( damage < 0 ) + if( damage < 0 ) damage = -damage; pOther->TakeDamage( pev, pev, damage, DMG_CRUSH ); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage; + + pevOther->velocity = ( pevOther->origin - VecBModelOrigin( pev ) ).Normalize() * damage; } -void CPendulum :: RopeTouch ( CBaseEntity *pOther ) +void CPendulum::RopeTouch( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + entvars_t *pevOther = pOther->pev; - if ( !pOther->IsPlayer() ) - {// not a player! - ALERT ( at_console, "Not a client\n" ); + 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. + if( ENT( pevOther ) == pev->enemy ) + { + // this player already on the rope. return; } diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 63d847de..18026b43 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -29,7 +29,7 @@ #define SQUID_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve -int iSquidSpitSprite; +int iSquidSpitSprite; //========================================================= // monster-specific schedule types @@ -64,47 +64,47 @@ public: void Touch( CBaseEntity *pOther ); void EXPORT Animate( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_maxFrame; + int m_maxFrame; }; LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ) -TYPEDESCRIPTION CSquidSpit::m_SaveData[] = +TYPEDESCRIPTION CSquidSpit::m_SaveData[] = { DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), }; IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ) -void CSquidSpit:: Spawn( void ) +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"); + 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) ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; } void CSquidSpit::Animate( void ) { pev->nextthink = gpGlobals->time + 0.1; - if ( pev->frame++ ) + if( pev->frame++ ) { - if ( pev->frame > m_maxFrame ) + if( pev->frame > m_maxFrame ) { pev->frame = 0; } @@ -115,60 +115,59 @@ 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->pev->owner = ENT( pevOwner ); pSpit->SetThink( &CSquidSpit::Animate ); pSpit->pev->nextthink = gpGlobals->time + 0.1; } -void CSquidSpit :: Touch ( CBaseEntity *pOther ) +void CSquidSpit::Touch( CBaseEntity *pOther ) { TraceResult tr; - int iPitch; + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - switch ( RANDOM_LONG( 0, 1 ) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); break; } - if ( !pOther->pev->takedamage ) + 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)); + 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_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 ) + 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 ); + pOther->TakeDamage( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); } SetThink( &CBaseEntity::SUB_Remove ); @@ -191,29 +190,29 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( 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 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 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 ); + BOOL FValidateHintType( short sHint ); Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); + 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 IRelationship( CBaseEntity *pTarget ); + int IgnoreConditions( void ); + MONSTERSTATE GetIdealState( void ); - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); CUSTOM_SCHEDULES @@ -239,19 +238,19 @@ IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ) //========================================================= // IgnoreConditions //========================================================= -int CBullsquid::IgnoreConditions ( void ) +int CBullsquid::IgnoreConditions( void ) { int iIgnore = CBaseMonster::IgnoreConditions(); - if ( gpGlobals->time - m_flLastHurtTime <= 20 ) + 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 != NULL ) + if( m_hEnemy != NULL ) { - if ( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) + if( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) { // (Unless after a tasty headcrab) iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; @@ -265,76 +264,76 @@ int CBullsquid::IgnoreConditions ( void ) // IRelationship - overridden for bullsquid so that it can // be made to ignore its love of headcrabs for a while. //========================================================= -int CBullsquid::IRelationship ( CBaseEntity *pTarget ) +int CBullsquid::IRelationship( CBaseEntity *pTarget ) { - if ( gpGlobals->time - m_flLastHurtTime < 5 && FClassnameIs ( pTarget->pev, "monster_headcrab" ) ) + 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 ); + 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 ) +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 != NULL && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) + if( m_hEnemy != NULL && 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 ) ) + 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" ) ) + 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 ); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } //========================================================= // CheckRangeAttack1 //========================================================= -BOOL CBullsquid :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CBullsquid::CheckRangeAttack1( float flDot, float flDist ) { - if ( IsMoving() && flDist >= 512 ) + 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( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { - if ( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) + 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() ) + if( IsMoving() ) { // don't spit again for a long time, resume chasing enemy. m_flNextSpitTime = gpGlobals->time + 5; @@ -355,9 +354,9 @@ BOOL CBullsquid :: CheckRangeAttack1 ( float flDot, float flDist ) // 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 ) +BOOL CBullsquid::CheckMeleeAttack1( float flDot, float flDist ) { - if ( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) + if( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) { return TRUE; } @@ -370,19 +369,19 @@ BOOL CBullsquid :: CheckMeleeAttack1 ( float flDot, float flDist ) // this attack will not be performed if the tailwhip attack // is valid. //========================================================= -BOOL CBullsquid :: CheckMeleeAttack2 ( float flDot, float flDist ) +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 + 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 ) +BOOL CBullsquid::FValidateHintType( short sHint ) { int i; @@ -391,15 +390,15 @@ BOOL CBullsquid :: FValidateHintType ( short sHint ) HINT_WORLD_HUMAN_BLOOD, }; - for ( i = 0 ; i < ARRAYSIZE ( sSquidHints ) ; i++ ) + for( i = 0; i < ARRAYSIZE( sSquidHints ); i++ ) { - if ( sSquidHints[ i ] == sHint ) + if( sSquidHints[i] == sHint ) { return TRUE; } } - ALERT ( at_aiconsole, "Couldn't validate hint type" ); + ALERT( at_aiconsole, "Couldn't validate hint type" ); return FALSE; } @@ -408,47 +407,47 @@ BOOL CBullsquid :: FValidateHintType ( short sHint ) // of sounds this monster regards. In the base class implementation, // monsters care about all sounds, but no scents. //========================================================= -int CBullsquid :: ISoundMask ( void ) +int CBullsquid::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_PLAYER; + 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 ) +int CBullsquid::Classify( void ) { - return CLASS_ALIEN_PREDATOR; + return CLASS_ALIEN_PREDATOR; } //========================================================= // IdleSound //========================================================= #define SQUID_ATTN_IDLE (float)1.5 -void CBullsquid :: IdleSound ( void ) +void CBullsquid::IdleSound( void ) { - switch ( RANDOM_LONG(0,4) ) + switch( RANDOM_LONG( 0, 4 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, SQUID_ATTN_IDLE ); + 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 ); + 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 ); + 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 ); + 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 ); + case 4: + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle5.wav", 1, SQUID_ATTN_IDLE ); break; } } @@ -456,23 +455,23 @@ void CBullsquid :: IdleSound ( void ) //========================================================= // PainSound //========================================================= -void CBullsquid :: PainSound ( void ) +void CBullsquid::PainSound( void ) { int iPitch = RANDOM_LONG( 85, 120 ); - switch ( RANDOM_LONG(0,3) ) + switch( RANDOM_LONG( 0, 3 ) ) { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain1.wav", 1, ATTN_NORM, 0, iPitch ); + 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 ); + 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 ); + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_pain4.wav", 1, ATTN_NORM, 0, iPitch ); break; } } @@ -480,17 +479,17 @@ void CBullsquid :: PainSound ( void ) //========================================================= // AlertSound //========================================================= -void CBullsquid :: AlertSound ( void ) +void CBullsquid::AlertSound( void ) { int iPitch = RANDOM_LONG( 140, 160 ); - switch ( RANDOM_LONG ( 0, 1 ) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, ATTN_NORM, 0, iPitch ); + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, ATTN_NORM, 0, iPitch ); break; } } @@ -499,7 +498,7 @@ void CBullsquid :: AlertSound ( void ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CBullsquid :: SetYawSpeed ( void ) +void CBullsquid::SetYawSpeed( void ) { int ys; @@ -507,10 +506,18 @@ void CBullsquid :: SetYawSpeed ( void ) 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; + 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; @@ -523,101 +530,96 @@ void CBullsquid :: SetYawSpeed ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CBullsquid::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case BSQUID_AE_SPIT: - { - Vector vecSpitOffset; - Vector vecSpitDir; + { + Vector vecSpitOffset; + Vector vecSpitDir; - UTIL_MakeVectors ( pev->angles ); + 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(); + // !!!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 ); + 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(); - // 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; + // 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; + // 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; + 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; + // close eye. + pev->skin = 1; } + break; + case BSQUID_AE_HOP: + { + float flGravity = g_psv_gravity->value; - // 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; + // 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; @@ -625,37 +627,35 @@ void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, 0, 0 ); - if ( pHurt ) + if( pHurt ) { // croonchy bite sound iPitch = RANDOM_FLOAT( 90, 110 ); - switch ( RANDOM_LONG( 0, 1 ) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); + 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 ); + 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; + //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() ) + if( pHurt->IsPlayer() ) { UTIL_MakeVectors( pev->angles ); pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; } } } - break; - + break; default: CBaseMonster::HandleAnimEvent( pEvent ); } @@ -664,22 +664,22 @@ void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CBullsquid :: Spawn() +void CBullsquid::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/bullsquid.mdl"); + 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; + 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_fCanThreatDisplay = TRUE; m_flNextSpitTime = gpGlobals->time; MonsterInit(); @@ -688,62 +688,62 @@ void CBullsquid :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CBullsquid :: Precache() +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_MODEL( "models/bullsquid.mdl" ); - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + PRECACHE_MODEL( "sprites/bigspit.spr" );// spit projectile. - 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"); + iSquidSpitSprite = PRECACHE_MODEL( "sprites/tinyspit.spr" );// client side spittle. - PRECACHE_SOUND("bullchicken/bc_acid1.wav"); + PRECACHE_SOUND( "zombie/claw_miss2.wav" );// because we use the basemonster SWIPE animation event - PRECACHE_SOUND("bullchicken/bc_bite2.wav"); - PRECACHE_SOUND("bullchicken/bc_bite3.wav"); + PRECACHE_SOUND( "bullchicken/bc_attack2.wav" ); + PRECACHE_SOUND( "bullchicken/bc_attack3.wav" ); - PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); - PRECACHE_SOUND("bullchicken/bc_spithit2.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 ) +void CBullsquid::DeathSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die1.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_die3.wav", 1, ATTN_NORM ); break; } } @@ -751,15 +751,15 @@ void CBullsquid :: DeathSound ( void ) //========================================================= // AttackSound //========================================================= -void CBullsquid :: AttackSound ( void ) +void CBullsquid::AttackSound( void ) { - switch ( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM ); break; } } @@ -768,26 +768,26 @@ void CBullsquid :: AttackSound ( void ) // RunAI - overridden for bullsquid because there are things // that need to be checked every think. //======================================================== -void CBullsquid :: RunAI ( void ) +void CBullsquid::RunAI( void ) { // first, do base class stuff - CBaseMonster :: RunAI(); + CBaseMonster::RunAI(); - if ( pev->skin != 0 ) + if( pev->skin != 0 ) { // close eye if it was open. pev->skin = 0; } - if ( RANDOM_LONG(0,39) == 0 ) + if( RANDOM_LONG( 0, 39 ) == 0 ) { pev->skin = 1; } - if ( m_hEnemy != NULL && m_Activity == ACT_RUN ) + if( m_hEnemy != NULL && m_Activity == ACT_RUN ) { // chasing enemy. Sprint for last bit - if ( (pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) + if( ( pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) { pev->framerate = 1.25; } @@ -799,23 +799,23 @@ void CBullsquid :: RunAI ( void ) //========================================================= // primary range attack -Task_t tlSquidRangeAttack1[] = +Task_t tlSquidRangeAttack1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, }; -Schedule_t slSquidRangeAttack1[] = +Schedule_t slSquidRangeAttack1[] = { - { + { tlSquidRangeAttack1, - ARRAYSIZE ( tlSquidRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | + 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" @@ -823,29 +823,28 @@ Schedule_t slSquidRangeAttack1[] = }; // Chase enemy schedule -Task_t tlSquidChaseEnemy1[] = +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 }, + { 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 | + 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_DANGER | bits_SOUND_MEAT, "Squid Chase Enemy" }, @@ -853,17 +852,17 @@ Schedule_t slSquidChaseEnemy[] = 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. + { 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 ), + ARRAYSIZE( tlSquidHurtHop ), 0, 0, "SquidHurtHop" @@ -872,18 +871,18 @@ Schedule_t slSquidHurtHop[] = Task_t tlSquidSeeCrab[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EXCITED }, - { TASK_FACE_ENEMY, (float)0 }, + { 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 | + ARRAYSIZE( tlSquidSeeCrab ), + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "SquidSeeCrab" @@ -893,20 +892,20 @@ Schedule_t slSquidSeeCrab[] = // 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 }, + { 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[] = @@ -914,13 +913,12 @@ Schedule_t slSquidEat[] = { tlSquidEat, ARRAYSIZE( tlSquidEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - + 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_MEAT | bits_SOUND_CARCASS, "SquidEat" } @@ -930,21 +928,21 @@ Schedule_t slSquidEat[] = // 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 }, + { 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[] = @@ -952,13 +950,12 @@ Schedule_t slSquidSniffAndEat[] = { tlSquidSniffAndEat, ARRAYSIZE( tlSquidSniffAndEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - + 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_MEAT | bits_SOUND_CARCASS, "SquidSniffAndEat" } @@ -967,18 +964,18 @@ Schedule_t slSquidSniffAndEat[] = // 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 }, + { 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[] = @@ -986,14 +983,12 @@ Schedule_t slSquidWallow[] = { tlSquidWallow, ARRAYSIZE( tlSquidWallow ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - + 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" } }; @@ -1014,24 +1009,24 @@ IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ) //========================================================= // GetSchedule //========================================================= -Schedule_t *CBullsquid :: GetSchedule( void ) +Schedule_t *CBullsquid::GetSchedule( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_ALERT: { - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) + if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { - return GetScheduleOfType ( SCHED_SQUID_HURTHOP ); + return GetScheduleOfType( SCHED_SQUID_HURTHOP ); } - if ( HasConditions(bits_COND_SMELL_FOOD) ) + if( HasConditions( bits_COND_SMELL_FOOD ) ) { - CSound *pSound; + CSound *pSound; pSound = PBestScent(); - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) + if( pSound && ( !FInViewCone( &pSound->m_vecOrigin ) || !FVisible( pSound->m_vecOrigin ) ) ) { // scent is behind or occluded return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); @@ -1041,48 +1036,47 @@ Schedule_t *CBullsquid :: GetSchedule( void ) return GetScheduleOfType( SCHED_SQUID_EAT ); } - if ( HasConditions(bits_COND_SMELL) ) + if( HasConditions( bits_COND_SMELL ) ) { // there's something stinky. - CSound *pSound; + CSound *pSound; pSound = PBestScent(); - if ( pSound ) - return GetScheduleOfType( SCHED_SQUID_WALLOW); + if( pSound ) + return GetScheduleOfType( SCHED_SQUID_WALLOW ); } - break; } case MONSTERSTATE_COMBAT: { // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } - if ( HasConditions(bits_COND_NEW_ENEMY) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { - if ( m_fCanThreatDisplay && IRelationship( m_hEnemy ) == R_HT ) + 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 ); + return GetScheduleOfType( SCHED_SQUID_SEECRAB ); } else { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); + return GetScheduleOfType( SCHED_WAKE_ANGRY ); } } - if ( HasConditions(bits_COND_SMELL_FOOD) ) + if( HasConditions( bits_COND_SMELL_FOOD ) ) { - CSound *pSound; + CSound *pSound; pSound = PBestScent(); - - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) + + if( pSound && ( !FInViewCone( &pSound->m_vecOrigin ) || !FVisible( pSound->m_vecOrigin ) ) ) { // scent is behind or occluded return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); @@ -1092,63 +1086,62 @@ Schedule_t *CBullsquid :: GetSchedule( void ) return GetScheduleOfType( SCHED_SQUID_EAT ); } - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) { - return GetScheduleOfType ( SCHED_MELEE_ATTACK2 ); + return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); } - - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); + return GetScheduleOfType( SCHED_CHASE_ENEMY ); break; } default: break; } - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } //========================================================= // GetScheduleOfType //========================================================= -Schedule_t* CBullsquid :: GetScheduleOfType ( int Type ) +Schedule_t *CBullsquid::GetScheduleOfType( int Type ) { - switch ( Type ) + switch( Type ) { case SCHED_RANGE_ATTACK1: - return &slSquidRangeAttack1[ 0 ]; + return &slSquidRangeAttack1[0]; break; case SCHED_SQUID_HURTHOP: - return &slSquidHurtHop[ 0 ]; + return &slSquidHurtHop[0]; break; case SCHED_SQUID_SEECRAB: - return &slSquidSeeCrab[ 0 ]; + return &slSquidSeeCrab[0]; break; case SCHED_SQUID_EAT: - return &slSquidEat[ 0 ]; + return &slSquidEat[0]; break; case SCHED_SQUID_SNIFF_AND_EAT: - return &slSquidSniffAndEat[ 0 ]; + return &slSquidSniffAndEat[0]; break; case SCHED_SQUID_WALLOW: - return &slSquidWallow[ 0 ]; + return &slSquidWallow[0]; break; case SCHED_CHASE_ENEMY: - return &slSquidChaseEnemy[ 0 ]; + return &slSquidChaseEnemy[0]; break; } - return CBaseMonster :: GetScheduleOfType ( Type ); + return CBaseMonster::GetScheduleOfType( Type ); } //========================================================= @@ -1158,52 +1151,52 @@ Schedule_t* CBullsquid :: GetScheduleOfType ( int Type ) // know explicitly when the last attempt to chase the enemy // failed, since that impacts its attack choices. //========================================================= -void CBullsquid :: StartTask ( Task_t *pTask ) +void CBullsquid::StartTask( Task_t *pTask ) { m_iTaskStatus = TASKSTATUS_RUNNING; - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_MELEE_ATTACK2: { - switch ( RANDOM_LONG ( 0, 2 ) ) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + case 2: + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); break; } - CBaseMonster :: StartTask ( pTask ); + CBaseMonster::StartTask( pTask ); break; } case TASK_SQUID_HOPTURN: { - SetActivity ( ACT_HOP ); - MakeIdealYaw ( m_vecEnemyLKP ); + 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 ) ) + if( BuildRoute( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) { m_iTaskStatus = TASKSTATUS_COMPLETE; } else { - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); + ALERT( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } default: { - CBaseMonster :: StartTask ( pTask ); + CBaseMonster::StartTask( pTask ); break; } } @@ -1212,16 +1205,16 @@ void CBullsquid :: StartTask ( Task_t *pTask ) //========================================================= // RunTask //========================================================= -void CBullsquid :: RunTask ( Task_t *pTask ) +void CBullsquid::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_SQUID_HOPTURN: { MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { m_iTaskStatus = TASKSTATUS_COMPLETE; } @@ -1229,7 +1222,7 @@ void CBullsquid :: RunTask ( Task_t *pTask ) } default: { - CBaseMonster :: RunTask( pTask ); + CBaseMonster::RunTask( pTask ); break; } } @@ -1240,21 +1233,21 @@ void CBullsquid :: RunTask ( Task_t *pTask ) // the feature that makes it lose interest in headcrabs for // a while if something injures it. //========================================================= -MONSTERSTATE CBullsquid :: GetIdealState ( void ) +MONSTERSTATE CBullsquid::GetIdealState( void ) { - int iConditions; + int iConditions; iConditions = IScheduleFlags(); - + // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: /* COMBAT goes to ALERT upon death of enemy */ { - if ( m_hEnemy != NULL && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) + if( m_hEnemy != NULL && ( 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 = NULL; @@ -1266,7 +1259,7 @@ MONSTERSTATE CBullsquid :: GetIdealState ( void ) break; } - m_IdealMonsterState = CBaseMonster :: GetIdealState(); + m_IdealMonsterState = CBaseMonster::GetIdealState(); return m_IdealMonsterState; } diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index bbbe3a1c..15a17cf2 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -27,28 +27,27 @@ #include "doors.h" #define SF_BUTTON_DONTMOVE 1 -#define SF_ROTBUTTON_NOTSOLID 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_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 ); + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - string_t m_globalstate; - int m_triggermode; - int m_initialstate; + string_t m_globalstate; + int m_triggermode; + int m_initialstate; }; TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = @@ -66,26 +65,26 @@ void CEnvGlobal::KeyValue( KeyValueData *pkvd ) { pkvd->fHandled = TRUE; - if ( FStrEq(pkvd->szKeyName, "globalstate") ) // State name + if( FStrEq( pkvd->szKeyName, "globalstate" ) ) // State name m_globalstate = ALLOC_STRING( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "triggermode") ) + else if( FStrEq( pkvd->szKeyName, "triggermode" ) ) m_triggermode = atoi( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "initialstate") ) + else if( FStrEq( pkvd->szKeyName, "initialstate" ) ) m_initialstate = atoi( pkvd->szValue ); - else + else CPointEntity::KeyValue( pkvd ); } void CEnvGlobal::Spawn( void ) { - if ( !m_globalstate ) + if( !m_globalstate ) { - REMOVE_ENTITY( ENT(pev) ); + REMOVE_ENTITY( ENT( pev ) ); return; } - if ( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) ) + if( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) ) { - if ( !gGlobalState.EntityInTable( m_globalstate ) ) + if( !gGlobalState.EntityInTable( m_globalstate ) ) gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)m_initialstate ); } } @@ -108,22 +107,20 @@ void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us break; default: case 3: - if ( oldState == GLOBAL_ON ) + if( oldState == GLOBAL_ON ) newState = GLOBAL_OFF; - else if ( oldState == GLOBAL_OFF ) + else if( oldState == GLOBAL_OFF ) newState = GLOBAL_ON; else newState = oldState; } - if ( gGlobalState.EntityInTable( m_globalstate ) ) + if( gGlobalState.EntityInTable( m_globalstate ) ) gGlobalState.EntitySetState( m_globalstate, newState ); else gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, newState ); } - - TYPEDESCRIPTION CMultiSource::m_SaveData[] = { //!!!BUGBUG FIX @@ -140,22 +137,21 @@ 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")) + 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") ) + else if( FStrEq( pkvd->szKeyName, "globalstate" ) ) { m_globalstate = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else + else CPointEntity::KeyValue( pkvd ); } @@ -169,7 +165,7 @@ void CMultiSource::Spawn() pev->movetype = MOVETYPE_NONE; pev->nextthink = gpGlobals->time + 0.1; pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized - SetThink( &CMultiSource::Register); + SetThink( &CMultiSource::Register ); } void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) @@ -177,27 +173,26 @@ void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE int i = 0; // Find the entity in our list - while (i < m_iTotal) - if ( m_rgEntities[i++] == pCaller ) + while( i < m_iTotal ) + if( m_rgEntities[i++] == pCaller ) break; // if we didn't find it, report error and leave - if (i > m_iTotal) + if( i > m_iTotal ) { - ALERT(at_console, "MultiSrc:Used by non member %s.\n", STRING(pCaller->pev->classname)); + 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; + m_rgTriggered[i - 1] ^= 1; // - if ( IsTriggered( pActivator ) ) + if( IsTriggered( pActivator ) ) { - ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING(pev->targetname), m_iTotal ); + ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING( pev->targetname ), m_iTotal ); USE_TYPE useType = USE_TOGGLE; - if ( m_globalstate ) + if( m_globalstate ) useType = USE_ON; SUB_UseTargets( NULL, useType, 0 ); } @@ -209,52 +204,51 @@ BOOL CMultiSource::IsTriggered( CBaseEntity * ) int i = 0; // Still initializing? - if ( pev->spawnflags & SF_MULTI_INIT ) + if( pev->spawnflags & SF_MULTI_INIT ) return 0; - while (i < m_iTotal) + while( i < m_iTotal ) { - if (m_rgTriggered[i] == 0) + if( m_rgTriggered[i] == 0 ) break; i++; } - if (i == m_iTotal) + if( i == m_iTotal ) { - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) + if( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) return 1; } - + return 0; } -void CMultiSource::Register(void) +void CMultiSource::Register( void ) { - edict_t *pentTarget = NULL; + edict_t *pentTarget = NULL; m_iTotal = 0; memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); - SetThink( &CBaseEntity::SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing ); // search for all entities which target this multisource (pev->targetname) + pentTarget = FIND_ENTITY_BY_STRING( NULL, "target", STRING( pev->targetname ) ); - pentTarget = FIND_ENTITY_BY_STRING(NULL, "target", STRING(pev->targetname)); - - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) + while( !FNullEnt( pentTarget ) && ( m_iTotal < MS_MAX_TARGETS ) ) { - CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); - if ( pTarget ) + 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( pentTarget, "target", STRING( pev->targetname ) ); } - pentTarget = FIND_ENTITY_BY_STRING(NULL, "classname", "multi_manager"); - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) + 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) ) + 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" ); @@ -274,7 +268,7 @@ TYPEDESCRIPTION CBaseButton::m_SaveData[] = 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() + //DEFINE_FIELD( CBaseButton, m_ls, FIELD_??? ), // This is restored in Precache() }; IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ) @@ -283,98 +277,131 @@ void CBaseButton::Precache( void ) { char *pszSound; - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state + 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"); + 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) + if( m_bLockedSound ) { pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); + PRECACHE_SOUND( pszSound ); + m_ls.sLockedSound = ALLOC_STRING( pszSound ); } - if (m_bUnlockedSound) + if( m_bUnlockedSound ) { pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); + PRECACHE_SOUND( pszSound ); + m_ls.sUnlockedSound = ALLOC_STRING( pszSound ); } // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) + 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; + case 1: // access denied + m_ls.sLockedSentence = MAKE_STRING( "NA" ); + break; + case 2: // security lockout + m_ls.sLockedSentence = MAKE_STRING( "ND" ); + break; + case 3: // blast door + m_ls.sLockedSentence = MAKE_STRING( "NF" ); + break; + case 4: // fire door + m_ls.sLockedSentence = MAKE_STRING( "NFIRE" ); + break; + case 5: // chemical door + m_ls.sLockedSentence = MAKE_STRING( "NCHEM" ); + break; + case 6: // radiation door + m_ls.sLockedSentence = MAKE_STRING( "NRAD" ); + break; + case 7: // gen containment + m_ls.sLockedSentence = MAKE_STRING( "NCON" ); + break; + case 8: // maintenance door + m_ls.sLockedSentence = MAKE_STRING( "NH" ); + break; + case 9: // broken door + m_ls.sLockedSentence = MAKE_STRING( "NG" ); + break; + default: + m_ls.sLockedSentence = 0; + break; } - switch (m_bUnlockedSentence) + 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; + case 1: // access granted + m_ls.sUnlockedSentence = MAKE_STRING( "EA" ); + break; + case 2: // security door + m_ls.sUnlockedSentence = MAKE_STRING("ED"); + break; + case 3: // blast door + m_ls.sUnlockedSentence = MAKE_STRING("EF"); + break; + case 4: // fire door + m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); + break; + case 5: // chemical door + m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); + break; + case 6: // radiation door + m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); + break; + case 7: // gen containment + m_ls.sUnlockedSentence = MAKE_STRING("ECON"); + break; + case 8: // maintenance door + m_ls.sUnlockedSentence = MAKE_STRING("EH"); + break; + 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")) + if( FStrEq( pkvd->szKeyName, "changetarget" ) ) { - m_strChangeTarget = ALLOC_STRING(pkvd->szValue); + m_strChangeTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) + else if( FStrEq( pkvd->szKeyName, "locked_sound" ) ) { - m_bLockedSound = atof(pkvd->szValue); + m_bLockedSound = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + else if( FStrEq( pkvd->szKeyName, "locked_sentence" ) ) { - m_bLockedSentence = atof(pkvd->szValue); + m_bLockedSentence = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + else if( FStrEq( pkvd->szKeyName, "unlocked_sound" ) ) { - m_bUnlockedSound = atof(pkvd->szValue); + m_bUnlockedSound = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + else if( FStrEq( pkvd->szKeyName, "unlocked_sentence" ) ) { - m_bUnlockedSentence = atof(pkvd->szValue); + m_bUnlockedSentence = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "sounds")) + else if( FStrEq( pkvd->szKeyName, "sounds" ) ) { - m_sounds = atoi(pkvd->szValue); + m_sounds = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -384,30 +411,30 @@ void CBaseButton::KeyValue( KeyValueData *pkvd ) // // ButtonShot // -int CBaseButton::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +int CBaseButton::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) + + 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 == NULL ) + if( m_hActivator == NULL ) return 0; - if ( code == BUTTON_RETURN ) + if( code == BUTTON_RETURN ) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + 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) ) + if( !( pev->spawnflags & SF_BUTTON_TOGGLE ) ) SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); ButtonReturn(); } else // code == BUTTON_ACTIVATE - ButtonActivate( ); + ButtonActivate(); return 0; } @@ -432,7 +459,7 @@ where it can be triggered again. LINK_ENTITY_TO_CLASS( func_button, CBaseButton ) -void CBaseButton::Spawn( ) +void CBaseButton::Spawn() { char *pszSound; @@ -441,52 +468,50 @@ void CBaseButton::Spawn( ) //a sound of 0 should not make a sound //---------------------------------------------------- pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); + 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 + 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); + SetMovedir( pev ); - pev->movetype = MOVETYPE_PUSH; - pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); + pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if (pev->speed == 0) + if( pev->speed == 0 ) pev->speed = 40; - if (pev->health > 0) + if( pev->health > 0 ) { pev->takedamage = DAMAGE_YES; } - if (m_flWait == 0) + if( m_flWait == 0 ) m_flWait = 1; - if (m_flLip == 0) + 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)); - + 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) ) + if( ( ( m_vecPosition2 - m_vecPosition1 ).Length() < 1 ) || ( pev->spawnflags & SF_BUTTON_DONTMOVE ) ) m_vecPosition2 = m_vecPosition1; - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); + 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 + if( FBitSet( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button { SetTouch( &CBaseButton::ButtonTouch ); } @@ -504,33 +529,74 @@ char *ButtonSound( int sound ) { char *pszSound; - switch ( sound ) + 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; + 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; + 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; @@ -539,28 +605,39 @@ char *ButtonSound( int sound ) // // Makes flagged buttons spark when turned off // - -void DoSpark(entvars_t *pev, const Vector &location ) +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) ) + 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; + 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 ) +void CBaseButton::ButtonSpark( void ) { SetThink( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval + pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT( 0, 1.5 );// spark again at random interval DoSpark( pev, pev->mins ); } @@ -568,39 +645,39 @@ void CBaseButton::ButtonSpark ( void ) // // Button's Use function // -void CBaseButton::ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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; + 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_toggle_state == TS_AT_TOP ) { - if (!m_fStayPushed && FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE)) + if( !m_fStayPushed && FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - + EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + //SUB_UseTargets( m_eoActivator ); ButtonReturn(); } } else - ButtonActivate( ); + 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 || + 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) ) ) + ( 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( m_toggle_state == TS_AT_TOP ) { - if((FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) && !m_fStayPushed) + if( ( FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) && !m_fStayPushed ) { return BUTTON_RETURN; } @@ -614,66 +691,66 @@ CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) // // Touching a button simply "activates" it. // -void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) +void CBaseButton::ButtonTouch( CBaseEntity *pOther ) { // Ignore touches by anything but players - if (!FClassnameIs(pOther->pev, "player")) + if( !FClassnameIs( pOther->pev, "player" ) ) return; m_hActivator = pOther; BUTTON_CODE code = ButtonResponseToTouch(); - if ( code == BUTTON_NOTHING ) + if( code == BUTTON_NOTHING ) return; - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) + if( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) { // play button locked sound - PlayLockSounds(pev, &m_ls, TRUE, TRUE); + PlayLockSounds( pev, &m_ls, TRUE, TRUE ); return; } // Temporarily disable the touch function, until movement is finished. SetTouch( NULL ); - if ( code == BUTTON_RETURN ) + if( code == BUTTON_RETURN ) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + 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( ); + ButtonActivate(); } // // Starts the button moving "in/up". // -void CBaseButton::ButtonActivate( ) +void CBaseButton::ButtonActivate() { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + 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); + PlayLockSounds( pev, &m_ls, TRUE, TRUE ); return; } else { // button is unlocked, play unlocked sound - PlayLockSounds(pev, &m_ls, FALSE, TRUE); + PlayLockSounds( pev, &m_ls, FALSE, TRUE ); } - ASSERT(m_toggle_state == TS_AT_BOTTOM); + ASSERT( m_toggle_state == TS_AT_BOTTOM ); m_toggle_state = TS_GOING_UP; SetMoveDone( &CBaseButton::TriggerAndWait ); - if (!m_fRotating) - LinearMove( m_vecPosition2, pev->speed); + if( !m_fRotating ) + LinearMove( m_vecPosition2, pev->speed ); else - AngularMove( m_vecAngle2, pev->speed); + AngularMove( m_vecAngle2, pev->speed ); } // @@ -681,18 +758,18 @@ void CBaseButton::ButtonActivate( ) // void CBaseButton::TriggerAndWait( void ) { - ASSERT(m_toggle_state == TS_GOING_UP); + ASSERT( m_toggle_state == TS_GOING_UP ); - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + 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( m_fStayPushed || FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) { - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! + if( !FBitSet( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! { // ALL buttons are now use only SetTouch( NULL ); @@ -705,9 +782,8 @@ void CBaseButton::TriggerAndWait( void ) pev->nextthink = pev->ltime + m_flWait; SetThink( &CBaseButton::ButtonReturn ); } - - pev->frame = 1; // use alternate textures + pev->frame = 1; // use alternate textures SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); } @@ -717,14 +793,14 @@ void CBaseButton::TriggerAndWait( void ) // void CBaseButton::ButtonReturn( void ) { - ASSERT(m_toggle_state == TS_AT_TOP); + ASSERT( m_toggle_state == TS_AT_TOP ); m_toggle_state = TS_GOING_DOWN; SetMoveDone( &CBaseButton::ButtonBackHome ); - if (!m_fRotating) - LinearMove( m_vecPosition1, pev->speed); + if( !m_fRotating ) + LinearMove( m_vecPosition1, pev->speed ); else - AngularMove( m_vecAngle1, pev->speed); + AngularMove( m_vecAngle1, pev->speed ); pev->frame = 0; // use normal textures } @@ -734,38 +810,37 @@ void CBaseButton::ButtonReturn( void ) // void CBaseButton::ButtonBackHome( void ) { - ASSERT(m_toggle_state == TS_GOING_DOWN); + ASSERT( m_toggle_state == TS_GOING_DOWN ); m_toggle_state = TS_AT_BOTTOM; - if ( FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) + if( FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) { - //EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + //EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); } - - if (!FStringNull(pev->target)) + if( !FStringNull( pev->target ) ) { - edict_t* pentTarget = NULL; - for (;;) + edict_t *pentTarget = NULL; + for( ;; ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->target ) ); - if (FNullEnt(pentTarget)) + if( FNullEnt( pentTarget ) ) break; - if (!FClassnameIs(pentTarget, "multisource")) + if( !FClassnameIs( pentTarget, "multisource" ) ) continue; CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); - if ( pTarget ) + 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! + if( !FBitSet( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! { // All buttons are now use only SetTouch( NULL ); @@ -774,7 +849,7 @@ void CBaseButton::ButtonBackHome( void ) SetTouch( &CBaseButton::ButtonTouch ); // reset think for a sparking button - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) + if( FBitSet( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) { SetThink( &CBaseButton::ButtonSpark ); pev->nextthink = gpGlobals->time + 0.5;// no hurry. @@ -800,46 +875,46 @@ void CRotButton::Spawn( void ) //a sound of 0 should not make a sound //---------------------------------------------------- pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); + 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) ) + if( FBitSet( pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS ) ) pev->movedir = pev->movedir * -1; - pev->movetype = MOVETYPE_PUSH; + pev->movetype = MOVETYPE_PUSH; - if ( pev->spawnflags & SF_ROTBUTTON_NOTSOLID ) - pev->solid = SOLID_NOT; + if( pev->spawnflags & SF_ROTBUTTON_NOTSOLID ) + pev->solid = SOLID_NOT; else - pev->solid = SOLID_BSP; + pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if (pev->speed == 0) + if( pev->speed == 0 ) pev->speed = 40; - if (m_flWait == 0) + if( m_flWait == 0 ) m_flWait = 1; - if (pev->health > 0) + 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_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_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 ) ) + if( !FBitSet( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) { SetTouch( NULL ); SetUse( &CBaseButton::ButtonUse ); @@ -859,37 +934,36 @@ void CRotButton::Spawn( void ) class CMomentaryRotButton : public CBaseToggle { public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + virtual int ObjectCaps( void ) { - int flags = CBaseToggle :: ObjectCaps() & (~FCAP_ACROSS_TRANSITION); - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) + 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 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 ); + 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 CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GET_PRIVATE( pent ); }; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - static TYPEDESCRIPTION m_SaveData[]; - - int m_lastUsed; - int m_direction; - float m_returnSpeed; - vec3_t m_start; - vec3_t m_end; - int m_sounds; + int m_lastUsed; + int m_direction; + float m_returnSpeed; + vec3_t m_start; + vec3_t m_end; + int m_sounds; }; TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = @@ -910,10 +984,10 @@ void CMomentaryRotButton::Spawn( void ) { CBaseToggle::AxisDir( pev ); - if ( pev->speed == 0 ) + if( pev->speed == 0 ) pev->speed = 100; - if ( m_flMoveDistance < 0 ) + if( m_flMoveDistance < 0 ) { m_start = pev->angles + pev->movedir * m_flMoveDistance; m_end = pev->angles; @@ -927,31 +1001,31 @@ void CMomentaryRotButton::Spawn( void ) m_direction = -1; // This will toggle to +1 on the first use() } - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) - pev->solid = SOLID_BSP; + if( pev->spawnflags & SF_MOMENTARY_DOOR ) + pev->solid = SOLID_BSP; else - pev->solid = SOLID_NOT; + pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin( pev, pev->origin ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); char *pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); + PRECACHE_SOUND( pszSound ); + pev->noise = ALLOC_STRING( pszSound ); m_lastUsed = 0; } void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "returnspeed")) + if( FStrEq( pkvd->szKeyName, "returnspeed" ) ) { - m_returnSpeed = atof(pkvd->szValue); + m_returnSpeed = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "sounds")) + else if( FStrEq( pkvd->szKeyName, "sounds" ) ) { - m_sounds = atoi(pkvd->szValue); + m_sounds = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -960,7 +1034,7 @@ void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) void CMomentaryRotButton::PlaySound( void ) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); + 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 @@ -978,19 +1052,18 @@ void CMomentaryRotButton::UpdateAllButtons( float value, int start ) { // Update all rot buttons attached to the same target edict_t *pentTarget = NULL; - for (;;) + for( ; ; ) { - - pentTarget = FIND_ENTITY_BY_STRING(pentTarget, "target", STRING(pev->target)); - if (FNullEnt(pentTarget)) + pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "target", STRING( pev->target ) ); + if( FNullEnt( pentTarget ) ) break; - if ( FClassnameIs( VARS(pentTarget), "momentary_rot_button" ) ) + if( FClassnameIs( VARS( pentTarget ), "momentary_rot_button" ) ) { - CMomentaryRotButton *pEntity = CMomentaryRotButton::Instance(pentTarget); - if ( pEntity ) + CMomentaryRotButton *pEntity = CMomentaryRotButton::Instance( pentTarget ); + if( pEntity ) { - if ( start ) + if( start ) pEntity->UpdateSelf( value ); else pEntity->UpdateSelfReturn( value ); @@ -1003,7 +1076,7 @@ void CMomentaryRotButton::UpdateSelf( float value ) { BOOL fplaysound = FALSE; - if ( !m_lastUsed ) + if( !m_lastUsed ) { fplaysound = TRUE; m_direction = -m_direction; @@ -1011,44 +1084,44 @@ void CMomentaryRotButton::UpdateSelf( float value ) m_lastUsed = 1; pev->nextthink = pev->ltime + 0.1; - if ( m_direction > 0 && value >= 1.0 ) + if( m_direction > 0 && value >= 1.0 ) { pev->avelocity = g_vecZero; pev->angles = m_end; return; } - else if ( m_direction < 0 && value <= 0 ) + else if( m_direction < 0 && value <= 0 ) { pev->avelocity = g_vecZero; pev->angles = m_start; return; } - - if (fplaysound) + + 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 ) + if( pev->nextthink < pev->ltime ) pev->nextthink = pev->ltime + 0.1; else pev->nextthink += 0.1; - pev->avelocity = (m_direction * pev->speed) * pev->movedir; + pev->avelocity = m_direction * pev->speed * pev->movedir; SetThink( &CMomentaryRotButton::Off ); } void CMomentaryRotButton::UpdateTarget( float value ) { - if (!FStringNull(pev->target)) + if( !FStringNull( pev->target ) ) { - edict_t* pentTarget = NULL; - for (;;) + edict_t *pentTarget= NULL; + for( ; ; ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->target ) ); + if( FNullEnt( pentTarget ) ) break; - CBaseEntity *pEntity = CBaseEntity::Instance(pentTarget); - if ( pEntity ) + CBaseEntity *pEntity = CBaseEntity::Instance( pentTarget ); + if( pEntity ) { pEntity->Use( this, this, USE_SET, value ); } @@ -1060,7 +1133,7 @@ void CMomentaryRotButton::Off( void ) { pev->avelocity = g_vecZero; m_lastUsed = 0; - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) + if( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) { SetThink( &CMomentaryRotButton::Return ); pev->nextthink = pev->ltime + 0.1; @@ -1075,13 +1148,13 @@ 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 ) + if( value > 0 ) UpdateTarget( value ); } void CMomentaryRotButton::UpdateSelfReturn( float value ) { - if ( value <= 0 ) + if( value <= 0 ) { pev->avelocity = g_vecZero; pev->angles = m_start; @@ -1102,19 +1175,18 @@ void CMomentaryRotButton::UpdateSelfReturn( float value ) 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); + 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - static TYPEDESCRIPTION m_SaveData[]; - - float m_flDelay; + float m_flDelay; }; TYPEDESCRIPTION CEnvSpark::m_SaveData[] = @@ -1127,33 +1199,33 @@ IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ) LINK_ENTITY_TO_CLASS( env_spark, CEnvSpark ) LINK_ENTITY_TO_CLASS( env_debris, CEnvSpark ) -void CEnvSpark::Spawn(void) +void CEnvSpark::Spawn( void ) { SetThink( NULL ); SetUse( NULL ); - if (FBitSet(pev->spawnflags, 32)) // Use for on/off + if( FBitSet( pev->spawnflags, 32 ) ) // Use for on/off { - if (FBitSet(pev->spawnflags, 64)) // Start on + if( FBitSet( pev->spawnflags, 64 ) ) // Start on { - SetThink( &CEnvSpark::SparkThink); // start sparking - SetUse( &CEnvSpark::SparkStop); // set up +USE to stop sparking + SetThink( &CEnvSpark::SparkThink ); // start sparking + SetUse( &CEnvSpark::SparkStop ); // set up +USE to stop sparking } else - SetUse( &CEnvSpark::SparkStart); + SetUse( &CEnvSpark::SparkStart ); } else - SetThink( &CEnvSpark::SparkThink); + SetThink( &CEnvSpark::SparkThink ); - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); + pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT( 0, 1.5 ); - if (m_flDelay <= 0) + if( m_flDelay <= 0 ) m_flDelay = 1.5; - Precache( ); + Precache(); } -void CEnvSpark::Precache(void) +void CEnvSpark::Precache( void ) { PRECACHE_SOUND( "buttons/spark1.wav" ); PRECACHE_SOUND( "buttons/spark2.wav" ); @@ -1165,36 +1237,36 @@ void CEnvSpark::Precache(void) void CEnvSpark::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "MaxDelay")) + if( FStrEq( pkvd->szKeyName, "MaxDelay" ) ) { - m_flDelay = atof(pkvd->szValue); + 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")) + 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) +void EXPORT CEnvSpark::SparkThink( void ) { - pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT (0, m_flDelay); + 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 ) +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)); + 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 ) +void EXPORT CEnvSpark::SparkStop( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { SetUse( &CEnvSpark::SparkStart); SetThink( NULL ); @@ -1209,46 +1281,46 @@ 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 ); + 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->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 ) ) + 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 ) ) + if( !ShouldToggle( useType, (int)pev->frame ) ) return; pev->frame = 1-pev->frame; - if ( pev->frame ) + if( pev->frame ) SUB_UseTargets( pActivator, USE_ON, 0 ); else SUB_UseTargets( pActivator, USE_OFF, 0 ); } -int CButtonTarget :: ObjectCaps( void ) +int CButtonTarget::ObjectCaps( void ) { int caps = CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - if ( FBitSet(pev->spawnflags, SF_BTARGET_USE) ) + 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 ) +int CButtonTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - Use( Instance(pevAttacker), this, USE_TOGGLE, 0 ); + Use( Instance( pevAttacker ), this, USE_TOGGLE, 0 ); return 1; } diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index eacb5124..62b4eaa1 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -29,10 +29,10 @@ extern "C" void PM_Init ( struct playermove_s *ppmove ); extern "C" char PM_FindTextureType( char *name ); extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; +extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL int g_iSkillLevel; -static DLL_FUNCTIONS gFunctionTable = +static DLL_FUNCTIONS gFunctionTable = { GameDLLInit, //pfnGameInit DispatchSpawn, //pfnSpawn @@ -80,7 +80,7 @@ static DLL_FUNCTIONS gFunctionTable = 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 @@ -103,25 +103,25 @@ extern "C" { #endif int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) { - if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) + if( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) { return FALSE; } - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + memcpy( pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS) ); return TRUE; } int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) { - if ( !pFunctionTable || *interfaceVersion != INTERFACE_VERSION ) + 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 ) ); + + memcpy( pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS) ); return TRUE; } @@ -131,40 +131,39 @@ int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) int DispatchSpawn( edict_t *pent ) { - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pent ); - if (pEntity) + 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->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); + pEntity = (CBaseEntity *)GET_PRIVATE( pent ); - if ( pEntity ) + if( pEntity ) { - if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) + if( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) return -1; // return that this entity should be deleted - if ( pEntity->pev->flags & FL_KILLME ) + if( pEntity->pev->flags & FL_KILLME ) return -1; } - // Handle global stuff here - if ( pEntity && pEntity->pev->globalname ) + if( pEntity && pEntity->pev->globalname ) { const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) + if( pGlobal ) { // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) + if( pGlobal->state == GLOBAL_DEAD ) return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) + 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 } @@ -172,7 +171,7 @@ int DispatchSpawn( edict_t *pent ) { // 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) ); + //ALERT( at_console, "Added global entity %s (%s)\n", STRING( pEntity->pev->classname ), STRING( pEntity->pev->globalname ) ); } } @@ -183,10 +182,10 @@ int DispatchSpawn( edict_t *pent ) void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) { - if ( !pkvd || !pentKeyvalue ) + if( !pkvd || !pentKeyvalue ) return; - EntvarsKeyvalue( VARS(pentKeyvalue), pkvd ); + 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. @@ -194,9 +193,9 @@ void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) return; // Get the actualy entity object - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentKeyvalue ); - if ( !pEntity ) + if( !pEntity ) return; pEntity->KeyValue( pkvd ); @@ -208,33 +207,33 @@ BOOL gTouchDisabled = FALSE; void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) { - if ( gTouchDisabled ) + if( gTouchDisabled ) return; - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentTouched ); CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) ) + 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); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentUsed ); + CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - if (pEntity && !(pEntity->pev->flags & FL_KILLME) ) + 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) + 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) ); - + if( FBitSet( pEntity->pev->flags, FL_DORMANT ) ) + ALERT( at_error, "Dormant entity %s is thinking!!\n", STRING( pEntity->pev->classname ) ); + pEntity->Think(); } } @@ -244,26 +243,26 @@ void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked ); CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - if (pEntity) + 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 ]; + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pent ); - if ( pTable->pent != 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 ) + 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 ) + if( pEntity->pev->movetype == MOVETYPE_PUSH ) { float delta = pEntity->pev->nextthink - pEntity->pev->ltime; pEntity->pev->ltime = gpGlobals->time; @@ -284,13 +283,13 @@ void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) // 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) ); + edict_t *pent = FIND_ENTITY_BY_STRING( NULL, "globalname", STRING( globalname ) ); CBaseEntity *pReturn = CBaseEntity::Instance( pent ); - if ( pReturn ) + if( pReturn ) { - if ( !FClassnameIs( pReturn->pev, STRING(classname) ) ) + if( !FClassnameIs( pReturn->pev, STRING( classname ) ) ) { - ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) ); + ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING( globalname ), STRING( pReturn->pev->classname ) ); pReturn = NULL; } } @@ -300,15 +299,15 @@ CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname ) int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) { - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pent ); - if ( pEntity && pSaveData ) + if( pEntity && pSaveData ) { entvars_t tmpVars; Vector oldOffset; CRestore restoreHelper( pSaveData ); - if ( globalEntity ) + if( globalEntity ) { CRestore tmpRestore( pSaveData ); tmpRestore.PrecacheMode( 0 ); @@ -320,23 +319,23 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity // ------------------- 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 ) ) + 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 ) + if( pNewEntity ) { -// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) ); + //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; + 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 @@ -348,10 +347,9 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity // 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 ) + if( pEntity->ObjectCaps() & FCAP_MUST_SPAWN ) { pEntity->Restore( restoreHelper ); pEntity->Spawn(); @@ -359,37 +357,37 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity else { pEntity->Restore( restoreHelper ); - pEntity->Precache( ); + pEntity->Precache(); } // Again, could be deleted, get the pointer again. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); + pEntity = (CBaseEntity *)GET_PRIVATE( pent ); #if 0 - if ( pEntity && pEntity->pev->globalname && globalEntity ) + if( pEntity && pEntity->pev->globalname && globalEntity ) { - ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) ); + 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 ) + 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) ); + //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 ) + if( pEntity ) { UTIL_SetOrigin( pEntity->pev, pEntity->pev->origin ); pEntity->OverrideReset(); } } - else if ( pEntity && pEntity->pev->globalname ) + else if( pEntity && pEntity->pev->globalname ) { const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) + if( pGlobal ) { // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) + if( pGlobal->state == GLOBAL_DEAD ) return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) + else if( !FStrEq( STRING( gpGlobals->mapname ), pGlobal->levelName ) ) { pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive } @@ -397,7 +395,7 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity } else { - ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) ); + 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 ); } @@ -408,8 +406,8 @@ int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity void DispatchObjectCollsionBox( edict_t *pent ) { - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity) + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pent ); + if( pEntity ) { pEntity->SetObjectCollisionBox(); } @@ -429,11 +427,11 @@ void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseD restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); } -edict_t * EHANDLE::Get( void ) +edict_t *EHANDLE::Get( void ) { - if (m_pent) + if( m_pent ) { - if (m_pent->serialnumber == m_serialnumber) + if( m_pent->serialnumber == m_serialnumber ) return m_pent; else return NULL; @@ -441,25 +439,25 @@ edict_t * EHANDLE::Get( void ) return NULL; } -edict_t * EHANDLE::Set( edict_t *pent ) -{ +edict_t *EHANDLE::Set( edict_t *pent ) +{ m_pent = pent; - if (pent) + if( pent ) m_serialnumber = m_pent->serialnumber; return pent; } -EHANDLE :: operator CBaseEntity *() +EHANDLE::operator CBaseEntity *() { - return (CBaseEntity *)GET_PRIVATE( Get( ) ); + return (CBaseEntity *)GET_PRIVATE( Get() ); } -CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) +CBaseEntity *EHANDLE::operator = ( CBaseEntity *pEntity ) { - if (pEntity) + if( pEntity ) { m_pent = ENT( pEntity->pev ); - if (m_pent) + if( m_pent ) m_serialnumber = m_pent->serialnumber; } else @@ -470,29 +468,29 @@ CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) return pEntity; } -EHANDLE :: operator int () +EHANDLE::operator int () { return Get() != NULL; } -CBaseEntity * EHANDLE :: operator -> () +CBaseEntity * EHANDLE::operator -> () { - return (CBaseEntity *)GET_PRIVATE( Get( ) ); + return (CBaseEntity *)GET_PRIVATE( Get() ); } // give health -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) +int CBaseEntity::TakeHealth( float flHealth, int bitsDamageType ) { - if (!pev->takedamage) + if( !pev->takedamage ) return 0; // heal - if ( pev->health >= pev->max_health ) + if( pev->health >= pev->max_health ) return 0; pev->health += flHealth; - if (pev->health > pev->max_health) + if( pev->health > pev->max_health ) pev->health = pev->max_health; return 1; @@ -500,47 +498,47 @@ int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) // 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 ) +int CBaseEntity::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - Vector vecTemp; + Vector vecTemp; - if (!pev->takedamage) + 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 ) + if( pevAttacker == pevInflictor ) { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); + vecTemp = pevInflictor->origin - VecBModelOrigin( pev ); } else // an actual missile was involved. { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); + 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) ) + 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; + 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) + 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) + if( pev->health <= 0 ) { Killed( pevAttacker, GIB_NORMAL ); return 0; @@ -549,7 +547,7 @@ int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, return 1; } -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +void CBaseEntity::Killed( entvars_t *pevAttacker, int iGib ) { pev->takedamage = DAMAGE_NO; pev->deadflag = DEAD_DEAD; @@ -558,17 +556,17 @@ void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) CBaseEntity *CBaseEntity::GetNextTarget( void ) { - if ( FStringNull( pev->target ) ) + if( FStringNull( pev->target ) ) return NULL; - edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ); - if ( FNullEnt(pTarget) ) + 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[] = +TYPEDESCRIPTION CBaseEntity::m_SaveData[] = { DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ), @@ -580,8 +578,8 @@ TYPEDESCRIPTION CBaseEntity::m_SaveData[] = int CBaseEntity::Save( CSave &save ) { - if ( save.WriteEntVars( "ENTVARS", pev ) ) - return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); + if( save.WriteEntVars( "ENTVARS", pev ) ) + return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE( m_SaveData ) ); return 0; } @@ -591,18 +589,18 @@ 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( status ) + status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE( m_SaveData ) ); - if ( pev->modelindex != 0 && !FStringNull(pev->model) ) + 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 + PRECACHE_MODEL( (char *)STRING( pev->model ) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); + UTIL_SetSize( pev, mins, maxs ); // Reset them } return status; @@ -611,26 +609,27 @@ int CBaseEntity::Restore( CRestore &restore ) // 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; + 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++) + for( i = 0; i < 3; i++ ) { - v = fabs( ((float *)pev->mins)[i]); - if (v > max) + v = fabs( ( (float *)pev->mins )[i] ); + if( v > max ) max = v; - v = fabs( ((float *)pev->maxs)[i]); - if (v > max) + v = fabs( ( (float *)pev->maxs )[i] ); + if( v > max ) max = v; } - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++ ) { - ((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max; - ((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max; + ( (float *)pev->absmin )[i] = ( (float *)pev->origin )[i] - max; + ( (float *)pev->absmax )[i] = ( (float *)pev->origin )[i] + max; } } else @@ -652,19 +651,19 @@ void CBaseEntity::SetObjectCollisionBox( void ) ::SetObjectCollisionBox( pev ); } -int CBaseEntity :: Intersects( CBaseEntity *pOther ) +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; + 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 ) +void CBaseEntity::MakeDormant( void ) { SetBits( pev->flags, FL_DORMANT ); @@ -680,62 +679,73 @@ void CBaseEntity :: MakeDormant( void ) UTIL_SetOrigin( pev, pev->origin ); } -int CBaseEntity :: IsDormant( void ) +int CBaseEntity::IsDormant( void ) { return FBitSet( pev->flags, FL_DORMANT ); } -BOOL CBaseEntity :: IsInWorld( void ) +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; + 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; + 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( useType != USE_TOGGLE && useType != USE_SET ) { - if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) ) + if( ( currentState && useType == USE_ON ) || ( !currentState && useType == USE_OFF ) ) return 0; } return 1; } - -int CBaseEntity :: DamageDecal( int bitsDamageType ) +int CBaseEntity::DamageDecal( int bitsDamageType ) { - if ( pev->rendermode == kRenderTransAlpha ) + if( pev->rendermode == kRenderTransAlpha ) return -1; - if ( pev->rendermode != kRenderNormal ) + if( pev->rendermode != kRenderNormal ) return DECAL_BPROOF1; - return DECAL_GUNSHOT1 + RANDOM_LONG(0,4); + 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( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) +CBaseEntity *CBaseEntity::Create( 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 ) ) + pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName ) ); + if( FNullEnt( pent ) ) { ALERT ( at_console, "NULL Ent in Create!\n" ); return NULL; diff --git a/dlls/cbase.h b/dlls/cbase.h index 88094c39..47ce7595 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -30,14 +30,14 @@ CBaseEntity // 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_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) +#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 @@ -64,37 +64,43 @@ 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 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; +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 ); +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_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_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_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_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; @@ -102,7 +108,6 @@ class CBaseMonster; class CBasePlayerItem; class CSquadMonster; - #define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn. // @@ -112,7 +117,7 @@ class EHANDLE { private: edict_t *m_pent; - int m_serialnumber; + int m_serialnumber; public: edict_t *Get( void ); edict_t *Set( edict_t *pent ); @@ -121,11 +126,10 @@ public: operator CBaseEntity *(); - CBaseEntity * operator = (CBaseEntity *pEntity); - CBaseEntity * operator ->(); + CBaseEntity *operator = ( CBaseEntity *pEntity ); + CBaseEntity *operator ->(); }; - // // Base Entity. All entity types derive from this // @@ -137,91 +141,89 @@ public: 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. + 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 ) {} - + 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 ); + 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. + // 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[]; - 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, 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 ); + 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, 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 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 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 ); + 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 ) + 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 ); + if( m_pfnUse ) + ( this->*m_pfnUse )( pActivator, pCaller, useType, value ); } - virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; + 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 ) + void *operator new( size_t stAllocateBlock, entvars_t *pev ) { - return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); + return (void *)ALLOC_PRIVATE( ENT( pev ), stAllocateBlock ); }; // don't use this. #if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher - void operator delete(void *pMem, entvars_t *pev) + void operator delete( void *pMem, entvars_t *pev ) { pev->flags |= FL_KILLME; }; @@ -233,26 +235,26 @@ public: void EXPORT SUB_Remove( void ); void EXPORT SUB_DoNothing( void ); void EXPORT SUB_StartFadeOut ( void ); - void EXPORT SUB_FadeOut ( 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 ); + 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; } + 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); + { + if( !pent ) + pent = ENT( 0 ); + CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE( pent ); return pEnt; } @@ -262,78 +264,72 @@ public: CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) { CBaseEntity *pEntity = Instance( pevMonster ); - if ( pEntity ) + if( pEntity ) return pEntity->MyMonsterPointer(); return NULL; } CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) { CBaseEntity *pEntity = Instance( pentMonster ); - if ( pEntity ) + 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((unsigned long)(pFunction)) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); + if( pFunction && !NAME_FOR_FUNCTION( (unsigned long)( pFunction ) ) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (unsigned long)pFunction ); } BASEPTR ThinkSet( BASEPTR func, char *name ) { m_pfnThink = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); + 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 ); + FunctionCheck( (void *)*( (int *)( (char *)this + ( offsetof( CBaseEntity, m_pfnTouch ) ) ) ), name ); return func; } - USEPTR UseSet( USEPTR func, char *name ) + USEPTR UseSet( USEPTR func, char *name ) { m_pfnUse = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); + FunctionCheck( (void *)*( (int *)( (char *)this + ( offsetof( CBaseEntity, m_pfnUse ) ) ) ), name ); return func; } - ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) + ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) { m_pfnBlocked = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); + 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( 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() ); }; + 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 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 int Illumination() { return GETENTITYILLUM( ENT( pev ) ); }; - virtual BOOL FVisible ( CBaseEntity *pEntity ); - virtual BOOL FVisible ( const Vector &vecOrigin ); + virtual BOOL FVisible( CBaseEntity *pEntity ); + virtual BOOL FVisible( const Vector &vecOrigin ); //We use this variables to store each ammo count. int ammo_9mm; @@ -354,8 +350,6 @@ public: 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. @@ -378,19 +372,16 @@ public: #define ResetUse( ) m_pfnUse = static_cast (NULL) #define ResetBlocked( ) m_pfnBlocked = static_cast (NULL) - #endif - class CPointEntity : public CBaseEntity { public: - void Spawn( void ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + 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 @@ -407,34 +398,34 @@ typedef struct locksounds // sounds that doors and buttons make when locked/un 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); +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 +#define MS_MAX_TARGETS 32 class CMultiSource : public CPointEntity { public: - void Spawn( ); + 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); } + 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[]; + 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]; + EHANDLE m_rgEntities[MS_MAX_TARGETS]; + int m_rgTriggered[MS_MAX_TARGETS]; - int m_iTotal; - string_t m_globalstate; + int m_iTotal; + string_t m_globalstate; }; @@ -444,58 +435,54 @@ public: class CBaseDelay : public CBaseEntity { public: - float m_flDelay; - int m_iszKillTarget; + 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[]; + 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[]; + 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 + 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 ); + 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 ); + 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 + 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. // @@ -671,7 +658,6 @@ class CSound; char *ButtonSound( int sound ); // get string of button sound number - // // Generic Button // @@ -683,29 +669,29 @@ public: void RotSpawn( void ); virtual void KeyValue( KeyValueData* pkvd); - void ButtonActivate( ); + void ButtonActivate(); void SparkSoundCache( void ); void EXPORT ButtonShot( void ); void EXPORT ButtonTouch( CBaseEntity *pOther ); - void EXPORT ButtonSpark ( void ); + 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 ); + 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 ); + 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); } + 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. + 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 @@ -713,17 +699,16 @@ public: 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; + BYTE m_bLockedSound; // ordinals from entity selection + BYTE m_bLockedSentence; + BYTE m_bUnlockedSound; + BYTE m_bUnlockedSentence; + int m_sounds; }; // // Weapons // - #define BAD_WEAPON 0x00007FFF // @@ -735,22 +720,21 @@ template T * GetClassPtr( T *a ) entvars_t *pev = (entvars_t *)a; // allocate entity if necessary - if (pev == NULL) - pev = VARS(CREATE_ENTITY()); + if( pev == NULL ) + pev = VARS( CREATE_ENTITY() ); // get the private data - a = (T *)GET_PRIVATE(ENT(pev)); + a = (T *)GET_PRIVATE( ENT( pev ) ); - if (a == NULL) + if( a == NULL ) { // allocate private data - a = new(pev) T; + a = new( pev ) T; a->pev = pev; } return a; } - /* bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA bit_MONSTER_DATA @@ -778,13 +762,12 @@ push_trigger_data typedef struct _SelAmmo { - BYTE Ammo1Type; - BYTE Ammo1; - BYTE Ammo2Type; - BYTE Ammo2; + BYTE Ammo1Type; + BYTE Ammo1; + BYTE Ammo2Type; + BYTE Ammo2; } SelAmmo; - // this moved here from world.cpp, to allow classes to be derived from it //======================= // CWorld diff --git a/dlls/cdll_dll.h b/dlls/cdll_dll.h index daefd1ee..c960a6ac 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -29,11 +29,11 @@ #define HIDEHUD_WEAPONS ( 1<<0 ) #define HIDEHUD_FLASHLIGHT ( 1<<1 ) -#define HIDEHUD_ALL ( 1<<2 ) -#define HIDEHUD_HEALTH ( 1<<3 ) +#define HIDEHUD_ALL ( 1<<2 ) +#define HIDEHUD_HEALTH ( 1<<3 ) -#define MAX_AMMO_TYPES 32 // ??? -#define MAX_AMMO_SLOTS 32 // not really slots +#define MAX_AMMO_TYPES 32 // ??? +#define MAX_AMMO_SLOTS 32 // not really slots #define HUD_PRINTNOTIFY 1 #define HUD_PRINTCONSOLE 2 @@ -41,6 +41,5 @@ #define HUD_PRINTCENTER 4 -#define WEAPON_SUIT 31 - -#endif \ No newline at end of file +#define WEAPON_SUIT 31 +#endif diff --git a/dlls/client.cpp b/dlls/client.cpp index 14646a32..908769db 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -44,7 +44,7 @@ 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 void CopyToBodyQue( entvars_t* pev ); extern int giPrecacheGrunt; extern int gmsgSayText; @@ -56,16 +56,16 @@ 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) +void set_suicide_frame( entvars_t *pev ) { - if (!FStrEq(STRING(pev->model), "models/player.mdl")) + 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; + //pev->frame = $deatha11; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_TOSS; + pev->deadflag = DEAD_DEAD; + pev->nextthink = -1; } @@ -76,17 +76,15 @@ ClientConnect called when a player connects to a server ============ */ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ +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 (); - +// if( intermission_running ) +// ExitIntermission(); } - /* =========== ClientDisconnect @@ -98,14 +96,14 @@ GLOBALS ASSUMED SET: g_fGameOver */ void ClientDisconnect( edict_t *pEntity ) { - if (g_fGameOver) + 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) ); + if( pEntity->v.netname ) + snprintf( text, sizeof(text), "- %s has left the game\n", STRING( pEntity->v.netname ) ); MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); + WRITE_BYTE( ENTINDEX( pEntity ) ); WRITE_STRING( text ); MESSAGE_END(); @@ -113,38 +111,37 @@ void ClientDisconnect( edict_t *pEntity ) pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); { // since this client isn't around to think anymore, reset their sound. - if ( pSound ) + if( pSound ) { pSound->Reset(); } } -// since the edict doesn't get deleted, fix it so it doesn't interfere. + // 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 ); + UTIL_SetOrigin( &pEntity->v, pEntity->v.origin ); g_pGameRules->ClientDisconnected( pEntity ); } - // called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) +void respawn( entvars_t *pev, BOOL fCopyCorpse ) { - if (gpGlobals->coop || gpGlobals->deathmatch) + if( gpGlobals->coop || gpGlobals->deathmatch ) { - if ( fCopyCorpse ) + if( fCopyCorpse ) { // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); + CopyToBodyQue( pev ); } // respawn player - GetClassPtr( (CBasePlayer *)pev)->Spawn( ); + GetClassPtr( (CBasePlayer *)pev )->Spawn(); } else { // restart the entire server - SERVER_COMMAND("reload\n"); + SERVER_COMMAND( "reload\n" ); } } @@ -161,9 +158,9 @@ void ClientKill( edict_t *pEntity ) { entvars_t *pev = &pEntity->v; - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); + CBasePlayer *pl = (CBasePlayer*)CBasePlayer::Instance( pev ); - if ( pl->m_fNextSuicideTime > gpGlobals->time ) + 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 @@ -172,9 +169,9 @@ void ClientKill( edict_t *pEntity ) pev->health = 0; pl->Killed( pev, GIB_NEVER ); -// pev->modelindex = g_ulModelIndexPlayer; -// pev->frags -= 2; // extra penalty -// respawn( pev ); + //pev->modelindex = g_ulModelIndexPlayer; + //pev->frags -= 2; // extra penalty + //respawn( pev ); } /* @@ -190,21 +187,19 @@ void ClientPutInServer( edict_t *pEntity ) entvars_t *pev = &pEntity->v; - pPlayer = GetClassPtr((CBasePlayer *)pev); - pPlayer->SetCustomDecalFrames(-1); // Assume none; + pPlayer = GetClassPtr( (CBasePlayer *)pev ); + pPlayer->SetCustomDecalFrames( -1 ); // Assume none; // Allocate a CBasePlayer for pev, and call spawn - pPlayer->Spawn() ; + pPlayer->Spawn(); // Reset interpolation during first frame pPlayer->pev->effects |= EF_NOINTERP; pPlayer->pev->iuser1 = 0; pPlayer->pev->iuser2 = 0; - } - #ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; @@ -224,22 +219,22 @@ void Host_Say( edict_t *pEntity, int teamonly ) char szTemp[256]; const char *cpSay = "say"; const char *cpSayTeam = "say_team"; - const char *pcmd = CMD_ARGV(0); + const char *pcmd = CMD_ARGV( 0 ); // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) + if( CMD_ARGC() == 0 ) return; entvars_t *pev = &pEntity->v; - CBasePlayer* player = GetClassPtr((CBasePlayer *)pev); + CBasePlayer* player = GetClassPtr( (CBasePlayer *)pev ); //Not yet. - if ( player->m_flNextChatTime > gpGlobals->time ) + if( player->m_flNextChatTime > gpGlobals->time ) return; - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) + if( !stricmp( pcmd, cpSay ) || !stricmp( pcmd, cpSayTeam ) ) { - if ( CMD_ARGC() >= 2 ) + if( CMD_ARGC() >= 2 ) { p = (char *)CMD_ARGS(); } @@ -251,51 +246,50 @@ void Host_Say( edict_t *pEntity, int teamonly ) } else // Raw text, need to prepend argv[0] { - if ( CMD_ARGC() >= 2 ) + if( CMD_ARGC() >= 2 ) { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); + 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 ); + sprintf( szTemp, "%s", (char *)pcmd ); } p = szTemp; } -// remove quotes if present - if (*p == '"') + // remove quotes if present + if( *p == '"' ) { p++; - p[strlen(p)-1] = 0; + p[strlen( p ) - 1] = 0; } -// make sure the text has content - for ( pc = p; pc != NULL && *pc != 0; pc++ ) + // make sure the text has content + for( pc = p; pc != NULL && *pc != 0; pc++ ) { - if ( !isspace( *pc ) ) + if( !isspace( *pc ) ) { pc = NULL; // we've found an alphanumeric character, so text is valid break; } } - if ( pc != NULL ) + if( pc != NULL ) return; // no character found, so say nothing -// turn on color set 2 (color on, no sound) - if ( teamonly ) + // turn on color set 2 (color on, no sound) + 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 ) + 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 @@ -304,50 +298,47 @@ void Host_Say( edict_t *pEntity, int teamonly ) // so check it, or it will infinite loop client = NULL; - while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) + while( ( ( client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" ) ) != NULL ) && ( !FNullEnt( client->edict() ) ) ) { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) + if( !client->pev ) continue; - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) + if( client->edict() == pEntity ) continue; + if( !( client->IsNetClient() ) ) // Not a client ? (should never be true) + continue; #ifndef NO_VOICEGAMEMGR // can the receiver hear the sender? or has he muted him? - if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) + if( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) continue; #endif - - if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) + if( teamonly && g_pGameRules->PlayerRelationship( client, CBaseEntity::Instance( pEntity ) ) != GR_TEAMMATE ) continue; MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); - WRITE_BYTE( ENTINDEX(pEntity) ); + 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_BYTE( ENTINDEX( pEntity ) ); WRITE_STRING( text ); MESSAGE_END(); // echo to server console g_engfuncs.pfnServerPrint( text ); - char * temp; - if ( teamonly ) + char *temp; + if( teamonly ) temp = "say_team"; else temp = "say"; - + // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", STRING( pEntity->v.netname ), @@ -369,7 +360,6 @@ void Host_Say( edict_t *pEntity, int teamonly ) } } - /* =========== ClientCommand @@ -381,106 +371,106 @@ 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 *pcmd = CMD_ARGV( 0 ); const char *pstr; // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) + if( !pEntity->pvPrivateData ) return; entvars_t *pev = &pEntity->v; - if ( FStrEq(pcmd, "say" ) ) + if( FStrEq( pcmd, "say" ) ) { Host_Say( pEntity, 0 ); } - else if ( FStrEq(pcmd, "say_team" ) ) + else if( FStrEq( pcmd, "say_team" ) ) { Host_Say( pEntity, 1 ); } - else if ( FStrEq(pcmd, "fullupdate" ) ) + else if( FStrEq( pcmd, "fullupdate" ) ) { - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); + GetClassPtr( (CBasePlayer *)pev )->ForceClientDllUpdate(); } - else if ( FStrEq(pcmd, "give" ) ) + else if( FStrEq(pcmd, "give" ) ) { - if ( g_flWeaponCheat != 0.0) + if( g_flWeaponCheat != 0.0 ) { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); + int iszItem = ALLOC_STRING( CMD_ARGV( 1 ) ); // Make a copy of the classname + GetClassPtr( (CBasePlayer *)pev )->GiveNamedItem( STRING( iszItem ) ); } } - else if ( FStrEq(pcmd, "fire") ) + else if( FStrEq( pcmd, "fire" ) ) { - if ( g_flWeaponCheat != 0.0) + if( g_flWeaponCheat != 0.0 ) { - CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); - if (CMD_ARGC() > 1) + CBaseEntity *pPlayer = CBaseEntity::Instance( pEntity ); + if( CMD_ARGC() > 1 ) { - FireTargets(CMD_ARGV(1), pPlayer, pPlayer, USE_TOGGLE, 0); + FireTargets( CMD_ARGV( 1 ), pPlayer, pPlayer, USE_TOGGLE, 0 ); } else { TraceResult tr; - UTIL_MakeVectors(pev->v_angle); + UTIL_MakeVectors( pev->v_angle ); UTIL_TraceLine( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 1000, dont_ignore_monsters, pEntity, &tr ); - if (tr.pHit) + if( tr.pHit ) { - CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); - if (pHitEnt) + CBaseEntity *pHitEnt = CBaseEntity::Instance( tr.pHit ); + if( pHitEnt ) { - pHitEnt->Use(pPlayer, pPlayer, USE_TOGGLE, 0); - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); + pHitEnt->Use( pPlayer, pPlayer, USE_TOGGLE, 0 ); + ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING( pHitEnt->pev->classname ), STRING( pHitEnt->pev->targetname ) ) ); } } } } } - else if ( FStrEq(pcmd, "drop" ) ) + else if( FStrEq( pcmd, "drop" ) ) { // player is dropping an item. - GetClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1)); + GetClassPtr( (CBasePlayer *)pev )->DropPlayerItem( (char *)CMD_ARGV( 1 ) ); } - else if ( FStrEq(pcmd, "fov" ) ) + else if( FStrEq( pcmd, "fov" ) ) { - if ( g_flWeaponCheat && CMD_ARGC() > 1) + if( g_flWeaponCheat && CMD_ARGC() > 1 ) { - GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(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 ) ); + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr( (CBasePlayer *)pev )->m_iFOV ) ); } } - else if ( FStrEq(pcmd, "use" ) ) + else if( FStrEq( pcmd, "use" ) ) { - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); + GetClassPtr( (CBasePlayer *)pev )->SelectItem( (char *)CMD_ARGV( 1 ) ); } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) + else if( ( ( pstr = strstr( pcmd, "weapon_" ) ) != NULL ) && ( pstr == pcmd ) ) { - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); + GetClassPtr( (CBasePlayer *)pev )->SelectItem( pcmd ); } - else if (FStrEq(pcmd, "lastinv" )) + else if( FStrEq( pcmd, "lastinv" ) ) { - GetClassPtr((CBasePlayer *)pev)->SelectLastItem(); + GetClassPtr( (CBasePlayer *)pev )->SelectLastItem(); } - else if ( FStrEq( pcmd, "spectate" ) && (pev->flags & FL_PROXY) ) // added for proxy support + else if( FStrEq( pcmd, "spectate" ) && ( pev->flags & FL_PROXY ) ) // added for proxy support { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); + CBasePlayer * pPlayer = GetClassPtr( (CBasePlayer *)pev ); edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); + pPlayer->StartObserver( pev->origin, VARS( pentSpawnSpot )->angles ); } - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) + /*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 if ( FStrEq(pcmd, "VModEnable") ) + }*/ + else if( FStrEq( pcmd, "VModEnable" ) ) { // clear 'Unknown command: VModEnable' in singleplayer return; @@ -500,7 +490,6 @@ void ClientCommand( edict_t *pEntity ) } } - /* ======================== ClientUserInfoChanged @@ -513,37 +502,37 @@ it gets sent into the rest of the engine. void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) { // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) + 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" )) ) + 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'; + sName[sizeof(sName) - 1] = '\0'; // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) + for( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) { // Replace it with a space - if ( *pApersand == '%' ) + if( *pApersand == '%' ) *pApersand = ' '; } // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); + g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pEntity ), infobuffer, "name", sName ); char text[256]; - snprintf( text, 256, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + snprintf( text, 256, "* %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_BYTE( ENTINDEX( pEntity ) ); WRITE_STRING( text ); MESSAGE_END(); // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", STRING( pEntity->v.netname ), @@ -563,18 +552,18 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) } } - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); + g_pGameRules->ClientUserInfoChanged( GetClassPtr( (CBasePlayer *)&pEntity->v ), infobuffer ); } static int g_serveractive = 0; void ServerDeactivate( void ) { -// ALERT( at_console, "ServerDeactivate()\n" ); + //ALERT( at_console, "ServerDeactivate()\n" ); // 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 ) + if( g_serveractive != 1 ) { return; } @@ -587,33 +576,33 @@ void ServerDeactivate( void ) void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) { - int i; - CBaseEntity *pClass; + int i; + CBaseEntity *pClass; -// ALERT( at_console, "ServerActivate()\n" ); + //ALERT( at_console, "ServerActivate()\n" ); // 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++ ) + for( i = 0; i < edictCount; i++ ) { - if ( pEdictList[i].free ) + if( pEdictList[i].free ) continue; - + // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) + 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) ) + if( pClass && !( pClass->pev->flags & FL_DORMANT ) ) { pClass->Activate(); } else { - ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); + ALERT( at_console, "Can't instance %s\n", STRING( pEdictList[i].v.classname ) ); } } @@ -621,7 +610,6 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) LinkUserMessages(); } - /* ================ PlayerPreThink @@ -631,13 +619,13 @@ Called every frame before physics are run */ void PlayerPreThink( edict_t *pEntity ) { -// ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + //ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); - if (pPlayer) - pPlayer->PreThink( ); + if( pPlayer ) + pPlayer->PreThink(); } /* @@ -649,43 +637,39 @@ Called every frame after physics are run */ void PlayerPostThink( edict_t *pEntity ) { -// ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + //ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); - if (pPlayer) - pPlayer->PostThink( ); + if( pPlayer ) + pPlayer->PostThink(); } - - void ParmsNewLevel( void ) { } - void ParmsChangeLevel( void ) { // retrieve the pointer to the save data SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - if ( pSaveData ) + if( pSaveData ) pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); } - // // GLOBALS ASSUMED SET: g_ulFrameCount // void StartFrame( void ) { -// ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + //ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - if ( g_pGameRules ) + if( g_pGameRules ) g_pGameRules->Think(); - if ( g_fGameOver ) + if( g_fGameOver ) return; gpGlobals->teamplay = teamplay.value; @@ -696,116 +680,113 @@ void StartFrame( void ) 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( "player/sprayer.wav" ); // spray paint sound for PreAlpha - 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_jumpland2.wav" ); // UNDONE: play 2x step sound - 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_fallpain2.wav" ); + PRECACHE_SOUND( "player/pl_fallpain3.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_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("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( "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_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_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_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_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_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_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_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_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_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_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_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( "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("debris/wood1.wav"); // hit wood texture - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.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("plats/train_use1.wav"); // use a train + 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("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( "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 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"); + // 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"); + 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"); - + 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" ); - 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"); + if( giPrecacheGrunt ) + UTIL_PrecacheOther( "monster_human_grunt" ); } /* @@ -817,7 +798,7 @@ 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 + 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"; @@ -847,24 +828,24 @@ animation right now. void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) { entvars_t *pev = &pEntity->v; - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); + CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); - if (!pPlayer) + if( !pPlayer ) { - ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); + ALERT( at_console, "PlayerCustomization: Couldn't get player!\n" ); return; } - if (!pCust) + if( !pCust ) { - ALERT(at_console, "PlayerCustomization: NULL customization!\n"); + ALERT( at_console, "PlayerCustomization: NULL customization!\n" ); return; } - switch (pCust->resource.type) + switch( pCust->resource.type ) { case t_decal: - pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. + pPlayer->SetCustomDecalFrames( pCust->nUserData2 ); // Second int is max # of frames. break; case t_sound: case t_skin: @@ -872,7 +853,7 @@ void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) // Ignore for now. break; default: - ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); + ALERT( at_console, "PlayerCustomization: Unknown customization type!\n" ); break; } } @@ -887,10 +868,10 @@ A spectator has joined the game void SpectatorConnect( edict_t *pEntity ) { entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - if (pPlayer) - pPlayer->SpectatorConnect( ); + if( pPlayer ) + pPlayer->SpectatorConnect(); } /* @@ -903,10 +884,10 @@ A spectator has left the game void SpectatorDisconnect( edict_t *pEntity ) { entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - if (pPlayer) - pPlayer->SpectatorDisconnect( ); + if( pPlayer ) + pPlayer->SpectatorDisconnect(); } /* @@ -919,10 +900,10 @@ A spectator has sent a usercmd void SpectatorThink( edict_t *pEntity ) { entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); + CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); - if (pPlayer) - pPlayer->SpectatorThink( ); + if( pPlayer ) + pPlayer->SpectatorThink(); } //////////////////////////////////////////////////////// @@ -949,12 +930,12 @@ void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pv edict_t *pView = pClient; // Find the client's PVS - if ( pViewEntity ) + if( pViewEntity ) { pView = pViewEntity; } - if ( pClient->v.flags & FL_PROXY ) + if( pClient->v.flags & FL_PROXY ) { *pvs = NULL; // the spectator proxy sees *pas = NULL; // and hears everything @@ -963,7 +944,7 @@ void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pv if( pView->v.effects & EF_MERGE_VISIBILITY ) { - if( FClassnameIs( pView, "env_sky" )) + if( FClassnameIs( pView, "env_sky" ) ) { org = pView->v.origin; } @@ -972,14 +953,14 @@ void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pv else { org = pView->v.origin + pView->v.view_ofs; - if ( pView->v.flags & FL_DUCKING ) + 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 ); + *pvs = ENGINE_SET_PVS( (float *)&org ); + *pas = ENGINE_SET_PAS( (float *)&org ); } #include "entity_state.h" @@ -999,61 +980,61 @@ we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. */ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) { - int i; + 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 ) ) + if( ( ent->v.effects == EF_NODRAW ) && ( ent != host ) ) return 0; // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model ) ) + 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 ) ) + 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( ent != host ) { - if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) + if( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) { // env_sky is visible always - if( !FClassnameIs( ent, "env_sky" )) + if( !FClassnameIs( ent, "env_sky" ) ) { 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( ent->v.flags & FL_SKIPLOCALHOST ) { - if ( hostflags & 4 ) return 0; // it's a portal pass - if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) + if( hostflags & 4 ) + return 0; // it's a portal pass + + if( ( hostflags & 1 ) && ( ent->v.owner == host ) ) return 0; } - if ( host->v.groupinfo ) + if( host->v.groupinfo ) { UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); // Should always be set, of course - if ( ent->v.groupinfo ) + if( ent->v.groupinfo ) { - if ( g_groupop == GROUP_OP_AND ) + if( g_groupop == GROUP_OP_AND ) { - if ( !(ent->v.groupinfo & host->v.groupinfo ) ) + if( !( ent->v.groupinfo & host->v.groupinfo ) ) return 0; } - else if ( g_groupop == GROUP_OP_NAND ) + else if( g_groupop == GROUP_OP_NAND ) { - if ( ent->v.groupinfo & host->v.groupinfo ) + if( ent->v.groupinfo & host->v.groupinfo ) return 0; } } @@ -1061,15 +1042,15 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h UTIL_UnsetGroupTrace(); } - memset( state, 0, sizeof( *state ) ); + 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->number = e; state->entityType = ENTITY_NORMAL; - + // Flag custom entities. - if ( ent->v.flags & FL_CUSTOMENTITY ) + if( ent->v.flags & FL_CUSTOMENTITY ) { state->entityType = ENTITY_BEAM; } @@ -1079,109 +1060,109 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h // // Round animtime to nearest millisecond - state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; + 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->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 ) ); - memcpy( state->velocity, ent->v.velocity, 3 * sizeof( float ) ); + memcpy( state->startpos, ent->v.startpos, 3 * sizeof(float) ); + memcpy( state->endpos, ent->v.endpos, 3 * sizeof(float) ); + memcpy( state->velocity, ent->v.velocity, 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; + 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 && + if( !player && ent->v.animtime && - ent->v.velocity[ 0 ] == 0 && - ent->v.velocity[ 1 ] == 0 && - ent->v.velocity[ 2 ] == 0 ) + 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->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; + 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++) + for( i = 0; i < 4; i++ ) { state->controller[i] = ent->v.controller[i]; } - for (i = 0; i < 2; i++) + for( i = 0; i < 2; i++ ) { - state->blending[i] = ent->v.blending[i]; + state->blending[i] = ent->v.blending[i]; } - state->rendermode = ent->v.rendermode; - state->renderamt = ent->v.renderamt; - state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor.x; - state->rendercolor.g = ent->v.rendercolor.y; - state->rendercolor.b = ent->v.rendercolor.z; + state->rendermode = ent->v.rendermode; + state->renderamt = ent->v.renderamt; + state->renderfx = ent->v.renderfx; + state->rendercolor.r = ent->v.rendercolor.x; + state->rendercolor.g = ent->v.rendercolor.y; + state->rendercolor.b = ent->v.rendercolor.z; state->aiment = 0; - if ( ent->v.aiment ) + if( ent->v.aiment ) { state->aiment = ENTINDEX( ent->v.aiment ); } state->owner = 0; - if ( ent->v.owner ) + if( ent->v.owner ) { int owner = ENTINDEX( ent->v.owner ); - + // Only care if owned by a player - if ( owner >= 1 && owner <= gpGlobals->maxClients ) + if( owner >= 1 && owner <= gpGlobals->maxClients ) { state->owner = owner; } } state->onground = 0; - if ( ent->v.groundentity ) + if( ent->v.groundentity ) { state->onground = ENTINDEX( ent->v.groundentity ); } // HACK: Somewhat... // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) - if ( !player ) + if( !player ) { state->playerclass = ent->v.playerclass; } // Special stuff for players only - if ( player ) + if( player ) { - memcpy( state->basevelocity, ent->v.basevelocity, 3 * sizeof( float ) ); + 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->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->gravity = ent->v.gravity; + //state->team = ent->v.team; + + state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; state->health = ent->v.health; } @@ -1206,49 +1187,49 @@ void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, st baseline->skin = (short)entity->v.skin; // render information - baseline->rendermode = (byte)entity->v.rendermode; + 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->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 ) + if( player ) { - baseline->mins = player_mins; - baseline->maxs = player_maxs; + baseline->mins = player_mins; + baseline->maxs = player_maxs; - baseline->colormap = eindex; + baseline->colormap = eindex; baseline->modelindex = playermodelindex; - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; + 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; + 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->mins = entity->v.mins; + baseline->maxs = entity->v.maxs; - baseline->colormap = 0; + baseline->colormap = 0; baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); - baseline->movetype = entity->v.movetype; + 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; + 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; + int field; } entity_field_alias_t; #define FIELD_ORIGIN0 0 @@ -1258,7 +1239,7 @@ typedef struct #define FIELD_ANGLES1 4 #define FIELD_ANGLES2 5 -static entity_field_alias_t entity_field_alias[]= +static entity_field_alias_t entity_field_alias[] = { { "origin[0]", 0 }, { "origin[1]", 0 }, @@ -1270,12 +1251,12 @@ static entity_field_alias_t entity_field_alias[]= 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_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 ); } /* @@ -1292,7 +1273,7 @@ void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const un int localplayer = 0; static int initialized = 0; - if ( !initialized ) + if( !initialized ) { Entity_FieldInit( pFields ); initialized = 1; @@ -1302,41 +1283,41 @@ void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const un 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 ) + 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 ); + 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 ) ) + 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_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 ); + 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 ) ) + 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 ); + 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 ) + 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 ); + 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[]= +static entity_field_alias_t player_field_alias[] = { { "origin[0]", 0 }, { "origin[1]", 0 }, @@ -1345,9 +1326,9 @@ static entity_field_alias_t player_field_alias[]= 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_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 ); } /* @@ -1363,7 +1344,7 @@ void Player_Encode( struct delta_s *pFields, const unsigned char *from, const un int localplayer = 0; static int initialized = 0; - if ( !initialized ) + if( !initialized ) { Player_FieldInit( pFields ); initialized = 1; @@ -1373,26 +1354,26 @@ void Player_Encode( struct delta_s *pFields, const unsigned char *from, const un 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 ) + localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); + if( localplayer ) { - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN0].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN1].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN2].field ); } - if ( ( t->movetype == MOVETYPE_FOLLOW ) && + if( ( t->movetype == MOVETYPE_FOLLOW ) && ( t->aiment != 0 ) ) { - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN0].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN1].field ); + DELTA_UNSETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN2].field ); } - else if ( t->aiment != f->aiment ) + else if( t->aiment != f->aiment ) { - DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, player_field_alias[ FIELD_ORIGIN2 ].field ); + DELTA_SETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN0].field ); + DELTA_SETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN1].field ); + DELTA_SETBYINDEX( pFields, player_field_alias[FIELD_ORIGIN2].field ); } } @@ -1403,10 +1384,10 @@ void Player_Encode( struct delta_s *pFields, const unsigned char *from, const un #define CUSTOMFIELD_ANGLES1 4 #define CUSTOMFIELD_ANGLES2 5 #define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 +#define CUSTOMFIELD_SEQUENCE 7 +#define CUSTOMFIELD_ANIMTIME 8 -entity_field_alias_t custom_entity_field_alias[]= +entity_field_alias_t custom_entity_field_alias[] = { { "origin[0]", 0 }, { "origin[1]", 0 }, @@ -1414,22 +1395,22 @@ entity_field_alias_t custom_entity_field_alias[]= { "angles[0]", 0 }, { "angles[1]", 0 }, { "angles[2]", 0 }, - { "skin", 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_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 ); } /* @@ -1446,7 +1427,7 @@ void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const un int beamType; static int initialized = 0; - if ( !initialized ) + if( !initialized ) { Custom_Entity_FieldInit( pFields ); initialized = 1; @@ -1456,32 +1437,32 @@ void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const un t = (entity_state_t *)to; beamType = t->rendermode & 0x0f; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) + + 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 ); + 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 ) + 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 ); + 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 ) + 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 ); + 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 ) + if( (int)f->animtime == (int)t->animtime ) { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[CUSTOMFIELD_ANIMTIME].field ); } } @@ -1505,54 +1486,53 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) int i; weapon_data_t *item; entvars_t *pev = &player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); CBasePlayerWeapon *gun; - + ItemInfo II; - memset( info, 0, 32 * sizeof( weapon_data_t ) ); + memset( info, 0, 32 * sizeof(weapon_data_t) ); - if ( !pl ) + 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++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( pl->m_rgpPlayerItems[ i ] ) + if( pl->m_rgpPlayerItems[i] ) { // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; + CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[i]; - while ( pPlayerItem ) + while( pPlayerItem ) { gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) + if( gun && gun->UseDecrement() ) { // Get The ID. - memset( &II, 0, sizeof( II ) ); + memset( &II, 0, sizeof(II) ); gun->GetItemInfo( &II ); - if ( II.iId >= 0 && II.iId < 32 ) + if( II.iId >= 0 && II.iId < 32 ) { - item = &info[ II.iId ]; + item = &info[II.iId]; - item->m_iId = II.iId; - item->m_iClip = gun->m_iClip; + 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_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 ); + 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; @@ -1560,7 +1540,7 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) } } #else - memset( info, 0, 32 * sizeof( weapon_data_t ) ); + memset( info, 0, 32 * sizeof(weapon_data_t) ); #endif return 1; } @@ -1573,25 +1553,25 @@ Data sent to current client only engine sets cd to 0 before calling. ================= */ -void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) { - cd->flags = ent->v.flags; - cd->health = ent->v.health; + cd->flags = ent->v.flags; + cd->health = ent->v.health; cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); cd->waterlevel = ent->v.waterlevel; cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; + cd->weapons = ent->v.weapons; // Vectors - cd->origin = ent->v.origin; + cd->origin = ent->v.origin; cd->velocity = ent->v.velocity; cd->view_ofs = ent->v.view_ofs; cd->punchangle = ent->v.punchangle; - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; + cd->bInDuck = ent->v.bInDuck; + cd->flTimeStepSound = ent->v.flTimeStepSound; cd->flDuckTime = ent->v.flDuckTime; cd->flSwimTime = ent->v.flSwimTime; cd->waterjumptime = ent->v.teleport_time; @@ -1599,53 +1579,52 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; + cd->fov = ent->v.fov; cd->weaponanim = ent->v.weaponanim; cd->pushmsec = ent->v.pushmsec; #if defined( CLIENT_WEAPONS ) - if ( sendweapons ) + if( sendweapons ) { entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); - if ( pl ) + 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; - + 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 ) + if( pl->m_pActiveItem ) { CBasePlayerWeapon *gun; gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) + if( gun && gun->UseDecrement() ) { ItemInfo II; - memset( &II, 0, sizeof( 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->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; + cd->vuser2.y = ( (CRpg *)pl->m_pActiveItem )->m_fSpotActive; + cd->vuser2.z = ( (CRpg *)pl->m_pActiveItem )->m_cActiveRockets; } } } @@ -1665,12 +1644,12 @@ This is the time to examine the usercmd for anything extra. This call happens e void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) { entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); if( !pl ) return; - if ( pl->pev->groupinfo != 0 ) + if( pl->pev->groupinfo != 0 ) { UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); } @@ -1685,14 +1664,14 @@ CmdEnd Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here ================= */ -void CmdEnd ( const edict_t *player ) +void CmdEnd( const edict_t *player ) { entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); if( !pl ) return; - if ( pl->pev->groupinfo != 0 ) + if( pl->pev->groupinfo != 0 ) { UTIL_UnsetGroupTrace(); } @@ -1706,7 +1685,7 @@ ConnectionlessPacket 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 ) +int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) { // Parse stuff from args int max_buffer_size = *response_buffer_size; @@ -1731,7 +1710,7 @@ int GetHullBounds( int hullnumber, float *mins, float *maxs ) { int iret = 0; - switch ( hullnumber ) + switch( hullnumber ) { case 0: // Normal player mins = VEC_HULL_MIN; @@ -1761,12 +1740,12 @@ Create pseudo-baselines for items that aren't placed in the map at spawn time, b to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) ================================ */ -void CreateInstancedBaselines ( void ) +void CreateInstancedBaselines( void ) { int iret = 0; entity_state_t state; - memset( &state, 0, sizeof( state ) ); + memset( &state, 0, sizeof(state) ); // Create any additional baselines here for things like grendates, etc. // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); @@ -1783,10 +1762,10 @@ One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the sp 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 ) +int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) { // Server doesn't care? - if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) + if( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) return 0; // Default behavior is to kick the player diff --git a/dlls/client.h b/dlls/client.h index 1e66cc89..6728151b 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -15,7 +15,7 @@ #ifndef CLIENT_H #define CLIENT_H -extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); +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 ); @@ -35,31 +35,30 @@ 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 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 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 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 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 void CreateInstancedBaselines( void ); -extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); +extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); extern int AllowLagCompensation( void ); - -#endif // CLIENT_H +#endif // CLIENT_H diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 5d7679fd..3a59844f 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -33,7 +33,7 @@ extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL int g_iSkillLevel; -extern Vector VecBModelOrigin( entvars_t* pevBModel ); +extern Vector VecBModelOrigin( entvars_t *pevBModel ); extern entvars_t *g_pevLastInflictor; #define GERMAN_GIB_COUNT 4 @@ -42,67 +42,67 @@ extern entvars_t *g_pevLastInflictor; // HACKHACK -- The gib velocity equations don't work -void CGib :: LimitVelocity( void ) +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 ) + 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 ) +void CGib::SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ) { int i; - if ( g_Language == LANGUAGE_GERMAN ) + if( g_Language == LANGUAGE_GERMAN ) { // no sticky gibs in germany right now! return; } - for ( i = 0 ; i < cGibs ; i++ ) + for( i = 0; i < cGibs; i++ ) { CGib *pGib = GetClassPtr( (CGib *)NULL ); pGib->Spawn( "models/stickygib.mdl" ); - pGib->pev->body = RANDOM_LONG(0,2); + pGib->pev->body = RANDOM_LONG( 0, 2 ); - if ( pevVictim ) + 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 ) ); + 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.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 ); + 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->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor(); + + if( pevVictim->health > -50 ) { pGib->pev->velocity = pGib->pev->velocity * 0.7; } - else if ( pevVictim->health > -200) + else if( pevVictim->health > -200 ) { pGib->pev->velocity = pGib->pev->velocity * 2; } @@ -111,10 +111,9 @@ void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs 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 ) ); + UTIL_SetSize( pGib->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); pGib->SetTouch( &CGib::StickyGibTouch ); pGib->SetThink( NULL ); } @@ -122,11 +121,11 @@ void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs } } -void CGib :: SpawnHeadGib( entvars_t *pevVictim ) +void CGib::SpawnHeadGib( entvars_t *pevVictim ) { CGib *pGib = GetClassPtr( (CGib *)NULL ); - if ( g_Language == LANGUAGE_GERMAN ) + if( g_Language == LANGUAGE_GERMAN ) { pGib->Spawn( "models/germangibs.mdl" );// throw one head pGib->pev->body = 0; @@ -137,16 +136,16 @@ void CGib :: SpawnHeadGib( entvars_t *pevVictim ) pGib->pev->body = 0; } - if ( pevVictim ) + 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 ) + + 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; + entvars_t *pevPlayer; pevPlayer = VARS( pentPlayer ); pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; @@ -154,21 +153,20 @@ void CGib :: SpawnHeadGib( entvars_t *pevVictim ) } else { - pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + 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 ); + 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->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor(); + + if( pevVictim->health > -50 ) { pGib->pev->velocity = pGib->pev->velocity * 0.7; } - else if ( pevVictim->health > -200) + else if( pevVictim->health > -200 ) { pGib->pev->velocity = pGib->pev->velocity * 2; } @@ -180,36 +178,36 @@ void CGib :: SpawnHeadGib( entvars_t *pevVictim ) pGib->LimitVelocity(); } -void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) +void CGib::SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) { int cSplat; - for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ ) + for( cSplat = 0; cSplat < cGibs; cSplat++ ) { CGib *pGib = GetClassPtr( (CGib *)NULL ); - if ( g_Language == LANGUAGE_GERMAN ) + if( g_Language == LANGUAGE_GERMAN ) { pGib->Spawn( "models/germangibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,GERMAN_GIB_COUNT-1); + pGib->pev->body = RANDOM_LONG( 0, GERMAN_GIB_COUNT - 1 ); } else { - if ( human ) + 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) + 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); + pGib->pev->body = RANDOM_LONG( 0, ALIEN_GIB_COUNT - 1 ); } } - if ( pevVictim ) + 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 ) ); @@ -220,23 +218,23 @@ void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) 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.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->velocity = pGib->pev->velocity * RANDOM_FLOAT( 300, 400 ); - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 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->m_bloodColor = ( CBaseEntity::Instance( pevVictim ) )->BloodColor(); + + if( pevVictim->health > -50 ) { pGib->pev->velocity = pGib->pev->velocity * 0.7; } - else if ( pevVictim->health > -200) + else if( pevVictim->health > -200 ) { pGib->pev->velocity = pGib->pev->velocity * 2; } @@ -246,45 +244,42 @@ void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) } pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector( 0 , 0 , 0 ), Vector ( 0, 0, 0 ) ); + UTIL_SetSize( pGib->pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); } pGib->LimitVelocity(); } } - -BOOL CBaseMonster :: HasHumanGibs( void ) +BOOL CBaseMonster::HasHumanGibs( void ) { int myClass = Classify(); - if ( myClass == CLASS_HUMAN_MILITARY || - myClass == CLASS_PLAYER_ALLY || - myClass == CLASS_HUMAN_PASSIVE || - myClass == CLASS_PLAYER ) + if( myClass == CLASS_HUMAN_MILITARY || + myClass == CLASS_PLAYER_ALLY || + myClass == CLASS_HUMAN_PASSIVE || + myClass == CLASS_PLAYER ) return TRUE; return FALSE; } - -BOOL CBaseMonster :: HasAlienGibs( void ) +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 ) + 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 TRUE; return FALSE; } - void CBaseMonster::FadeMonster( void ) { StopAnimation(); @@ -300,35 +295,35 @@ void CBaseMonster::FadeMonster( void ) // GibMonster - create some gore and get rid of a monster's // model. //========================================================= -void CBaseMonster :: GibMonster( void ) +void CBaseMonster::GibMonster( void ) { TraceResult tr; BOOL gibbed = FALSE; - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); + 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( HasHumanGibs() ) { - if ( CVAR_GET_FLOAT("violence_hgibs") != 0 ) // Only the player will ever get here + 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() ) + else if( HasAlienGibs() ) { - if ( CVAR_GET_FLOAT("violence_agibs") != 0 ) // Should never get here, but someone might call it directly + 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( !IsPlayer() ) { - if ( gibbed ) + if( gibbed ) { // don't remove players! SetThink( &CBaseEntity::SUB_Remove ); @@ -345,7 +340,7 @@ void CBaseMonster :: GibMonster( void ) // GetDeathActivity - determines the best type of death // anim to play. //========================================================= -Activity CBaseMonster :: GetDeathActivity ( void ) +Activity CBaseMonster::GetDeathActivity( void ) { Activity deathActivity; BOOL fTriedDirection; @@ -353,7 +348,7 @@ Activity CBaseMonster :: GetDeathActivity ( void ) TraceResult tr; Vector vecSrc; - if ( pev->deadflag != DEAD_NO ) + if( pev->deadflag != DEAD_NO ) { // don't run this while dying. return m_IdealActivity; @@ -364,55 +359,50 @@ Activity CBaseMonster :: GetDeathActivity ( void ) 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 ); + UTIL_MakeVectors( pev->angles ); + flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1 ); - switch ( m_LastHitGroup ) + 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 ) + if( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } - else if ( flDot <= -0.3 ) + 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 ) + if( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } - else if ( flDot <= -0.3 ) + else if( flDot <= -0.3 ) { deathActivity = ACT_DIEBACKWARD; } break; } - // can we perform the prescribed death? - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) { // no! did we fail to perform a directional death? - if ( fTriedDirection ) + if( fTriedDirection ) { // if yes, we're out of options. Go simple. deathActivity = ACT_DIESIMPLE; @@ -420,43 +410,43 @@ Activity CBaseMonster :: GetDeathActivity ( void ) else { // cannot perform the ideal region-specific death, so try a direction. - if ( flDot > 0.3 ) + if( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } - else if ( flDot <= -0.3 ) + else if( flDot <= -0.3 ) { deathActivity = ACT_DIEBACKWARD; } } } - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) { // if we're still invalid, simple is our only option. deathActivity = ACT_DIESIMPLE; } - if ( deathActivity == ACT_DIEFORWARD ) + 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 ); + // 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( tr.flFraction != 1.0 ) + { + deathActivity = ACT_DIESIMPLE; + } } - if ( deathActivity == ACT_DIEBACKWARD ) + 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 ); + // 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; - } + if( tr.flFraction != 1.0 ) + { + deathActivity = ACT_DIESIMPLE; + } } return deathActivity; @@ -466,17 +456,17 @@ Activity CBaseMonster :: GetDeathActivity ( void ) // GetSmallFlinchActivity - determines the best type of flinch // anim to play. //========================================================= -Activity CBaseMonster :: GetSmallFlinchActivity ( void ) +Activity CBaseMonster::GetSmallFlinchActivity( void ) { Activity flinchActivity; BOOL fTriedDirection; float flDot; fTriedDirection = FALSE; - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) + UTIL_MakeVectors( pev->angles ); + flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1 ); + + switch( m_LastHitGroup ) { // pick a region-specific flinch case HITGROUP_HEAD: @@ -504,9 +494,8 @@ Activity CBaseMonster :: GetSmallFlinchActivity ( void ) break; } - // do we have a sequence for the ideal activity? - if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) { flinchActivity = ACT_SMALL_FLINCH; } @@ -518,7 +507,7 @@ Activity CBaseMonster :: GetSmallFlinchActivity ( void ) 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. @@ -531,35 +520,33 @@ void CBaseMonster::BecomeDead( void ) //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 ) ) + 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( HasHumanGibs() ) { - if ( CVAR_GET_FLOAT("violence_hgibs") == 0 ) + if( CVAR_GET_FLOAT( "violence_hgibs" ) == 0 ) fade = TRUE; } - else if ( HasAlienGibs() ) + else if( HasAlienGibs() ) { - if ( CVAR_GET_FLOAT("violence_agibs") == 0 ) + 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 ) + if( fade ) { FadeMonster(); } @@ -573,29 +560,28 @@ void CBaseMonster::CallGibMonster( void ) FCheckAITrigger(); // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) + if( pev->health < -99 ) { pev->health = 0; } - - if ( ShouldFadeOnDeath() && !fade ) - UTIL_Remove(this); -} + if( ShouldFadeOnDeath() && !fade ) + UTIL_Remove( this ); +} /* ============ Killed ============ */ -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) +void CBaseMonster::Killed( entvars_t *pevAttacker, int iGib ) { unsigned int cCount = 0; - BOOL fDone = FALSE; + BOOL fDone = FALSE; - if ( HasMemory( bits_MEMORY_KILLED ) ) + if( HasMemory( bits_MEMORY_KILLED ) ) { - if ( ShouldGibMonster( iGib ) ) + if( ShouldGibMonster( iGib ) ) CallGibMonster(); return; } @@ -603,37 +589,37 @@ void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) 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); + 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 ) + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); + if( pOwner ) { pOwner->DeathNotice( pev ); } - if ( ShouldGibMonster( iGib ) ) + if( ShouldGibMonster( iGib ) ) { CallGibMonster(); return; } - else if ( pev->flags & FL_MONSTER ) + 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) + if( pev->health < -99 ) { pev->health = 0; } - + //pev->enemy = ENT( pevAttacker );//why? (sjb) - + m_IdealMonsterState = MONSTERSTATE_DEAD; } @@ -642,9 +628,9 @@ void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) // // DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER! // SET A FUTURE THINK AND A RENDERMODE!! -void CBaseEntity :: SUB_StartFadeOut ( void ) +void CBaseEntity::SUB_StartFadeOut( void ) { - if (pev->rendermode == kRenderNormal) + if( pev->rendermode == kRenderNormal ) { pev->renderamt = 255; pev->rendermode = kRenderTransTexture; @@ -657,9 +643,9 @@ void CBaseEntity :: SUB_StartFadeOut ( void ) SetThink( &CBaseEntity::SUB_FadeOut ); } -void CBaseEntity :: SUB_FadeOut ( void ) +void CBaseEntity::SUB_FadeOut( void ) { - if ( pev->renderamt > 7 ) + if( pev->renderamt > 7 ) { pev->renderamt -= 7; pev->nextthink = gpGlobals->time + 0.1; @@ -678,24 +664,24 @@ void CBaseEntity :: SUB_FadeOut ( void ) // bouncing to emit their scent. That's what this function // does. //========================================================= -void CGib :: WaitTillLand ( void ) +void CGib::WaitTillLand( void ) { - if (!IsInWorld()) + if( !IsInWorld() ) { UTIL_Remove( this ); return; } - if ( pev->velocity == g_vecZero ) + if( pev->velocity == g_vecZero ) { - SetThink( &CBaseEntity::SUB_StartFadeOut); + SetThink( &CBaseEntity::SUB_StartFadeOut ); pev->nextthink = gpGlobals->time + m_lifeTime; // If you bleed, you stink! - if ( m_bloodColor != DONT_BLEED ) + if( m_bloodColor != DONT_BLEED ) { // ok, start stinkin! - CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); + CSoundEnt::InsertSound( bits_SOUND_MEAT, pev->origin, 384, 25 ); } } else @@ -708,15 +694,15 @@ void CGib :: WaitTillLand ( void ) // // Gib bounces on the ground or wall, sponges some blood down, too! // -void CGib :: BounceGibTouch ( CBaseEntity *pOther ) +void CGib::BounceGibTouch( CBaseEntity *pOther ) { Vector vecSpot; TraceResult tr; - - //if ( RANDOM_LONG(0,1) ) + + //if( RANDOM_LONG( 0, 1 ) ) // return;// don't bleed everytime - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { pev->velocity = pev->velocity * 0.9; pev->angles.x = 0; @@ -726,22 +712,22 @@ void CGib :: BounceGibTouch ( CBaseEntity *pOther ) } else { - if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) + 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); + 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 ) + 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); + float zvel = fabs( pev->velocity.z ); + + volume = 0.8 * min( 1.0, ( (float)zvel ) / 450.0 ); CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); } @@ -751,27 +737,27 @@ void CGib :: BounceGibTouch ( CBaseEntity *pOther ) // // Sticky gib puts blood on the wall and stays put. // -void CGib :: StickyGibTouch ( CBaseEntity *pOther ) +void CGib::StickyGibTouch( CBaseEntity *pOther ) { Vector vecSpot; TraceResult tr; - + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 10; - if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) + 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_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->angles = UTIL_VecToAngles( pev->velocity ); + pev->velocity = g_vecZero; pev->avelocity = g_vecZero; pev->movetype = MOVETYPE_NONE; } @@ -779,21 +765,21 @@ void CGib :: StickyGibTouch ( CBaseEntity *pOther ) // // Throw a chunk // -void CGib :: Spawn( const char *szGibModel ) +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"); + pev->classname = MAKE_STRING( "gib" ); - SET_MODEL(ENT(pev), szGibModel); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + SET_MODEL( ENT( pev ), szGibModel ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); pev->nextthink = gpGlobals->time + 4; m_lifeTime = 25; @@ -805,18 +791,18 @@ void CGib :: Spawn( const char *szGibModel ) } // take health -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) +int CBaseMonster::TakeHealth( float flHealth, int bitsDamageType ) { - if (!pev->takedamage) + 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); + m_bitsDamageType &= ~( bitsDamageType & ~DMG_TIMEBASED ); + + return CBaseEntity::TakeHealth( flHealth, bitsDamageType ); } /* @@ -830,25 +816,23 @@ 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 ) +int CBaseMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { float flTake; Vector vecDir; - if (!pev->takedamage) + if( !pev->takedamage ) return 0; - if ( !IsAlive() ) + if( !IsAlive() ) { return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } - if ( pev->deadflag == DEAD_NO ) + if( pev->deadflag == DEAD_NO ) { // no pain sound during death animation. PainSound();// "Ouch!" @@ -862,10 +846,10 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // 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 )) + if( !FNullEnt( pevInflictor ) ) { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) + CBaseEntity *pInflictor = CBaseEntity::Instance( pevInflictor ); + if( pInflictor ) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); @@ -875,22 +859,22 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // 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( IsPlayer() ) { - if ( pevInflictor ) - pev->dmg_inflictor = ENT(pevInflictor); + if( pevInflictor ) + pev->dmg_inflictor = ENT( pevInflictor ); pev->dmg_take += flTake; // check for godmode or invincibility - if ( pev->flags & FL_GODMODE ) + 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) ) + if( ( !FNullEnt( pevInflictor ) ) && ( pev->movetype == MOVETYPE_WALK ) && ( !pevAttacker || pevAttacker->solid != SOLID_TRIGGER ) ) { pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); } @@ -898,23 +882,22 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // 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 ) + if( m_MonsterState == MONSTERSTATE_SCRIPT ) { SetConditions( bits_COND_LIGHT_DAMAGE ); return 0; } - if ( pev->health <= 0 ) + if( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; - if ( bitsDamageType & DMG_ALWAYSGIB ) + if( bitsDamageType & DMG_ALWAYSGIB ) { Killed( pevAttacker, GIB_ALWAYS ); } - else if ( bitsDamageType & DMG_NEVERGIB ) + else if( bitsDamageType & DMG_NEVERGIB ) { Killed( pevAttacker, GIB_NEVER ); } @@ -929,15 +912,15 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, } // react to the damage (get mad) - if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) + if( ( pev->flags & FL_MONSTER ) && !FNullEnt( pevAttacker ) ) { - if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) - {// only if the attack was a monster or client! - + 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( pevInflictor ) { - if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) + if( m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions( bits_COND_SEE_ENEMY ) ) { m_vecEnemyLKP = pevInflictor->origin; } @@ -952,14 +935,14 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // 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 ) + if( flDamage > 0 ) { - SetConditions(bits_COND_LIGHT_DAMAGE); + SetConditions( bits_COND_LIGHT_DAMAGE ); } - if ( flDamage >= 20 ) + if( flDamage >= 20 ) { - SetConditions(bits_COND_HEAVY_DAMAGE); + SetConditions( bits_COND_HEAVY_DAMAGE ); } } } @@ -971,16 +954,16 @@ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // DeadTakeDamage - takedamage function called when a monster's // corpse is damaged. //========================================================= -int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CBaseMonster::DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - Vector vecDir; + 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 )) + if( !FNullEnt( pevInflictor ) ) { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) + CBaseEntity *pInflictor = CBaseEntity::Instance( pevInflictor ); + if( pInflictor ) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); @@ -993,17 +976,15 @@ int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttac pev->origin.z += 1; // let the damage scoot the corpse around a bit. - if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) + 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( bitsDamageType & DMG_GIB_CORPSE ) { - if ( pev->health <= flDamage ) + if( pev->health <= flDamage ) { pev->health = -50; Killed( pevAttacker, GIB_ALWAYS ); @@ -1012,16 +993,15 @@ int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttac // Accumulate corpse gibbing damage, so you can gib with multiple hits pev->health -= flDamage * 0.1; } - + return 1; } - -float CBaseMonster :: DamageForce( float damage ) +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) + float force = damage * ( ( 32 * 32 * 72.0 ) / ( pev->size.x * pev->size.y * pev->size.z ) ) * 5; + + if( force > 1000.0 ) { force = 1000.0; } @@ -1033,8 +1013,6 @@ float CBaseMonster :: DamageForce( float damage ) // 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; @@ -1042,62 +1020,64 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke float flAdjustedDamage, falloff; Vector vecSpot; - if ( flRadius ) + if( flRadius ) falloff = flDamage / flRadius; else falloff = 1.0; - int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); + int bInWater = ( UTIL_PointContents( vecSrc ) == CONTENTS_WATER ); vecSrc.z += 1;// in case grenade is lying on the ground - if ( !pevAttacker ) + if( !pevAttacker ) pevAttacker = pevInflictor; // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius ) ) != NULL ) { - if ( pEntity->pev->takedamage != DAMAGE_NO ) + 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 + 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) + if( bInWater && pEntity->pev->waterlevel == 0 ) continue; - if (!bInWater && pEntity->pev->waterlevel == 3) + 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) + 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 ) + + if( flAdjustedDamage < 0 ) { flAdjustedDamage = 0; } - + // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) + if( tr.flFraction != 1.0 ) { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); + ClearMultiDamage(); + pEntity->TraceAttack( pevInflictor, flAdjustedDamage, ( tr.vecEndPos - vecSrc ).Normalize(), &tr, bitsDamageType ); ApplyMultiDamage( pevInflictor, pevAttacker ); } else @@ -1109,19 +1089,16 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke } } - -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int 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 ) +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 @@ -1130,26 +1107,26 @@ void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entva // // Used for many contact-range melee attacks. Bites, claws, etc. //========================================================= -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) +CBaseEntity* CBaseMonster::CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { TraceResult tr; - if (IsPlayer()) + 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 ); + Vector vecEnd = vecStart + ( gpGlobals->v_forward * flDist ); - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); + + if( tr.pHit ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if ( iDamage > 0 ) + if( iDamage > 0 ) { pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); } @@ -1160,25 +1137,24 @@ CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, in 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 ) +BOOL CBaseMonster::FInViewCone( CBaseEntity *pEntity ) { Vector2D vec2LOS; float flDot; - UTIL_MakeVectors ( pev->angles ); - + UTIL_MakeVectors( pev->angles ); + vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); vec2LOS = vec2LOS.Normalize(); - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + flDot = DotProduct( vec2LOS, gpGlobals->v_forward.Make2D() ); - if ( flDot > m_flFieldOfView ) + if( flDot > m_flFieldOfView ) { return TRUE; } @@ -1193,19 +1169,19 @@ BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) // the caller's forward view cone. The dot product is performed // in 2d, making the view cone infinitely tall. //========================================================= -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) +BOOL CBaseMonster::FInViewCone( Vector *pOrigin ) { Vector2D vec2LOS; float flDot; - UTIL_MakeVectors ( pev->angles ); - + UTIL_MakeVectors( pev->angles ); + vec2LOS = ( *pOrigin - pev->origin ).Make2D(); vec2LOS = vec2LOS.Normalize(); - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + flDot = DotProduct( vec2LOS, gpGlobals->v_forward.Make2D() ); - if ( flDot > m_flFieldOfView ) + if( flDot > m_flFieldOfView ) { return TRUE; } @@ -1219,31 +1195,31 @@ BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) // FVisible - returns true if a line can be traced from // the caller's eyes to the target //========================================================= -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) +BOOL CBaseEntity::FVisible( CBaseEntity *pEntity ) { TraceResult tr; Vector vecLookerOrigin; Vector vecTargetOrigin; - - if(!pEntity) + + if( !pEntity ) return FALSE; - if(!pEntity->pev) + if( !pEntity->pev ) return FALSE; - if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) + 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)) + 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) + 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 } @@ -1257,16 +1233,16 @@ BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) // FVisible - returns true if a line can be traced from // the caller's eyes to the target vector //========================================================= -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) +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) + 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 } @@ -1285,41 +1261,39 @@ void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vec { Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - if ( pev->takedamage ) + if( pev->takedamage ) { AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); int blood = BloodColor(); - - if ( blood != DONT_BLEED ) + + if( blood != DONT_BLEED ) { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. + 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) +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 ); + ALERT( at_console, "%d\n", ptr->iHitgroup ); - - if ( pev->takedamage ) + if( pev->takedamage ) { AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); int blood = BloodColor(); - - if ( blood != DONT_BLEED ) + + if( blood != DONT_BLEED ) { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. + SpawnBlood( vecOrigin, blood, flDamage );// a little surface blood. } } } @@ -1328,13 +1302,13 @@ void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector ve //========================================================= // TraceAttack //========================================================= -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +void CBaseMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if ( pev->takedamage ) + if( pev->takedamage ) { m_LastHitGroup = ptr->iHitgroup; - switch ( ptr->iHitgroup ) + switch( ptr->iHitgroup ) { case HITGROUP_GENERIC: break; @@ -1359,7 +1333,7 @@ void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector break; } - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } @@ -1374,7 +1348,7 @@ 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 ) +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; @@ -1382,20 +1356,20 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting Vector vecRight = gpGlobals->v_right; Vector vecUp = gpGlobals->v_up; - if ( pevAttacker == NULL ) + if( pevAttacker == NULL ) pevAttacker = pev; // the default attacker is ourselves ClearMultiDamage(); gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; - for (ULONG iShot = 1; iShot <= cShots; iShot++) + 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; + 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 + @@ -1404,23 +1378,24 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting Vector vecEnd; vecEnd = vecSrc + vecDir * flDistance; - UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( pev )/*pentIgnore*/, &tr ); tracer = 0; - if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 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; + 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 + + if( iTracerFreq != 1 ) // guns that always trace also always decal tracer = 1; switch( iBulletType ) { @@ -1441,64 +1416,58 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting } } // do damage, paint decals - if (tr.flFraction != 1.0) + if( tr.flFraction != 1.0 ) { - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if ( iDamage ) + if( iDamage ) { - pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + 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) + else switch( iBulletType ) { default: case BULLET_MONSTER_9MM: - pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + 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); + 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 ) + case BULLET_MONSTER_12MM: + pEntity->TraceAttack( pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET ); + if( !tracer ) { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + 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); + 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) + if( !FNullEnt( tr.pHit ) && VARS( tr.pHit )->rendermode != 0 ) { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); + UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG( 0, 2 ) ); } break; } } // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, ( flDistance * tr.flFraction ) / 64.0 ); } - ApplyMultiDamage(pev, pevAttacker); + ApplyMultiDamage( pev, pevAttacker ); } - /* ================ FireBullets @@ -1508,7 +1477,7 @@ 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 ) +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 ) { static int tracerCount; TraceResult tr; @@ -1516,13 +1485,13 @@ Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecD Vector vecUp = gpGlobals->v_up; float x, y, z; - if ( pevAttacker == NULL ) + if( pevAttacker == NULL ) pevAttacker = pev; // the default attacker is ourselves ClearMultiDamage(); gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + for( ULONG iShot = 1; iShot <= cShots; iShot++ ) { //Use player's random seed. // get circular gaussian spread @@ -1536,71 +1505,67 @@ Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecD 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); + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( pev )/*pentIgnore*/, &tr ); - if ( iDamage ) + // 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); + 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) + else switch( iBulletType ) { default: - case BULLET_PLAYER_9MM: - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET); + 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); + case BULLET_PLAYER_MP5: + pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET ); break; - - case BULLET_PLAYER_BUCKSHOT: + case BULLET_PLAYER_BUCKSHOT: // make distance based! - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET); + pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET ); break; - - case BULLET_PLAYER_357: - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET); + 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); + 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) + if( !FNullEnt( tr.pHit ) && VARS( tr.pHit )->rendermode != 0 ) { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); + UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG( 0, 2 ) ); } break; } } // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 ); + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, ( flDistance * tr.flFraction ) / 64.0 ); } - ApplyMultiDamage(pev, pevAttacker); + ApplyMultiDamage( pev, pevAttacker ); return Vector( x * vecSpread.x, y * vecSpread.y, 0.0 ); } -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) +void CBaseEntity::TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if (BloodColor() == DONT_BLEED) - return; - - if (flDamage == 0) + if( BloodColor() == DONT_BLEED ) return; - if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) + 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; @@ -1609,10 +1574,10 @@ void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int i; /* - if ( !IsAlive() ) + if( !IsAlive() ) { // dealing with a dead monster. - if ( pev->max_health <= 0 ) + if( pev->max_health <= 0 ) { // no blood decal for a monster that has already decalled its limit. return; @@ -1623,13 +1588,12 @@ void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, } } */ - - if (flDamage < 10) + if( flDamage < 10 ) { flNoise = 0.1; cCount = 1; } - else if (flDamage < 25) + else if( flDamage < 25 ) { flNoise = 0.2; cCount = 2; @@ -1640,7 +1604,7 @@ void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, cCount = 4; } - for ( i = 0 ; i < cCount ; i++ ) + for( i = 0; i < cCount; i++ ) { vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) @@ -1648,9 +1612,9 @@ void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, 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); + UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT( pev ), &Bloodtr ); - if ( Bloodtr.flFraction != 1.0 ) + if( Bloodtr.flFraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } @@ -1659,17 +1623,17 @@ void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, //========================================================= //========================================================= -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) +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() ) + if( !IsAlive() ) { // dealing with a dead monster. - if ( pev->max_health <= 0 ) + if( pev->max_health <= 0 ) { // no blood decal for a monster that has already decalled its limit. return; @@ -1680,7 +1644,7 @@ void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResu } } - for ( i = 0 ; i < cCount ; i++ ) + for( i = 0; i < cCount; i++ ) { vecTraceDir = vecDir; @@ -1688,7 +1652,7 @@ void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResu 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); + UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT( pev ), &Bloodtr ); /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -1696,14 +1660,14 @@ void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResu 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 ) + if( Bloodtr.flFraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } diff --git a/dlls/controller.cpp b/dlls/controller.cpp index 75754f62..3d56325f 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -30,44 +30,44 @@ //========================================================= // 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_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[]; + 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 ); + 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 ); + 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 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 ); + void SetActivity( Activity NewActivity ); BOOL ShouldAdvanceRoute( float flWaypointDist ); - int LookupFloat( ); + int LookupFloat(); float m_flNextFlinch; @@ -91,7 +91,7 @@ public: void GibMonster( void ); CSprite *m_pBall[2]; // hand balls - int m_iBall[2]; // how bright it should be + 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 @@ -103,7 +103,7 @@ public: LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ) -TYPEDESCRIPTION CController::m_SaveData[] = +TYPEDESCRIPTION CController::m_SaveData[] = { DEFINE_ARRAY( CController, m_pBall, FIELD_CLASSPTR, 2 ), DEFINE_ARRAY( CController, m_iBall, FIELD_INTEGER, 2 ), @@ -114,14 +114,14 @@ TYPEDESCRIPTION CController::m_SaveData[] = IMPLEMENT_SAVERESTORE( CController, CSquadMonster ) -const char *CController::pAttackSounds[] = +const char *CController::pAttackSounds[] = { "controller/con_attack1.wav", "controller/con_attack2.wav", "controller/con_attack3.wav", }; -const char *CController::pIdleSounds[] = +const char *CController::pIdleSounds[] = { "controller/con_idle1.wav", "controller/con_idle2.wav", @@ -130,21 +130,21 @@ const char *CController::pIdleSounds[] = "controller/con_idle5.wav", }; -const char *CController::pAlertSounds[] = +const char *CController::pAlertSounds[] = { "controller/con_alert1.wav", "controller/con_alert2.wav", "controller/con_alert3.wav", }; -const char *CController::pPainSounds[] = +const char *CController::pPainSounds[] = { "controller/con_pain1.wav", "controller/con_pain2.wav", "controller/con_pain3.wav", }; -const char *CController::pDeathSounds[] = +const char *CController::pDeathSounds[] = { "controller/con_die1.wav", "controller/con_die2.wav", @@ -154,7 +154,7 @@ const char *CController::pDeathSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CController :: Classify ( void ) +int CController::Classify( void ) { return CLASS_ALIEN_MILITARY; } @@ -163,7 +163,7 @@ int CController :: Classify ( void ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CController :: SetYawSpeed ( void ) +void CController::SetYawSpeed( void ) { int ys; @@ -176,10 +176,10 @@ void CController :: SetYawSpeed ( void ) pev->yaw_speed = ys; } -int CController :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CController::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { // HACK HACK -- until we fix this. - if ( IsAlive() ) + if( IsAlive() ) PainSound(); return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } @@ -195,12 +195,12 @@ void CController::Killed( entvars_t *pevAttacker, int iGib ) */ // fade balls - if (m_pBall[0]) + if( m_pBall[0] ) { m_pBall[0]->SUB_StartFadeOut(); m_pBall[0] = NULL; } - if (m_pBall[1]) + if( m_pBall[1] ) { m_pBall[1]->SUB_StartFadeOut(); m_pBall[1] = NULL; @@ -212,41 +212,41 @@ void CController::Killed( entvars_t *pevAttacker, int iGib ) void CController::GibMonster( void ) { // delete balls - if (m_pBall[0]) + if( m_pBall[0] ) { UTIL_Remove( m_pBall[0] ); m_pBall[0] = NULL; } - if (m_pBall[1]) + if( m_pBall[1] ) { UTIL_Remove( m_pBall[1] ); m_pBall[1] = NULL; } - CSquadMonster::GibMonster( ); + CSquadMonster::GibMonster(); } -void CController :: PainSound( void ) +void CController::PainSound( void ) { - if (RANDOM_LONG(0,5) < 2) + if( RANDOM_LONG( 0, 5 ) < 2 ) EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); } -void CController :: AlertSound( void ) +void CController::AlertSound( void ) { EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); } -void CController :: IdleSound( void ) +void CController::IdleSound( void ) { EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pIdleSounds ); } -void CController :: AttackSound( void ) +void CController::AttackSound( void ) { EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAttackSounds ); } -void CController :: DeathSound( void ) +void CController::DeathSound( void ) { EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); } @@ -255,19 +255,19 @@ void CController :: DeathSound( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) +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_SHORT( entindex() + 0x1000 ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); @@ -283,10 +283,8 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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; @@ -295,7 +293,7 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment + WRITE_SHORT( entindex() + 0x1000 ); // entity, attachment WRITE_COORD( 0 ); // origin WRITE_COORD( 0 ); WRITE_COORD( 0 ); @@ -318,7 +316,7 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; case CONTROLLER_AE_SMALL_SHOOT: { - AttackSound( ); + AttackSound(); m_flShootTime = gpGlobals->time; m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; } @@ -348,18 +346,18 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CController :: Spawn() +void CController::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/controller.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 )); + SET_MODEL( ENT( pev ), "models/controller.mdl" ); + UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_FLY; - pev->flags |= FL_FLY; + pev->flags |= FL_FLY; m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.controllerHealth; + 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; @@ -370,9 +368,9 @@ void CController :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CController :: Precache() +void CController::Precache() { - PRECACHE_MODEL("models/controller.mdl"); + PRECACHE_MODEL( "models/controller.mdl" ); PRECACHE_SOUND_ARRAY( pAttackSounds ); PRECACHE_SOUND_ARRAY( pIdleSounds ); @@ -380,7 +378,7 @@ void CController :: Precache() PRECACHE_SOUND_ARRAY( pPainSounds ); PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_MODEL( "sprites/xspark4.spr"); + PRECACHE_MODEL( "sprites/xspark4.spr" ); UTIL_PrecacheOther( "controller_energy_ball" ); UTIL_PrecacheOther( "controller_head_ball" ); @@ -391,76 +389,75 @@ void CController :: Precache() //========================================================= // Chase enemy schedule -Task_t tlControllerChaseEnemy[] = +Task_t tlControllerChaseEnemy[] = { - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - + { TASK_GET_PATH_TO_ENEMY, (float)128 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, }; Schedule_t slControllerChaseEnemy[] = { - { + { tlControllerChaseEnemy, - ARRAYSIZE ( tlControllerChaseEnemy ), - bits_COND_NEW_ENEMY | + ARRAYSIZE( tlControllerChaseEnemy ), + bits_COND_NEW_ENEMY | bits_COND_TASK_FAILED, 0, "ControllerChaseEnemy" }, }; -Task_t tlControllerStrafe[] = +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 }, + { 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[] = +Schedule_t slControllerStrafe[] = { - { + { tlControllerStrafe, - ARRAYSIZE ( tlControllerStrafe ), + ARRAYSIZE( tlControllerStrafe ), bits_COND_NEW_ENEMY, 0, "ControllerStrafe" }, }; -Task_t tlControllerTakeCover[] = +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 }, + { 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[] = +Schedule_t slControllerTakeCover[] = { - { + { tlControllerTakeCover, - ARRAYSIZE ( tlControllerTakeCover ), + ARRAYSIZE( tlControllerTakeCover ), bits_COND_NEW_ENEMY, 0, "ControllerTakeCover" }, }; -Task_t tlControllerFail[] = +Task_t tlControllerFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slControllerFail[] = +Schedule_t slControllerFail[] = { { tlControllerFail, - ARRAYSIZE ( tlControllerFail ), + ARRAYSIZE( tlControllerFail ), 0, 0, "ControllerFail" @@ -480,23 +477,23 @@ IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ) //========================================================= // StartTask //========================================================= -void CController :: StartTask ( Task_t *pTask ) +void CController::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: - CSquadMonster :: StartTask ( pTask ); + 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 )) + 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" ); + ALERT( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; @@ -505,26 +502,26 @@ void CController :: StartTask ( Task_t *pTask ) { CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy == NULL ) + if( pEnemy == NULL ) { TaskFail(); return; } - if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, (pEnemy->pev->origin - pev->origin).Length() + 1024 )) + 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" ); + ALERT( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } default: - CSquadMonster :: StartTask ( pTask ); + CSquadMonster::StartTask( pTask ); break; } } @@ -534,22 +531,22 @@ 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 b = 0 * DotProduct( vecTo, vecMove ); // why does this work? float c = DotProduct( vecTo, vecTo ); - float t; - if (a == 0) + + if( a == 0 ) { - t = c / (flSpeed * flSpeed); + t = c / ( flSpeed * flSpeed ); } else { t = b * b - 4 * a * c; - t = sqrt( t ) / (2.0 * a); + t = sqrt( t ) / ( 2.0 * a ); float t1 = -b +t; float t2 = -b -t; - if (t1 < 0 || t2 < t1) + if( t1 < 0 || t2 < t1 ) t = t2; else t = t1; @@ -557,18 +554,18 @@ Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) // ALERT( at_console, "Intersect %f\n", t ); - if (t < 0.1) + if( t < 0.1 ) t = 0.1; - if (t > 10.0) + if( t > 10.0 ) t = 10.0; Vector vecHit = vecTo + vecMove * t; - return vecHit.Normalize( ) * flSpeed; + return vecHit.Normalize() * flSpeed; } -int CController::LookupFloat( ) +int CController::LookupFloat() { - if (m_velocity.Length( ) < 32.0) + if( m_velocity.Length() < 32.0 ) { return LookupSequence( "up" ); } @@ -578,49 +575,48 @@ int CController::LookupFloat( ) 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( fabs( x ) > fabs( y ) && fabs( x ) > fabs( z ) ) { - if (x > 0) - return LookupSequence( "forward"); + if( x > 0 ) + return LookupSequence( "forward" ); else - return LookupSequence( "backward"); + return LookupSequence( "backward" ); } - else if (fabs(y) > fabs(z)) + else if( fabs( y ) > fabs( z ) ) { - if (y > 0) - return LookupSequence( "right"); + if( y > 0 ) + return LookupSequence( "right" ); else - return LookupSequence( "left"); + return LookupSequence( "left" ); } else { - if (z > 0) - return LookupSequence( "up"); + if( z > 0 ) + return LookupSequence( "up" ); else - return LookupSequence( "down"); + return LookupSequence( "down" ); } } //========================================================= // RunTask //========================================================= -void CController :: RunTask ( Task_t *pTask ) +void CController::RunTask( Task_t *pTask ) { - - if (m_flShootEnd > gpGlobals->time) + if( m_flShootEnd > gpGlobals->time ) { Vector vecHand, vecAngle; - + GetAttachment( 2, vecHand, vecAngle ); - - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) + + while( m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time ) { - Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); + Vector vecSrc = vecHand + pev->velocity * ( m_flShootTime - gpGlobals->time ); Vector vecDir; - - if (m_hEnemy != NULL) + + if( m_hEnemy != NULL ) { - if (HasConditions( bits_COND_SEE_ENEMY )) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; } @@ -632,14 +628,14 @@ void CController :: RunTask ( Task_t *pTask ) 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); + 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) + if( m_flShootTime > m_flShootEnd ) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; @@ -649,7 +645,7 @@ void CController :: RunTask ( Task_t *pTask ) } } - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: @@ -658,43 +654,43 @@ void CController :: RunTask ( Task_t *pTask ) MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { m_fInCombat = FALSE; } - CSquadMonster :: RunTask ( pTask ); + CSquadMonster::RunTask( pTask ); - if (!m_fInCombat) + if( !m_fInCombat ) { - if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); m_fInCombat = TRUE; } - else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) + else if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) ) { pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); m_fInCombat = TRUE; } else { - int iFloat = LookupFloat( ); - if (m_fSequenceFinished || iFloat != pev->sequence) + int iFloat = LookupFloat(); + if( m_fSequenceFinished || iFloat != pev->sequence ) { pev->sequence = iFloat; pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); } } } break; default: - CSquadMonster :: RunTask ( pTask ); + CSquadMonster::RunTask( pTask ); break; } } @@ -705,20 +701,20 @@ void CController :: RunTask ( Task_t *pTask ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CController :: GetSchedule ( void ) +Schedule_t *CController::GetSchedule( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: { Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); // dead enemy - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) + if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) { // m_iFrustration++; } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) { // m_iFrustration++; } @@ -731,15 +727,15 @@ Schedule_t *CController :: GetSchedule ( void ) break; } - return CSquadMonster :: GetSchedule(); + return CSquadMonster::GetSchedule(); } //========================================================= //========================================================= -Schedule_t* CController :: GetScheduleOfType ( int Type ) +Schedule_t *CController::GetScheduleOfType( int Type ) { // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) + switch( Type ) { case SCHED_CHASE_ENEMY: return slControllerChaseEnemy; @@ -754,41 +750,41 @@ Schedule_t* CController :: GetScheduleOfType ( int Type ) return slControllerFail; } - return CBaseMonster :: GetScheduleOfType( Type ); + return CBaseMonster::GetScheduleOfType( Type ); } //========================================================= // CheckRangeAttack1 - shoot a bigass energy ball out of their head // //========================================================= -BOOL CController :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CController::CheckRangeAttack1( float flDot, float flDist ) { - if ( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) + if( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) { return TRUE; } return FALSE; } -BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) +BOOL CController::CheckRangeAttack2( float flDot, float flDist ) { - if ( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) + if( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) { return TRUE; } return FALSE; } -BOOL CController :: CheckMeleeAttack1 ( float flDot, float flDist ) +BOOL CController::CheckMeleeAttack1( float flDot, float flDist ) { return FALSE; } -void CController :: SetActivity ( Activity NewActivity ) +void CController::SetActivity( Activity NewActivity ) { CBaseMonster::SetActivity( NewActivity ); - switch ( m_Activity) + switch( m_Activity ) { case ACT_WALK: m_flGroundSpeed = 100; @@ -802,40 +798,40 @@ void CController :: SetActivity ( Activity NewActivity ) //========================================================= // RunAI //========================================================= -void CController :: RunAI( void ) +void CController::RunAI( void ) { - CBaseMonster :: RunAI(); + CBaseMonster::RunAI(); Vector vecStart, angleGun; - if ( HasMemory( bits_MEMORY_KILLED ) ) + if( HasMemory( bits_MEMORY_KILLED ) ) return; - for (int i = 0; i < 2; i++) + for( int i = 0; i < 2; i++ ) { - if (m_pBall[i] == NULL) + 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]->SetAttachment( edict(), ( i + 3 ) ); m_pBall[i]->SetScale( 1.0 ); } float t = m_iBallTime[i] - gpGlobals->time; - if (t > 0.1) + if( t > 0.1 ) t = 0.1 / t; else t = 1.0; - m_iBallCurrent[i] += (m_iBall[i] - m_iBallCurrent[i]) * t; + 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_SHORT( entindex() + 0x1000 * ( i + 3 ) ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); @@ -851,14 +847,14 @@ void CController :: RunAI( void ) extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); -void CController::Stop( void ) +void CController::Stop( void ) { m_IdealActivity = GetStoppedActivity(); } #define DIST_TO_CHECK 200 -void CController :: Move ( float flInterval ) +void CController::Move( float flInterval ) { float flWaypointDist; float flCheckDist; @@ -869,21 +865,21 @@ void CController :: Move ( float flInterval ) CBaseEntity *pTargetEnt; // Don't move if no valid route - if ( FRouteClear() ) + if( FRouteClear() ) { ALERT( at_aiconsole, "Tried to move with no route!\n" ); TaskFail(); return; } - - if ( m_flMoveWaitFinished > gpGlobals->time ) + + if( m_flMoveWaitFinished > gpGlobals->time ) return; // Debug, test movement code #if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) +// if( CVAR_GET_FLOAT( "stopmove" ) != 0 ) { - if ( m_movementGoal == MOVEGOAL_ENEMY ) + if( m_movementGoal == MOVEGOAL_ENEMY ) RouteSimplify( m_hEnemy ); else RouteSimplify( m_hTargetEnt ); @@ -898,26 +894,26 @@ void CController :: Move ( float flInterval ) // to that entity for the CheckLocalMove and Triangulate functions. pTargetEnt = NULL; - if (m_flGroundSpeed == 0) + if( m_flGroundSpeed == 0 ) { m_flGroundSpeed = 100; - // TaskFail( ); + // TaskFail(); // return; } flMoveDist = m_flGroundSpeed * flInterval; - do + 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 ); + 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 ) + if( flWaypointDist < DIST_TO_CHECK ) { flCheckDist = flWaypointDist; } @@ -925,13 +921,13 @@ void CController :: Move ( float flInterval ) { flCheckDist = DIST_TO_CHECK; } - - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) + + 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 ) + else if( ( m_Route[m_iRouteIndex].iType & ~bits_MF_NOT_TO_MASK ) == bits_MF_TO_TARGETENT ) { pTargetEnt = m_hTargetEnt; } @@ -940,7 +936,7 @@ void CController :: Move ( float flInterval ) // 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 ) + if( CheckLocalMove( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) { CBaseEntity *pBlocker; @@ -948,14 +944,14 @@ void CController :: Move ( float flInterval ) Stop(); // Blocking entity is in global trace_ent pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) + if( pBlocker ) { DispatchBlocked( edict(), pBlocker->edict() ); } - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) + 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 ) + if( flDist < m_flGroundSpeed ) { // Wait for a second m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; @@ -963,10 +959,10 @@ void CController :: Move ( float flInterval ) return; } } - else + else { // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) + if( FTriangulate( pev->origin, m_Route[m_iRouteIndex].vecLocation, flDist, pTargetEnt, &vecApex ) ) { InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); RouteSimplify( pTargetEnt ); @@ -975,7 +971,7 @@ void CController :: Move ( float flInterval ) { ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); Stop(); - if ( m_moveWaitTime > 0 ) + if( m_moveWaitTime > 0 ) { FRefreshRoute(); m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; @@ -984,7 +980,7 @@ void CController :: Move ( float flInterval ) { 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 ); + //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, ( pev->origin + ( vecDir * flCheckDist ) ).z, m_Route[m_iRouteIndex].vecLocation.z ); } return; } @@ -992,7 +988,7 @@ void CController :: Move ( float flInterval ) } // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if (flCheckDist < flMoveDist) + if( flCheckDist < flMoveDist ) { MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); @@ -1004,42 +1000,42 @@ void CController :: Move ( float flInterval ) { MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); - if ( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) + if( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) { AdvanceRoute( flWaypointDist ); } flMoveDist = 0; } - if ( MovementIsComplete() ) + if( MovementIsComplete() ) { Stop(); RouteClear(); } - } while (flMoveDist > 0 && flCheckDist > 0); + } while( flMoveDist > 0 && flCheckDist > 0 ); // cut corner? - if (flWaypointDist < 128) + if( flWaypointDist < 128 ) { - if ( m_movementGoal == MOVEGOAL_ENEMY ) + if( m_movementGoal == MOVEGOAL_ENEMY ) RouteSimplify( m_hEnemy ); else RouteSimplify( m_hTargetEnt ); FRefreshRoute(); - if (m_flGroundSpeed > 100) + if( m_flGroundSpeed > 100 ) m_flGroundSpeed -= 40; } else { - if (m_flGroundSpeed < 400) + if( m_flGroundSpeed < 400 ) m_flGroundSpeed += 10; } } -BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) +BOOL CController::ShouldAdvanceRoute( float flWaypointDist ) { - if ( flWaypointDist <= 32 ) + if( flWaypointDist <= 32 ) { return TRUE; } @@ -1047,24 +1043,24 @@ BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) return FALSE; } -int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +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 ); + 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) + if( pflDist ) { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. + *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( tr.fStartSolid || tr.flFraction < 1.0 ) { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + if( pTarget && pTarget->edict() == gpGlobals->trace_ent ) return LOCALMOVE_VALID; return LOCALMOVE_INVALID; } @@ -1074,17 +1070,17 @@ int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { - if ( m_IdealActivity != m_movementActivity ) + 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 ); + // 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 ); + UTIL_MoveToOrigin( ENT( pev ), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); } //========================================================= @@ -1107,14 +1103,14 @@ class CControllerHeadBall : public CBaseMonster LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ) -void CControllerHeadBall :: Spawn( void ) +void CControllerHeadBall::Spawn( void ) { - Precache( ); + Precache(); // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); + SET_MODEL(ENT( pev ), "sprites/xspark4.spr" ); pev->rendermode = kRenderTransAdd; pev->rendercolor.x = 255; pev->rendercolor.y = 255; @@ -1122,7 +1118,7 @@ void CControllerHeadBall :: Spawn( void ) pev->renderamt = 255; pev->scale = 2.0; - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetSize(pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); UTIL_SetOrigin( pev, pev->origin ); SetThink( &CControllerHeadBall::HuntThink ); @@ -1136,14 +1132,14 @@ void CControllerHeadBall :: Spawn( void ) pev->dmgtime = gpGlobals->time; } -void CControllerHeadBall :: Precache( void ) +void CControllerHeadBall::Precache( void ) { - PRECACHE_MODEL("sprites/xspark1.spr"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_MODEL( "sprites/xspark1.spr" ); + PRECACHE_SOUND( "debris/zap4.wav" ); + PRECACHE_SOUND( "weapons/electro4.wav" ); } -void CControllerHeadBall :: HuntThink( void ) +void CControllerHeadBall::HuntThink( void ) { pev->nextthink = gpGlobals->time + 0.1; @@ -1151,7 +1147,7 @@ void CControllerHeadBall :: HuntThink( void ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_SHORT( entindex() ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1164,25 +1160,25 @@ void CControllerHeadBall :: HuntThink( void ) MESSAGE_END(); // check world boundaries - if (gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + if( gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || 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( ) ); + MovetoTarget( m_hEnemy->Center() ); - if ((m_hEnemy->Center() - pev->origin).Length() < 64) + if( ( m_hEnemy->Center() - pev->origin ).Length() < 64 ) { TraceResult tr; - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, ENT(pev), &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) + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + if( pEntity != NULL && pEntity->pev->takedamage ) { - ClearMultiDamage( ); + ClearMultiDamage(); pEntity->TraceAttack( m_hOwner->pev, gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK ); ApplyMultiDamage( pev, m_hOwner->pev ); } @@ -1206,7 +1202,7 @@ void CControllerHeadBall :: HuntThink( void ) WRITE_BYTE( 10 ); // speed MESSAGE_END(); - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + UTIL_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); m_flNextAttack = gpGlobals->time + 3.0; @@ -1214,36 +1210,35 @@ void CControllerHeadBall :: HuntThink( void ) pev->nextthink = gpGlobals->time + 0.3; } - //Crawl( ); + //Crawl(); } -void CControllerHeadBall :: DieThink( void ) +void CControllerHeadBall::DieThink( void ) { UTIL_Remove( this ); } -void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) +void CControllerHeadBall::MovetoTarget( Vector vecTarget ) { // accelerate float flSpeed = m_vecIdeal.Length(); - if (flSpeed == 0) + if( flSpeed == 0 ) { m_vecIdeal = pev->velocity; flSpeed = m_vecIdeal.Length(); } - if (flSpeed > 400) + if( flSpeed > 400 ) { - m_vecIdeal = m_vecIdeal.Normalize( ) * 400; + m_vecIdeal = m_vecIdeal.Normalize() * 400; } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 100; + m_vecIdeal = m_vecIdeal + ( vecTarget - pev->origin ).Normalize() * 100; pev->velocity = m_vecIdeal; } -void CControllerHeadBall :: Crawl( void ) +void CControllerHeadBall::Crawl( void ) { - - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); + 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 ); @@ -1268,11 +1263,11 @@ void CControllerHeadBall :: Crawl( void ) void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) { - Vector vecDir = m_vecIdeal.Normalize( ); + Vector vecDir = m_vecIdeal.Normalize(); - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); - float n = -DotProduct(tr.vecPlaneNormal, vecDir); + float n = -DotProduct( tr.vecPlaneNormal, vecDir ); vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; @@ -1291,14 +1286,14 @@ class CControllerZapBall : public CBaseMonster LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ) -void CControllerZapBall :: Spawn( void ) +void CControllerZapBall::Spawn( void ) { - Precache( ); + Precache(); // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); + SET_MODEL( ENT( pev ), "sprites/xspark4.spr" ); pev->rendermode = kRenderTransAdd; pev->rendercolor.x = 255; pev->rendercolor.y = 255; @@ -1306,7 +1301,7 @@ void CControllerZapBall :: Spawn( void ) pev->renderamt = 255; pev->scale = 0.5; - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); UTIL_SetOrigin( pev, pev->origin ); SetThink( &CControllerZapBall::AnimateThink ); @@ -1317,20 +1312,20 @@ void CControllerZapBall :: Spawn( void ) pev->nextthink = gpGlobals->time + 0.1; } -void CControllerZapBall :: Precache( void ) +void CControllerZapBall::Precache( void ) { - PRECACHE_MODEL("sprites/xspark4.spr"); - // PRECACHE_SOUND("debris/zap4.wav"); - // PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_MODEL( "sprites/xspark4.spr" ); + // PRECACHE_SOUND( "debris/zap4.wav" ); + // PRECACHE_SOUND( "weapons/electro4.wav" ); } -void CControllerZapBall :: AnimateThink( void ) +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) + pev->frame = ( (int)pev->frame + 1 ) % 11; + + if( gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10 ) { SetTouch( NULL ); UTIL_Remove( this ); @@ -1339,12 +1334,13 @@ void CControllerZapBall :: AnimateThink( void ) void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) { - if (pOther->pev->takedamage) + if( pOther->pev->takedamage ) { - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); - entvars_t *pevOwner; - if (m_hOwner != NULL) + entvars_t *pevOwner; + + if( m_hOwner != NULL ) { pevOwner = m_hOwner->pev; } @@ -1353,12 +1349,11 @@ void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) pevOwner = pev; } - ClearMultiDamage( ); + 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_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) ); } UTIL_Remove( this ); diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index dee2562a..d34ad25d 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -36,7 +36,7 @@ class CCrossbowBolt : public CBaseEntity { void Spawn( void ); void Precache( void ); - int Classify ( void ); + int Classify( void ); void EXPORT BubbleThink( void ); void EXPORT BoltTouch( CBaseEntity *pOther ); void EXPORT ExplodeThink( void ); @@ -53,46 +53,44 @@ CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) { // Create a new entity with CCrossbowBolt private data CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL ); - pBolt->pev->classname = MAKE_STRING("crossbow_bolt"); // g-cont. enable save\restore + pBolt->pev->classname = MAKE_STRING( "crossbow_bolt" ); // g-cont. enable save\restore pBolt->Spawn(); return pBolt; } -void CCrossbowBolt::Spawn( ) +void CCrossbowBolt::Spawn() { - Precache( ); + Precache(); pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; pev->gravity = 0.5; - SET_MODEL(ENT(pev), "models/crossbow_bolt.mdl"); + SET_MODEL( ENT( pev ), "models/crossbow_bolt.mdl" ); UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); + 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( ) +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"); + 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 ) +int CCrossbowBolt::Classify( void ) { - return CLASS_NONE; + return CLASS_NONE; } void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) @@ -100,71 +98,73 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) SetTouch( NULL ); SetThink( NULL ); - if (pOther->pev->takedamage) + if( pOther->pev->takedamage ) { - TraceResult tr = UTIL_GetGlobalTrace( ); - entvars_t *pevOwner; + TraceResult tr = UTIL_GetGlobalTrace(); + entvars_t *pevOwner; pevOwner = VARS( pev->owner ); // UNDONE: this needs to call TraceAttack instead - ClearMultiDamage( ); + ClearMultiDamage(); - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { - pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); + 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 ); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; + 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; + EMIT_SOUND( ENT( pev ), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM ); + break; } - if ( !g_pGameRules->IsMultiplayer() ) + 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)); + 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( &CBaseEntity::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( FClassnameIs( pOther->pev, "worldspawn" ) ) { // if what we hit is static architecture, can stay around for a while. - Vector vecDir = pev->velocity.Normalize( ); + 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->angles.z = RANDOM_LONG( 0, 360 ); pev->nextthink = gpGlobals->time + 10.0; } - else if ( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) + else if( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) { - Vector vecDir = pev->velocity.Normalize( ); + Vector vecDir = pev->velocity.Normalize(); UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); pev->angles = UTIL_VecToAngles( vecDir ); pev->solid = SOLID_NOT; pev->velocity = Vector( 0, 0, 0 ); pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG(0,360); + pev->angles.z = RANDOM_LONG( 0, 360 ); pev->nextthink = gpGlobals->time + 10.0; // g-cont. Setup movewith feature @@ -172,13 +172,13 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) pev->aiment = ENT( pOther->pev ); // set parent } - if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) + if( UTIL_PointContents( pev->origin ) != CONTENTS_WATER ) { UTIL_Sparks( pev->origin ); } } - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { SetThink( &CCrossbowBolt::ExplodeThink ); pev->nextthink = gpGlobals->time + 0.1; @@ -189,7 +189,7 @@ void CCrossbowBolt::BubbleThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - if (pev->waterlevel == 0) + if( pev->waterlevel == 0 ) return; UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); @@ -197,18 +197,18 @@ void CCrossbowBolt::BubbleThink( void ) void CCrossbowBolt::ExplodeThink( void ) { - int iContents = UTIL_PointContents ( pev->origin ); + 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_BYTE( TE_EXPLOSION ); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) + if( iContents != CONTENTS_WATER ) { WRITE_SHORT( g_sModelIndexFireball ); } @@ -216,14 +216,14 @@ void CCrossbowBolt::ExplodeThink( void ) { WRITE_SHORT( g_sModelIndexWExplosion ); } - WRITE_BYTE( iScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( iScale ); // scale * 10 + WRITE_BYTE( 15 ); // framerate WRITE_BYTE( TE_EXPLFLAG_NONE ); MESSAGE_END(); entvars_t *pevOwner; - if ( pev->owner ) + if( pev->owner ) pevOwner = VARS( pev->owner ); else pevOwner = NULL; @@ -232,11 +232,12 @@ void CCrossbowBolt::ExplodeThink( void ) ::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB ); - UTIL_Remove(this); + UTIL_Remove( this ); } #endif -enum crossbow_e { +enum crossbow_e +{ CROSSBOW_IDLE1 = 0, // full CROSSBOW_IDLE2, // empty CROSSBOW_FIDGET1, // full @@ -253,11 +254,11 @@ enum crossbow_e { LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ) -void CCrossbow::Spawn( ) +void CCrossbow::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_CROSSBOW; - SET_MODEL(ENT(pev), "models/w_crossbow.mdl"); + SET_MODEL( ENT( pev ), "models/w_crossbow.mdl" ); m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE; @@ -266,7 +267,7 @@ void CCrossbow::Spawn( ) int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -278,12 +279,12 @@ int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) void CCrossbow::Precache( void ) { - PRECACHE_MODEL("models/w_crossbow.mdl"); - PRECACHE_MODEL("models/v_crossbow.mdl"); - PRECACHE_MODEL("models/p_crossbow.mdl"); + 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"); + PRECACHE_SOUND( "weapons/xbow_fire1.wav" ); + PRECACHE_SOUND( "weapons/xbow_reload1.wav" ); UTIL_PrecacheOther( "crossbow_bolt" ); @@ -291,10 +292,9 @@ void CCrossbow::Precache( void ) m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" ); } - -int CCrossbow::GetItemInfo(ItemInfo *p) +int CCrossbow::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "bolts"; p->iMaxAmmo1 = BOLT_MAX_CARRY; p->pszAmmo2 = NULL; @@ -308,10 +308,9 @@ int CCrossbow::GetItemInfo(ItemInfo *p) return 1; } - -BOOL CCrossbow::Deploy( ) +BOOL CCrossbow::Deploy() { - if (m_iClip) + 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" ); } @@ -320,13 +319,13 @@ void CCrossbow::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. - if ( m_fInZoom ) + if( m_fInZoom ) { - SecondaryAttack( ); + SecondaryAttack(); } m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if (m_iClip) + if( m_iClip ) SendWeaponAnim( CROSSBOW_HOLSTER1 ); else SendWeaponAnim( CROSSBOW_HOLSTER2 ); @@ -334,11 +333,10 @@ void CCrossbow::Holster( int skiplocal /* = 0 */ ) void CCrossbow::PrimaryAttack( void ) { - #ifdef CLIENT_DLL - if ( m_fInZoom && bIsMultiplayer() ) + if( m_fInZoom && bIsMultiplayer() ) #else - if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) + if( m_fInZoom && g_pGameRules->IsMultiplayer() ) #endif { FireSniperBolt(); @@ -353,9 +351,9 @@ void CCrossbow::FireSniperBolt() { m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip == 0) + if( m_iClip == 0 ) { - PlayEmptySound( ); + PlayEmptySound(); return; } @@ -375,19 +373,19 @@ void CCrossbow::FireSniperBolt() // 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 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); + UTIL_TraceLine( vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr ); #ifndef CLIENT_DLL - if ( tr.pHit->v.takedamage ) + if( tr.pHit->v.takedamage ) { - ClearMultiDamage( ); - CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); + ClearMultiDamage(); + CBaseEntity::Instance( tr.pHit )->TraceAttack( m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); ApplyMultiDamage( pev, m_pPlayer->pev ); } #endif @@ -397,9 +395,9 @@ void CCrossbow::FireBolt() { TraceResult tr; - if (m_iClip == 0) + if( m_iClip == 0 ) { - PlayEmptySound( ); + PlayEmptySound(); return; } @@ -421,10 +419,10 @@ void CCrossbow::FireBolt() Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; UTIL_MakeVectors( anglesAim ); - - anglesAim.x = -anglesAim.x; - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; + + anglesAim.x = -anglesAim.x; + Vector vecSrc = m_pPlayer->GetGunPosition() - gpGlobals->v_up * 2; + Vector vecDir = gpGlobals->v_forward; #ifndef CLIENT_DLL CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); @@ -432,7 +430,7 @@ void CCrossbow::FireBolt() pBolt->pev->angles = anglesAim; pBolt->pev->owner = m_pPlayer->edict(); - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY; pBolt->pev->speed = BOLT_WATER_VELOCITY; @@ -445,68 +443,65 @@ void CCrossbow::FireBolt() pBolt->pev->avelocity.z = 10; #endif - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 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_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip != 0) + 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 ) + 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 ) + 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 ) + if( m_pPlayer->ammo_bolts <= 0 ) return; - if ( m_pPlayer->pev->fov != 0 ) + if( m_pPlayer->pev->fov != 0 ) { SecondaryAttack(); } - if ( DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ) ) + 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)); + 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( ); + ResetEmptySound(); - if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) + if( flRand <= 0.75 ) { - if (m_iClip) + if( m_iClip ) { SendWeaponAnim( CROSSBOW_IDLE1 ); } @@ -518,7 +513,7 @@ void CCrossbow::WeaponIdle( void ) } else { - if (m_iClip) + if( m_iClip ) { SendWeaponAnim( CROSSBOW_FIDGET1 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; @@ -533,26 +528,24 @@ void CCrossbow::WeaponIdle( void ) } } - - class CCrossbowAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_crossbow_clip.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + PRECACHE_MODEL( "models/w_crossbow_clip.mdl" ); + PRECACHE_SOUND( "items/9mmclip1.wav" ); } - BOOL AddAmmo( CBaseEntity *pOther ) + BOOL AddAmmo( CBaseEntity *pOther ) { - if (pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1) + if( pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1 ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; @@ -560,7 +553,4 @@ class CCrossbowAmmo : public CBasePlayerAmmo }; LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ) - - - #endif diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 7ff7911b..0ec2be70 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -22,13 +22,13 @@ #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 { +enum gauss_e +{ CROWBAR_IDLE = 0, CROWBAR_DRAW, CROWBAR_HOLSTER, @@ -43,33 +43,32 @@ enum gauss_e { void CCrowbar::Spawn( ) { - Precache( ); + Precache(); m_iId = WEAPON_CROWBAR; - SET_MODEL(ENT(pev), "models/w_crowbar.mdl"); + 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"); + 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" ); + m_usCrowbar = PRECACHE_EVENT( 1, "events/crowbar.sc" ); } -int CCrowbar::GetItemInfo(ItemInfo *p) +int CCrowbar::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = NULL; p->iMaxAmmo1 = -1; p->pszAmmo2 = NULL; @@ -82,9 +81,7 @@ int CCrowbar::GetItemInfo(ItemInfo *p) return 1; } - - -BOOL CCrowbar::Deploy( ) +BOOL CCrowbar::Deploy() { return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); } @@ -95,41 +92,40 @@ void CCrowbar::Holster( int skiplocal /* = 0 */ ) SendWeaponAnim( CROWBAR_HOLSTER ); } - void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) { - int i, j, k; + int i, j, k; float distance; float *minmaxs[2] = {mins, maxs}; - TraceResult tmpTrace; + TraceResult tmpTrace; Vector vecHullEnd = tr.vecEndPos; Vector vecEnd; distance = 1e6f; - vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); + vecHullEnd = vecSrc + ( ( vecHullEnd - vecSrc ) * 2 ); UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) + if( tmpTrace.flFraction < 1.0 ) { tr = tmpTrace; return; } - for ( i = 0; i < 2; i++ ) + for( i = 0; i < 2; i++ ) { - for ( j = 0; j < 2; j++ ) + for( j = 0; j < 2; j++ ) { - for ( k = 0; k < 2; k++ ) + 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 ) + if( tmpTrace.flFraction < 1.0 ) { - float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length(); - if ( thisDistance < distance ) + float thisDistance = ( tmpTrace.vecEndPos - vecSrc ).Length(); + if( thisDistance < distance ) { tr = tmpTrace; distance = thisDistance; @@ -140,131 +136,130 @@ void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, f } } - void CCrowbar::PrimaryAttack() { - if (! Swing( 1 )) + if( !Swing( 1 ) ) { SetThink( &CCrowbar::SwingAgain ); pev->nextthink = gpGlobals->time + 0.1; } } - -void CCrowbar::Smack( ) +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_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 ) + if( tr.flFraction >= 1.0 ) { UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); - if ( tr.flFraction < 1.0 ) + 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() ) + 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, 0.0 ); - - if ( tr.flFraction >= 1.0 ) + if( tr.flFraction >= 1.0 ) { - if (fFirst) + if( fFirst ) { // miss m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - + // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); } } else { - switch( ((m_iSwing++) % 2) + 1 ) + switch( ( ( m_iSwing++ ) % 2 ) + 1 ) { case 0: - SendWeaponAnim( CROWBAR_ATTACK1HIT ); break; + SendWeaponAnim( CROWBAR_ATTACK1HIT ); + break; case 1: - SendWeaponAnim( CROWBAR_ATTACK2HIT ); break; + SendWeaponAnim( CROWBAR_ATTACK2HIT ); + break; case 2: - SendWeaponAnim( CROWBAR_ATTACK3HIT ); break; + SendWeaponAnim( CROWBAR_ATTACK3HIT ); + break; } // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#ifndef CLIENT_DLL +#ifndef CLIENT_DLL // hit fDidHit = TRUE; - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - ClearMultiDamage( ); + ClearMultiDamage(); - if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) + 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 ); + 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 ); - } + 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 ) { - if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) + if( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) { // play thwack or smack sound - switch( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break; + 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; + 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; + 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; + if( !pEntity->IsAlive() ) + return TRUE; else - flVol = 0.1; + flVol = 0.1; fHitWorld = FALSE; } @@ -273,11 +268,11 @@ int CCrowbar::Swing( int fFirst ) // play texture hit sound // UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line - if (fHitWorld) + if( fHitWorld ) { - float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR); + float fvolbar = TEXTURETYPE_PlaySound( &tr, vecSrc, vecSrc + ( vecEnd - vecSrc ) * 2, BULLET_PLAYER_CROWBAR ); - if ( g_pGameRules->IsMultiplayer() ) + 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. @@ -286,13 +281,13 @@ int CCrowbar::Swing( int fFirst ) } // also play crowbar strike - switch( RANDOM_LONG(0,1) ) + 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)); + 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)); + EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG( 0, 3 ) ); break; } @@ -303,14 +298,9 @@ int CCrowbar::Swing( int fFirst ) m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; #endif m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - + SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; - - } return fDidHit; } - - - diff --git a/dlls/defaultai.cpp b/dlls/defaultai.cpp index 645fa916..e14a8ce2 100644 --- a/dlls/defaultai.cpp +++ b/dlls/defaultai.cpp @@ -28,19 +28,19 @@ //========================================================= // Fail //========================================================= -Task_t tlFail[] = +Task_t tlFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slFail[] = +Schedule_t slFail[] = { { tlFail, - ARRAYSIZE ( tlFail ), + ARRAYSIZE( tlFail ), bits_COND_CAN_ATTACK, 0, "Fail" @@ -50,75 +50,74 @@ Schedule_t slFail[] = //========================================================= // Idle Schedules //========================================================= -Task_t tlIdleStand1[] = +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. + { 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[] = +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 | + 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_COMBAT |// sound flags + bits_SOUND_WORLD | + bits_SOUND_PLAYER | + bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | bits_SOUND_GARBAGE, "IdleStand" }, }; -Schedule_t slIdleTrigger[] = +Schedule_t slIdleTrigger[] = { - { + { tlIdleStand1, - ARRAYSIZE ( tlIdleStand1 ), - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlIdleStand1 ), + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "Idle Trigger" }, }; - -Task_t tlIdleWalk1[] = +Task_t tlIdleWalk1[] = { - { TASK_WALK_PATH, (float)9999 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { TASK_WALK_PATH, (float)9999 }, + { TASK_WAIT_FOR_MOVEMENT, (float)0 }, }; -Schedule_t slIdleWalk[] = +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 | + 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_COMBAT |// sound flags - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | + bits_SOUND_MEAT |// scents + bits_SOUND_CARCASS | bits_SOUND_GARBAGE, "Idle Walk" }, @@ -128,23 +127,22 @@ Schedule_t slIdleWalk[] = // Ambush - monster stands in place and waits for a new // enemy, or chance to attack an existing enemy. //========================================================= -Task_t tlAmbush[] = +Task_t tlAmbush[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_INDEFINITE, (float)0 }, }; -Schedule_t slAmbush[] = +Schedule_t slAmbush[] = { - { + { tlAmbush, - ARRAYSIZE ( tlAmbush ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + ARRAYSIZE( tlAmbush ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | bits_COND_PROVOKED, - 0, "Ambush" }, @@ -160,18 +158,18 @@ Schedule_t slAmbush[] = ///========================================================= 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 }, + { 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[] = @@ -179,15 +177,14 @@ Schedule_t slActiveIdle[] = { tlActiveIdle, ARRAYSIZE( tlActiveIdle ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | + 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_COMBAT | + bits_SOUND_WORLD | + bits_SOUND_PLAYER | bits_SOUND_DANGER, "Active Idle" } @@ -198,17 +195,17 @@ Schedule_t slActiveIdle[] = //========================================================= Task_t tlWakeAngry1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, + { 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 ), + ARRAYSIZE( tlWakeAngry1 ), 0, 0, "Wake Angry" @@ -218,22 +215,22 @@ Schedule_t slWakeAngry[] = //========================================================= // AlertFace Schedules //========================================================= -Task_t tlAlertFace1[] = +Task_t tlAlertFace1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_IDEAL, (float)0 }, }; -Schedule_t slAlertFace[] = +Schedule_t slAlertFace[] = { - { + { tlAlertFace1, - ARRAYSIZE ( tlAlertFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + ARRAYSIZE( tlAlertFace1 ), + bits_COND_NEW_ENEMY | + bits_COND_SEE_FEAR | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | bits_COND_PROVOKED, 0, "Alert Face" @@ -244,19 +241,19 @@ Schedule_t slAlertFace[] = // AlertSmallFlinch Schedule - shot, but didn't see attacker, // flinch then face //========================================================= -Task_t tlAlertSmallFlinch[] = +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 }, + { 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[] = +Schedule_t slAlertSmallFlinch[] = { - { + { tlAlertSmallFlinch, - ARRAYSIZE ( tlAlertSmallFlinch ), + ARRAYSIZE( tlAlertSmallFlinch ), 0, 0, "Alert Small Flinch" @@ -266,36 +263,34 @@ Schedule_t slAlertSmallFlinch[] = //========================================================= // AlertIdle Schedules //========================================================= -Task_t tlAlertStand1[] = +Task_t tlAlertStand1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)20 }, - { TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)20 }, + { TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, }; -Schedule_t slAlertStand[] = +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 | + 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_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" }, @@ -307,31 +302,30 @@ Schedule_t slAlertStand[] = //========================================================= 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 }, + { 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[] = +Schedule_t slInvestigateSound[] = { - { + { tlInvestigateSound, - ARRAYSIZE ( tlInvestigateSound ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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" }, @@ -340,22 +334,22 @@ Schedule_t slInvestigateSound[] = //========================================================= // CombatIdle Schedule //========================================================= -Task_t tlCombatStand1[] = +Task_t tlCombatStand1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_INDEFINITE, (float)0 }, }; -Schedule_t slCombatStand[] = +Schedule_t slCombatStand[] = { - { + { tlCombatStand1, - ARRAYSIZE ( tlCombatStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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" @@ -365,20 +359,20 @@ Schedule_t slCombatStand[] = //========================================================= // CombatFace Schedule //========================================================= -Task_t tlCombatFace1[] = +Task_t tlCombatFace1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_FACE_ENEMY, (float)0 }, }; -Schedule_t slCombatFace[] = +Schedule_t slCombatFace[] = { { tlCombatFace1, - ARRAYSIZE ( tlCombatFace1 ), - bits_COND_CAN_ATTACK | - bits_COND_NEW_ENEMY | + ARRAYSIZE( tlCombatFace1 ), + bits_COND_CAN_ATTACK | + bits_COND_NEW_ENEMY | bits_COND_ENEMY_DEAD, 0, "Combat Face" @@ -390,24 +384,23 @@ Schedule_t slCombatFace[] = // hiding in cover or the enemy has moved out of sight. // Should we look around in this schedule? //========================================================= -Task_t tlStandoff[] = +Task_t tlStandoff[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, + { 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 | + 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" } @@ -418,15 +411,15 @@ Schedule_t slStandoff[] = //========================================================= Task_t tlArmWeapon[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float) ACT_ARM } + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_ARM } }; -Schedule_t slArmWeapon[] = +Schedule_t slArmWeapon[] = { { tlArmWeapon, - ARRAYSIZE ( tlArmWeapon ), + ARRAYSIZE( tlArmWeapon ), 0, 0, "Arm Weapon" @@ -438,15 +431,15 @@ Schedule_t slArmWeapon[] = //========================================================= Task_t tlReload[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, }; -Schedule_t slReload[] = +Schedule_t slReload[] = { { tlReload, - ARRAYSIZE ( tlReload ), + ARRAYSIZE( tlReload ), bits_COND_HEAVY_DAMAGE, 0, "Reload" @@ -458,73 +451,71 @@ Schedule_t slReload[] = //========================================================= // primary range attack -Task_t tlRangeAttack1[] = +Task_t tlRangeAttack1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, }; -Schedule_t slRangeAttack1[] = +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 | + 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_t tlRangeAttack2[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK2, (float)0 }, }; -Schedule_t slRangeAttack2[] = +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 | + 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_t tlPrimaryMeleeAttack1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK1, (float)0 }, }; -Schedule_t slPrimaryMeleeAttack[] = +Schedule_t slPrimaryMeleeAttack[] = { - { + { tlPrimaryMeleeAttack1, - ARRAYSIZE ( tlPrimaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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" @@ -532,22 +523,22 @@ Schedule_t slPrimaryMeleeAttack[] = }; // secondary melee attack -Task_t tlSecondaryMeleeAttack1[] = +Task_t tlSecondaryMeleeAttack1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK2, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK2, (float)0}, }; -Schedule_t slSecondaryMeleeAttack[] = +Schedule_t slSecondaryMeleeAttack[] = { - { + { tlSecondaryMeleeAttack1, - ARRAYSIZE ( tlSecondaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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" @@ -555,79 +546,76 @@ Schedule_t slSecondaryMeleeAttack[] = }; // special attack1 -Task_t tlSpecialAttack1[] = +Task_t tlSpecialAttack1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SPECIAL_ATTACK1, (float)0 }, }; -Schedule_t slSpecialAttack1[] = +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 | + 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_t tlSpecialAttack2[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK2, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_SPECIAL_ATTACK2, (float)0 }, }; -Schedule_t slSpecialAttack2[] = +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 | + 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_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 }, + { 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 | + 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" }, @@ -635,52 +623,50 @@ Schedule_t slChaseEnemy[] = // Chase enemy failure schedule -Task_t tlChaseEnemyFailed[] = +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 }, + { 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[] = +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 | + 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 }, + { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, + { TASK_STOP_MOVING, 0 }, + { TASK_SMALL_FLINCH, 0 }, }; Schedule_t slSmallFlinch[] = { { tlSmallFlinch, - ARRAYSIZE ( tlSmallFlinch ), + ARRAYSIZE( tlSmallFlinch ), 0, 0, "Small Flinch" @@ -692,9 +678,9 @@ Schedule_t slSmallFlinch[] = //========================================================= Task_t tlDie1[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SOUND_DIE, (float)0 }, + { TASK_DIE, (float)0 }, }; Schedule_t slDie[] = @@ -713,9 +699,9 @@ Schedule_t slDie[] = //========================================================= Task_t tlVictoryDance[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_WAIT, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, + { TASK_WAIT, (float)0 }, }; Schedule_t slVictoryDance[] = @@ -734,19 +720,19 @@ Schedule_t slVictoryDance[] = // so play a hit animation, then play a cycling pull animation // as the creature is hoisting the monster. //========================================================= -Task_t tlBarnacleVictimGrab[] = +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. + { 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 ), + ARRAYSIZE( tlBarnacleVictimGrab ), 0, 0, "Barnacle Victim" @@ -758,123 +744,121 @@ Schedule_t slBarnacleVictimGrab[] = // mouth. Victim should play the BARNCLE_CHOMP animation // once, then loop the BARNACLE_CHEW animation indefinitely //========================================================= -Task_t tlBarnacleVictimChomp[] = +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. + { 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 ), + ARRAYSIZE( tlBarnacleVictimChomp ), 0, 0, "Barnacle Chomp" } }; - -// Universal Error Schedule -Task_t tlError[] = +// Universal Error Schedule +Task_t tlError[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_INDEFINITE, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_WAIT_INDEFINITE, (float)0 }, }; -Schedule_t slError[] = +Schedule_t slError[] = { - { + { tlError, - ARRAYSIZE ( tlError ), + ARRAYSIZE( tlError ), 0, 0, "Error" }, }; -Task_t tlScriptedWalk[] = +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 }, + { 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 ), + ARRAYSIZE( tlScriptedWalk ), SCRIPT_BREAK_CONDITIONS, 0, "WalkToScript" }, }; - -Task_t tlScriptedRun[] = +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 }, + { 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 ), + ARRAYSIZE( tlScriptedRun ), SCRIPT_BREAK_CONDITIONS, 0, "RunToScript" }, }; -Task_t tlScriptedWait[] = +Task_t tlScriptedWait[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_WAIT_FOR_SCRIPT, (float)0 }, + { TASK_PLAY_SCRIPT, (float)0 }, }; Schedule_t slWaitScript[] = { - { + { tlScriptedWait, - ARRAYSIZE ( tlScriptedWait ), + ARRAYSIZE( tlScriptedWait ), SCRIPT_BREAK_CONDITIONS, 0, "WaitForScript" }, }; -Task_t tlScriptedFace[] = +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 }, + { 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 ), + ARRAYSIZE( tlScriptedFace ), SCRIPT_BREAK_CONDITIONS, 0, "FaceScript" @@ -885,17 +869,17 @@ Schedule_t slFaceScript[] = // Cower - this is what is usually done when attempts // to escape danger fail. //========================================================= -Task_t tlCower[] = +Task_t tlCower[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_COWER }, + { TASK_STOP_MOVING, 0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_COWER }, }; -Schedule_t slCower[] = +Schedule_t slCower[] = { { tlCower, - ARRAYSIZE ( tlCower ), + ARRAYSIZE( tlCower ), 0, 0, "Cower" @@ -905,21 +889,21 @@ Schedule_t slCower[] = //========================================================= // move away from where you're currently standing. //========================================================= -Task_t tlTakeCoverFromOrigin[] = +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 }, + { 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[] = +Schedule_t slTakeCoverFromOrigin[] = { - { + { tlTakeCoverFromOrigin, - ARRAYSIZE ( tlTakeCoverFromOrigin ), + ARRAYSIZE( tlTakeCoverFromOrigin ), bits_COND_NEW_ENEMY, 0, "TakeCoverFromOrigin" @@ -929,21 +913,21 @@ Schedule_t slTakeCoverFromOrigin[] = //========================================================= // hide from the loudest sound source //========================================================= -Task_t tlTakeCoverFromBestSound[] = +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 }, + { 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[] = +Schedule_t slTakeCoverFromBestSound[] = { - { + { tlTakeCoverFromBestSound, - ARRAYSIZE ( tlTakeCoverFromBestSound ), + ARRAYSIZE( tlTakeCoverFromBestSound ), bits_COND_NEW_ENEMY, 0, "TakeCoverFromBestSound" @@ -954,31 +938,31 @@ Schedule_t slTakeCoverFromBestSound[] = // Take cover from enemy! Tries lateral cover before node // cover! //========================================================= -Task_t tlTakeCoverFromEnemy[] = +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 }, + { 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[] = +Schedule_t slTakeCoverFromEnemy[] = { - { + { tlTakeCoverFromEnemy, - ARRAYSIZE ( tlTakeCoverFromEnemy ), + ARRAYSIZE( tlTakeCoverFromEnemy ), bits_COND_NEW_ENEMY, 0, "tlTakeCoverFromEnemy" }, }; -Schedule_t *CBaseMonster::m_scheduleList[] = +Schedule_t *CBaseMonster::m_scheduleList[] = { slIdleStand, slIdleTrigger, @@ -1022,29 +1006,27 @@ Schedule_t *CBaseMonster::m_scheduleList[] = Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { - return ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) ); + return ScheduleInList( pName, m_scheduleList, ARRAYSIZE( m_scheduleList ) ); } - -Schedule_t *CBaseMonster :: ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) +Schedule_t *CBaseMonster::ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) { int i; - - if ( !pName ) + + if( !pName ) { - ALERT( at_console, "%s set to unnamed schedule!\n", STRING(pev->classname) ); + ALERT( at_console, "%s set to unnamed schedule!\n", STRING( pev->classname ) ); return NULL; } - - for ( i = 0; i < listCount; i++ ) + for( i = 0; i < listCount; i++ ) { - if ( !pList[i]->pName ) + if( !pList[i]->pName ) { ALERT( at_console, "Unnamed schedule!\n" ); continue; } - if ( stricmp( pName, pList[i]->pName ) == 0 ) + if( stricmp( pName, pList[i]->pName ) == 0 ) return pList[i]; } return NULL; @@ -1054,32 +1036,32 @@ Schedule_t *CBaseMonster :: ScheduleInList( const char *pName, Schedule_t **pLis // GetScheduleOfType - returns a pointer to one of the // monster's available schedules of the indicated type. //========================================================= -Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) +Schedule_t* CBaseMonster::GetScheduleOfType( int Type ) { -// ALERT ( at_console, "Sched Type:%d\n", Type ); - switch ( 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 ) + if( !m_pCine ) { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); + 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) ); + //else + // ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING( pev->classname ) ); - switch ( m_pCine->m_fMoveTo ) + switch( m_pCine->m_fMoveTo ) { - case 0: - case 4: + case 0: + case 4: return slWaitScript; - case 1: + case 1: return slWalkToScript; - case 2: + case 2: return slRunToScript; case 5: return slFaceScript; @@ -1088,132 +1070,132 @@ Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) } case SCHED_IDLE_STAND: { - if ( RANDOM_LONG(0,14) == 0 && FCanActiveIdle() ) + if( RANDOM_LONG( 0, 14 ) == 0 && FCanActiveIdle() ) { - return &slActiveIdle[ 0 ]; + return &slActiveIdle[0]; } - return &slIdleStand[ 0 ]; + return &slIdleStand[0]; } case SCHED_IDLE_WALK: { - return &slIdleWalk[ 0 ]; + return &slIdleWalk[0]; } case SCHED_WAIT_TRIGGER: { - return &slIdleTrigger[ 0 ]; + return &slIdleTrigger[0]; } case SCHED_WAKE_ANGRY: { - return &slWakeAngry[ 0 ]; + return &slWakeAngry[0]; } case SCHED_ALERT_FACE: { - return &slAlertFace[ 0 ]; + return &slAlertFace[0]; } case SCHED_ALERT_STAND: { - return &slAlertStand[ 0 ]; + return &slAlertStand[0]; } case SCHED_COMBAT_STAND: { - return &slCombatStand[ 0 ]; + return &slCombatStand[0]; } case SCHED_COMBAT_FACE: { - return &slCombatFace[ 0 ]; + return &slCombatFace[0]; } case SCHED_CHASE_ENEMY: { - return &slChaseEnemy[ 0 ]; + return &slChaseEnemy[0]; } case SCHED_CHASE_ENEMY_FAILED: { - return &slFail[ 0 ]; + return &slFail[0]; } case SCHED_SMALL_FLINCH: { - return &slSmallFlinch[ 0 ]; + return &slSmallFlinch[0]; } case SCHED_ALERT_SMALL_FLINCH: { - return &slAlertSmallFlinch[ 0 ]; + return &slAlertSmallFlinch[0]; } case SCHED_RELOAD: { - return &slReload[ 0 ]; + return &slReload[0]; } case SCHED_ARM_WEAPON: { - return &slArmWeapon[ 0 ]; + return &slArmWeapon[0]; } case SCHED_STANDOFF: { - return &slStandoff[ 0 ]; + return &slStandoff[0]; } case SCHED_RANGE_ATTACK1: { - return &slRangeAttack1[ 0 ]; + return &slRangeAttack1[0]; } case SCHED_RANGE_ATTACK2: { - return &slRangeAttack2[ 0 ]; + return &slRangeAttack2[0]; } case SCHED_MELEE_ATTACK1: { - return &slPrimaryMeleeAttack[ 0 ]; + return &slPrimaryMeleeAttack[0]; } case SCHED_MELEE_ATTACK2: { - return &slSecondaryMeleeAttack[ 0 ]; + return &slSecondaryMeleeAttack[0]; } case SCHED_SPECIAL_ATTACK1: { - return &slSpecialAttack1[ 0 ]; + return &slSpecialAttack1[0]; } case SCHED_SPECIAL_ATTACK2: { - return &slSpecialAttack2[ 0 ]; + return &slSpecialAttack2[0]; } case SCHED_TAKE_COVER_FROM_BEST_SOUND: { - return &slTakeCoverFromBestSound[ 0 ]; + return &slTakeCoverFromBestSound[0]; } case SCHED_TAKE_COVER_FROM_ENEMY: { - return &slTakeCoverFromEnemy[ 0 ]; + return &slTakeCoverFromEnemy[0]; } case SCHED_COWER: { - return &slCower[ 0 ]; + return &slCower[0]; } case SCHED_AMBUSH: { - return &slAmbush[ 0 ]; + return &slAmbush[0]; } case SCHED_BARNACLE_VICTIM_GRAB: { - return &slBarnacleVictimGrab[ 0 ]; + return &slBarnacleVictimGrab[0]; } case SCHED_BARNACLE_VICTIM_CHOMP: { - return &slBarnacleVictimChomp[ 0 ]; + return &slBarnacleVictimChomp[0]; } case SCHED_INVESTIGATE_SOUND: { - return &slInvestigateSound[ 0 ]; + return &slInvestigateSound[0]; } case SCHED_DIE: { - return &slDie[ 0 ]; + return &slDie[0]; } case SCHED_TAKE_COVER_FROM_ORIGIN: { - return &slTakeCoverFromOrigin[ 0 ]; + return &slTakeCoverFromOrigin[0]; } case SCHED_VICTORY_DANCE: { - return &slVictoryDance[ 0 ]; + return &slVictoryDance[0]; } case SCHED_FAIL: { @@ -1221,9 +1203,9 @@ Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) } default: { - ALERT ( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); + ALERT( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); - return &slIdleStand[ 0 ]; + return &slIdleStand[0]; break; } } diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 75e1fb17..26fca575 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -23,7 +23,7 @@ #include "cbase.h" #include "doors.h" -extern void SetMovedir(entvars_t* ev); +extern void SetMovedir( entvars_t *ev ); #define noiseMoving noise1 #define noiseArrived noise2 @@ -37,17 +37,16 @@ public: virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); virtual void Blocked( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) + virtual int ObjectCaps( void ) { - if (pev->spawnflags & SF_ITEM_USE_ONLY) - return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; + 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 int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; virtual void SetToggleState( int state ); @@ -55,23 +54,23 @@ public: void EXPORT DoorTouch( CBaseEntity *pOther ); // local functions - int DoorActivate( ); + 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 + + 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; + + BYTE m_bLockedSound; // ordinals from entity selection + BYTE m_bLockedSentence; + BYTE m_bUnlockedSound; + BYTE m_bUnlockedSentence; }; TYPEDESCRIPTION CBaseDoor::m_SaveData[] = @@ -79,12 +78,11 @@ 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 ), - + DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ), }; IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ) @@ -99,51 +97,51 @@ IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ) // 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) +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) + if( fbutton ) flsoundwait = BUTTON_SOUNDWAIT; else flsoundwait = DOOR_SOUNDWAIT; - if (flocked) + if( flocked ) { - int fplaysound = (pls->sLockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence); + int fplaysound = ( pls->sLockedSound && gpGlobals->time > pls->flwaitSound ); + int fplaysentence = ( pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence ); float fvol; - if (fplaysound && fplaysentence) + if( fplaysound && fplaysentence ) fvol = 0.25; else fvol = 1.0; // if there is a locked sound, and we've debounced, play sound - if (fplaysound) + if( fplaysound ) { // play 'door locked' sound - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sLockedSound), fvol, ATTN_NORM); + 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) + 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->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->bEOFLocked = ( iprev == pls->iLockedSentence ); + pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; } } @@ -151,34 +149,34 @@ void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) { // UNLOCKED SOUND - int fplaysound = (pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence); + 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) + if( fplaysound && fplaysentence ) fvol = 0.25; else fvol = 1.0; // play 'door unlocked' sound if set - if (fplaysound) + if( fplaysound ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sUnlockedSound), fvol, ATTN_NORM); + 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) + 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->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->bEOFUnlocked = ( iprev == pls->iUnlockedSentence ); pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; } } @@ -187,53 +185,51 @@ void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) // // 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 + if( FStrEq( pkvd->szKeyName, "skin" ) )//skin is used for content type { - pev->skin = atof(pkvd->szValue); + pev->skin = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "movesnd")) + else if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof(pkvd->szValue); + m_bMoveSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) + else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) { - m_bStopSnd = atof(pkvd->szValue); + m_bStopSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) + else if( FStrEq( pkvd->szKeyName, "healthvalue" ) ) { - m_bHealthValue = atof(pkvd->szValue); + m_bHealthValue = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) + else if( FStrEq( pkvd->szKeyName, "locked_sound" ) ) { - m_bLockedSound = atof(pkvd->szValue); + m_bLockedSound = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) + else if( FStrEq( pkvd->szKeyName, "locked_sentence" ) ) { - m_bLockedSentence = atof(pkvd->szValue); + m_bLockedSentence = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) + else if( FStrEq( pkvd->szKeyName, "unlocked_sound" ) ) { - m_bUnlockedSound = atof(pkvd->szValue); + m_bUnlockedSound = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) + else if( FStrEq( pkvd->szKeyName, "unlocked_sentence" ) ) { - m_bUnlockedSentence = atof(pkvd->szValue); + m_bUnlockedSentence = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "WaveHeight")) + else if( FStrEq( pkvd->szKeyName, "WaveHeight" ) ) { - pev->scale = atof(pkvd->szValue) * (1.0/8.0); + pev->scale = atof( pkvd->szValue ) * ( 1.0 / 8.0 ); pkvd->fHandled = TRUE; } else @@ -271,50 +267,50 @@ LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ) // LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ) -void CBaseDoor::Spawn( ) +void CBaseDoor::Spawn() { Precache(); - SetMovedir (pev); + SetMovedir( pev ); - if ( pev->skin == 0 ) + if( pev->skin == 0 ) { //normal door - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; + if( FBitSet( pev->spawnflags, SF_DOOR_PASSABLE ) ) + pev->solid = SOLID_NOT; else - pev->solid = SOLID_BSP; + pev->solid = SOLID_BSP; } else { // special contents - pev->solid = SOLID_NOT; + 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->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; + + 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) ) + 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); + 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 ) ) + if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) ) { SetTouch( NULL ); } @@ -322,9 +318,9 @@ void CBaseDoor::Spawn( ) SetTouch( &CBaseDoor::DoorTouch ); } -void CBaseDoor :: SetToggleState( int state ) +void CBaseDoor::SetToggleState( int state ) { - if ( state == TS_AT_TOP ) + if( state == TS_AT_TOP ) UTIL_SetOrigin( pev, m_vecPosition2 ); else UTIL_SetOrigin( pev, m_vecPosition1 ); @@ -335,142 +331,195 @@ void CBaseDoor::Precache( void ) char *pszSound; // set the door's "in-motion" sound - switch (m_bMoveSnd) + 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; + 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) + 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; + 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) + if( m_bLockedSound ) { pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); + PRECACHE_SOUND( pszSound ); + m_ls.sLockedSound = ALLOC_STRING( pszSound ); } - if (m_bUnlockedSound) + if( m_bUnlockedSound ) { pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); + PRECACHE_SOUND( pszSound ); + m_ls.sUnlockedSound = ALLOC_STRING( pszSound ); } // get sentence group names, for doors which are directly 'touched' to open - switch (m_bLockedSentence) + 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; + case 1: + // access denied + m_ls.sLockedSentence = ALLOC_STRING( "NA" ); + break; + case 2: + // security lockout + m_ls.sLockedSentence = ALLOC_STRING( "ND" ); + break; + case 3: + // blast door + m_ls.sLockedSentence = ALLOC_STRING( "NF" ); + break; + case 4: + // fire door + m_ls.sLockedSentence = ALLOC_STRING( "NFIRE" ); + break; + case 5: + // chemical door + m_ls.sLockedSentence = ALLOC_STRING( "NCHEM" ); + break; + case 6: + // radiation door + m_ls.sLockedSentence = ALLOC_STRING( "NRAD" ); + break; + case 7: + // gen containment + m_ls.sLockedSentence = ALLOC_STRING( "NCON" ); + break; + case 8: + // maintenance door + m_ls.sLockedSentence = ALLOC_STRING( "NH" ); + break; + case 9: + // broken door + m_ls.sLockedSentence = ALLOC_STRING( "NG" ); + break; + default: + m_ls.sLockedSentence = 0; + break; } - switch (m_bUnlockedSentence) + 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; + case 1: + // access granted + m_ls.sUnlockedSentence = ALLOC_STRING( "EA" ); + break; + case 2: + // security door + m_ls.sUnlockedSentence = ALLOC_STRING( "ED" ); + break; + case 3: + // blast door + m_ls.sUnlockedSentence = ALLOC_STRING( "EF" ); + break; + case 4: + // fire door + m_ls.sUnlockedSentence = ALLOC_STRING( "EFIRE" ); + break; + case 5: + // chemical door + m_ls.sUnlockedSentence = ALLOC_STRING( "ECHEM" ); + break; + case 6: + // radiation door + m_ls.sUnlockedSentence = ALLOC_STRING( "ERAD" ); + break; + case 7: + // gen containment + m_ls.sUnlockedSentence = ALLOC_STRING( "ECON" ); + break; + case 8: + // maintenance door + m_ls.sUnlockedSentence = ALLOC_STRING( "EH" ); + break; + default: + m_ls.sUnlockedSentence = 0; + break; } } @@ -479,31 +528,29 @@ void CBaseDoor::Precache( void ) // void CBaseDoor::DoorTouch( CBaseEntity *pOther ) { - entvars_t* pevToucher = pOther->pev; - + entvars_t *pevToucher = pOther->pev; + // Ignore touches by anything but players - if (!FClassnameIs(pevToucher, "player")) + 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 (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)) + if( !FStringNull( pev->targetname ) ) { // play locked sound - PlayLockSounds(pev, &m_ls, TRUE, FALSE); + PlayLockSounds( pev, &m_ls, TRUE, FALSE ); return; } - + m_hActivator = pOther;// remember who activated the door - if (DoorActivate( )) + if( DoorActivate()) SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. } @@ -514,19 +561,19 @@ void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use { 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 ) ) + 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( ) +int CBaseDoor::DoorActivate() { - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + if( !UTIL_IsMasterTriggered( m_sMaster, m_hActivator ) ) return 0; - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) + if( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP ) { // door should close DoorGoDown(); @@ -534,18 +581,17 @@ int CBaseDoor::DoorActivate( ) else { // door should open - if ( m_hActivator != NULL && m_hActivator->IsPlayer() ) + if( m_hActivator != NULL && m_hActivator->IsPlayer() ) { // give health if player opened the door (medikit) //VARS( m_eoActivator )->health += m_bHealthValue; - - m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); + m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); } // play door unlock sounds - PlayLockSounds(pev, &m_ls, FALSE, FALSE); - + PlayLockSounds( pev, &m_ls, FALSE, FALSE ); + DoorGoUp(); } @@ -559,46 +605,46 @@ extern Vector VecBModelOrigin( entvars_t* pevBModel ); // void CBaseDoor::DoorGoUp( void ) { - entvars_t *pevActivator; + entvars_t *pevActivator; // It could be going-down, if blocked. - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); + 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); + 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 != NULL ) + 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 != NULL ) { pevActivator = m_hActivator->pev; - - if ( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player + + 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 ) + 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); + AngularMove( m_vecAngle2*sign, pev->speed ); } else - LinearMove(m_vecPosition2, pev->speed); + LinearMove( m_vecPosition2, pev->speed ); } // @@ -606,20 +652,20 @@ void CBaseDoor::DoorGoUp( void ) // void CBaseDoor::DoorHitTop( void ) { - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + 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); + 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); + 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)) + if( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) ) { // Re-instate touch method, movement is complete - if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + if( !FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) ) SetTouch( &CBaseDoor::DoorTouch ); } else @@ -628,15 +674,15 @@ void CBaseDoor::DoorHitTop( void ) pev->nextthink = pev->ltime + m_flWait; SetThink( &CBaseDoor::DoorGoDown ); - if ( m_flWait == -1 ) + 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 ); + 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 } @@ -646,19 +692,19 @@ void CBaseDoor::DoorHitTop( void ) // 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); + 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); + 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); + if( FClassnameIs( pev, "func_door_rotating" ) )//rotating door + AngularMove( m_vecAngle1, pev->speed ); else - LinearMove( m_vecPosition1, pev->speed); + LinearMove( m_vecPosition1, pev->speed ); } // @@ -666,17 +712,17 @@ void CBaseDoor::DoorGoDown( void ) // void CBaseDoor::DoorHitBottom( void ) { - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + 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); + 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); + 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 ) ) + if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) ) { // use only door SetTouch( NULL ); @@ -687,8 +733,8 @@ void CBaseDoor::DoorHitBottom( void ) 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 ); + if( pev->netname && !( pev->spawnflags & SF_DOOR_START_OPEN ) ) + FireTargets( STRING( pev->netname ), m_hActivator, this, USE_TOGGLE, 0 ); } void CBaseDoor::Blocked( CBaseEntity *pOther ) @@ -697,15 +743,14 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) CBaseDoor *pDoor = NULL; // Hurt the blocker a little. - if ( pev->dmg ) + 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_flWait >= 0 ) { - if (m_toggle_state == TS_GOING_DOWN) + if( m_toggle_state == TS_GOING_DOWN ) { DoorGoUp(); } @@ -716,43 +761,43 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) } // Block all door pieces with the same targetname here. - if ( !FStringNull ( pev->targetname ) ) + if( !FStringNull( pev->targetname ) ) { - for (;;) + for(;;) { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->targetname ) ); - if ( VARS( pentTarget ) != pev ) + if( VARS( pentTarget ) != pev ) { - if (FNullEnt(pentTarget)) + if( FNullEnt( pentTarget ) ) break; - if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) ) + if( FClassnameIs( pentTarget, "func_door" ) || FClassnameIs( pentTarget, "func_door_rotating" ) ) { - - pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) ); + pDoor = GetClassPtr( (CBaseDoor *)VARS( pentTarget ) ); - if ( pDoor->m_flWait >= 0) + if( pDoor->m_flWait >= 0 ) { - if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity) + 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 + 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 + { + // 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( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ) ); - - if ( pDoor->m_toggle_state == TS_GOING_DOWN) + if( pDoor->m_toggle_state == TS_GOING_DOWN ) pDoor->DoorGoUp(); else pDoor->DoorGoDown(); @@ -818,30 +863,30 @@ void CRotDoor::Spawn( void ) CBaseToggle::AxisDir( pev ); // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) + 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; + //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; + 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->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); + pev->movetype = MOVETYPE_PUSH; + UTIL_SetOrigin( pev, pev->origin ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if (pev->speed == 0) + 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) ) + if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN ) ) { // swap pos1 and pos2, put door at pos2, invert movement direction pev->angles = m_vecAngle2; @@ -853,7 +898,7 @@ void CRotDoor::Spawn( void ) m_toggle_state = TS_AT_BOTTOM; - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) + if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) ) { SetTouch( NULL ); } @@ -861,9 +906,9 @@ void CRotDoor::Spawn( void ) SetTouch( &CBaseDoor::DoorTouch ); } -void CRotDoor :: SetToggleState( int state ) +void CRotDoor::SetToggleState( int state ) { - if ( state == TS_AT_TOP ) + if( state == TS_AT_TOP ) pev->angles = m_vecAngle2; else pev->angles = m_vecAngle1; @@ -874,25 +919,25 @@ void CRotDoor :: SetToggleState( int state ) class CMomentaryDoor : public CBaseToggle { public: - void Spawn( void ); + void Spawn( void ); void Precache( void ); void EXPORT MomentaryMoveDone( 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; } + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - BYTE m_bMoveSnd; // sound a door makes while moving - BYTE m_bStopSnd; // sound a door makes when it stops + BYTE m_bMoveSnd; // sound a door makes while moving + BYTE m_bStopSnd; // sound a door makes when it stops }; LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ) -TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = +TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = { DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, FIELD_CHARACTER ), @@ -902,120 +947,120 @@ IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ) void CMomentaryDoor::Spawn( void ) { - SetMovedir (pev); + SetMovedir( pev ); - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) + UTIL_SetOrigin( pev, pev->origin ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); + + if( pev->speed == 0 ) pev->speed = 100; - if (pev->dmg == 0) + 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) ) + 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); + 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) + switch( m_bMoveSnd ) { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); + case 0: + pev->noiseMoving = ALLOC_STRING( "common/null.wav" ); break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + case 8: + PRECACHE_SOUND( "doors/doormove8.wav" ); + pev->noiseMoving = ALLOC_STRING( "doors/doormove8.wav" ); break; default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); + pev->noiseMoving = ALLOC_STRING( "common/null.wav" ); break; } // set the door's 'reached destination' stop sound - switch (m_bStopSnd) + switch( m_bStopSnd ) { - case 0: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); + case 0: + pev->noiseArrived = ALLOC_STRING(" common/null.wav "); break; - case 1: - PRECACHE_SOUND ("doors/doorstop1.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop1.wav"); + 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"); + case 2: + PRECACHE_SOUND( "doors/doorstop2.wav" ); + pev->noiseArrived = ALLOC_STRING( "doors/doorstop2.wav" ); break; - case 3: - PRECACHE_SOUND ("doors/doorstop3.wav"); + 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"); + 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"); + 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"); + 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"); + 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"); + case 8: + PRECACHE_SOUND( "doors/doorstop8.wav" ); + pev->noiseArrived = ALLOC_STRING( "doors/doorstop8.wav" ); break; default: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); + pev->noiseArrived = ALLOC_STRING( "common/null.wav" ); break; } } @@ -1023,19 +1068,19 @@ void CMomentaryDoor::Precache( void ) void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "movesnd")) + if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof(pkvd->szValue); + m_bMoveSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) + else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) { - m_bStopSnd = atof(pkvd->szValue); + m_bStopSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) + else if( FStrEq( pkvd->szKeyName, "healthvalue" ) ) { - //m_bHealthValue = atof(pkvd->szValue); + //m_bHealthValue = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1044,25 +1089,25 @@ void CMomentaryDoor::KeyValue( KeyValueData *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 + if( useType != USE_SET ) // Momentary buttons will pass down a float in here return; - if ( value > 1.0 ) + if( value > 1.0 ) value = 1.0; - if ( value < 0.0 ) + if( value < 0.0 ) value = 0.0; - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); + Vector move = m_vecPosition1 + ( value * ( m_vecPosition2 - m_vecPosition1 ) ); Vector delta = move - pev->origin; float speed = delta.Length() * 10; - if ( speed != 0 ) + if( speed != 0 ) { // 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 - if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); + if( pev->nextthink < pev->ltime || pev->nextthink == 0 ) + EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ), 1, ATTN_NORM ); LinearMove( move, speed ); SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); @@ -1072,6 +1117,6 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP void CMomentaryDoor::MomentaryMoveDone( void ) { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving)); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); + 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/dlls/doors.h b/dlls/doors.h index 80088615..7e89b497 100644 --- a/dlls/doors.h +++ b/dlls/doors.h @@ -18,16 +18,13 @@ // doors #define SF_DOOR_ROTATE_Y 0 #define SF_DOOR_START_OPEN 1 -#define SF_DOOR_ROTATE_BACKWARDS 2 +#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_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/dlls/effects.cpp b/dlls/effects.cpp index bd8bb160..e9492dd6 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -24,7 +24,7 @@ #include "func_break.h" #include "shake.h" -#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired +#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired #define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. @@ -34,22 +34,22 @@ 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 ); + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; + void EXPORT FizzThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_density; - int m_frequency; - int m_bubbleModel; - int m_state; + 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 ) @@ -69,8 +69,8 @@ IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ) void CBubbling::Spawn( void ) { - Precache( ); - SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size + 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 @@ -80,10 +80,9 @@ void CBubbling::Spawn( void ) // HACKHACK!!! - Speed in rendercolor pev->rendercolor.x = speed >> 8; pev->rendercolor.y = speed & 255; - pev->rendercolor.z = (pev->speed < 0) ? 1 : 0; + pev->rendercolor.z = ( pev->speed < 0 ) ? 1 : 0; - - if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) + if( !( pev->spawnflags & SF_BUBBLES_STARTOFF ) ) { SetThink( &CBubbling::FizzThink ); pev->nextthink = gpGlobals->time + 2.0; @@ -95,15 +94,15 @@ void CBubbling::Spawn( void ) void CBubbling::Precache( void ) { - m_bubbleModel = PRECACHE_MODEL("sprites/bubble.spr"); // Precache bubble sprite + 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 ) ) + if( ShouldToggle( useType, m_state ) ) m_state = !m_state; - if ( m_state ) + if( m_state ) { SetThink( &CBubbling::FizzThink ); pev->nextthink = gpGlobals->time + 0.1; @@ -117,19 +116,19 @@ void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use void CBubbling::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "density")) + if( FStrEq( pkvd->szKeyName, "density" ) ) { - m_density = atoi(pkvd->szValue); + m_density = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "frequency")) + else if( FStrEq( pkvd->szKeyName, "frequency" ) ) { - m_frequency = atoi(pkvd->szValue); + m_frequency = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "current")) + else if( FStrEq( pkvd->szKeyName, "current" ) ) { - pev->speed = atoi(pkvd->szValue); + pev->speed = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -138,17 +137,17 @@ void CBubbling::KeyValue( KeyValueData *pkvd ) void CBubbling::FizzThink( void ) { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); + 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 ) + if( m_frequency > 19 ) pev->nextthink = gpGlobals->time + 0.5; else - pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency); + pev->nextthink = gpGlobals->time + 2.5 - ( 0.1 * m_frequency ); } // -------------------------------------------------- @@ -162,33 +161,33 @@ LINK_ENTITY_TO_CLASS( beam, CBeam ) void CBeam::Spawn( void ) { pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); + Precache(); } void CBeam::Precache( void ) { - if ( pev->owner ) + if( pev->owner ) SetStartEntity( ENTINDEX( pev->owner ) ); - if ( pev->aiment ) + if( pev->aiment ) SetEndEntity( ENTINDEX( pev->aiment ) ); } -void CBeam::SetStartEntity( int entityIndex ) +void CBeam::SetStartEntity( int entityIndex ) { - pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); + pev->sequence = ( entityIndex & 0x0FFF ) | ( ( pev->sequence & 0xF000 ) << 12 ); pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); } -void CBeam::SetEndEntity( int entityIndex ) +void CBeam::SetEndEntity( int entityIndex ) { - pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); + 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 ) + if( GetType() == BEAM_ENTS ) { edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); return pent->v.origin; @@ -199,13 +198,13 @@ const Vector &CBeam::GetStartPos( void ) const Vector &CBeam::GetEndPos( void ) { int type = GetType(); - if ( type == BEAM_POINTS || type == BEAM_HOSE ) + if( type == BEAM_POINTS || type == BEAM_HOSE ) { return pev->angles; } edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); - if ( pent ) + if( pent ) return pent->v.origin; return pev->angles; } @@ -214,7 +213,7 @@ 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->pev->classname = MAKE_STRING( "beam" ); pBeam->BeamInit( pSpriteName, width ); @@ -310,11 +309,11 @@ void CBeam::SetObjectCollisionBox( void ) void CBeam::TriggerTouch( CBaseEntity *pOther ) { - if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) + if( pOther->pev->flags & ( FL_CLIENT | FL_MONSTER ) ) { - if ( pev->owner ) + if( pev->owner ) { - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); pOwner->Use( pOther, this, USE_TOGGLE, 0 ); } ALERT( at_console, "Firing targets!!!\n" ); @@ -327,10 +326,10 @@ CBaseEntity *CBeam::RandomTargetname( const char *szName ) CBaseEntity *pEntity = NULL; CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) + while( ( pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName ) ) != NULL ) { total++; - if (RANDOM_LONG(0,total-1) < 1) + if( RANDOM_LONG( 0, total - 1 ) < 1 ) pEntity = pNewEntity; } return pEntity; @@ -338,13 +337,13 @@ CBaseEntity *CBeam::RandomTargetname( const char *szName ) void CBeam::DoSparks( const Vector &start, const Vector &end ) { - if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) + if( pev->spawnflags & ( SF_BEAM_SPARKSTART | SF_BEAM_SPARKEND ) ) { - if ( pev->spawnflags & SF_BEAM_SPARKSTART ) + if( pev->spawnflags & SF_BEAM_SPARKSTART ) { UTIL_Sparks( start ); } - if ( pev->spawnflags & SF_BEAM_SPARKEND ) + if( pev->spawnflags & SF_BEAM_SPARKEND ) { UTIL_Sparks( end ); } @@ -354,44 +353,44 @@ void CBeam::DoSparks( const Vector &start, const Vector &end ) class CLightning : public CBeam { public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); + 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 ); + 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) ) + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - void BeamUpdateVars( void ); + void BeamUpdateVars( void ); - int m_active; - int m_iszStartEntity; - int m_iszEndEntity; + int m_active; + int m_iszStartEntity; + int m_iszEndEntity; float m_life; - int m_boltWidth; - int m_noiseAmplitude; - int m_brightness; - int m_speed; + int m_boltWidth; + int m_noiseAmplitude; + int m_brightness; + int m_speed; float m_restrike; - int m_spriteTexture; - int m_iszSpriteName; - int m_frameStart; + int m_spriteTexture; + int m_iszSpriteName; + int m_frameStart; float m_radius; }; @@ -417,7 +416,7 @@ void CTripBeam::Spawn( void ) } #endif -TYPEDESCRIPTION CLightning::m_SaveData[] = +TYPEDESCRIPTION CLightning::m_SaveData[] = { DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ), @@ -438,27 +437,27 @@ IMPLEMENT_SAVERESTORE( CLightning, CBeam ) void CLightning::Spawn( void ) { - if ( FStringNull( m_iszSpriteName ) ) + if( FStringNull( m_iszSpriteName ) ) { SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); + Precache(); pev->dmgtime = gpGlobals->time; - if ( ServerSide() ) + if( ServerSide() ) { SetThink( NULL ); - if ( pev->dmg > 0 ) + if( pev->dmg > 0 ) { SetThink( &CLightning::DamageThink ); pev->nextthink = gpGlobals->time + 0.1; } - if ( pev->targetname ) + if( pev->targetname ) { - if ( !(pev->spawnflags & SF_BEAM_STARTON) ) + if( !( pev->spawnflags & SF_BEAM_STARTON ) ) { pev->effects = EF_NODRAW; m_active = 0; @@ -473,11 +472,11 @@ void CLightning::Spawn( void ) else { m_active = 0; - if ( !FStringNull(pev->targetname) ) + if( !FStringNull( pev->targetname ) ) { SetUse( &CLightning::StrikeUse ); } - if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) + if( FStringNull( pev->targetname ) || FBitSet( pev->spawnflags, SF_BEAM_STARTON ) ) { SetThink( &CLightning::StrikeThink ); pev->nextthink = gpGlobals->time + 1.0; @@ -487,71 +486,71 @@ void CLightning::Spawn( void ) void CLightning::Precache( void ) { - m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); + m_spriteTexture = PRECACHE_MODEL( (char *)STRING( m_iszSpriteName ) ); CBeam::Precache(); } void CLightning::Activate( void ) { - if ( ServerSide() ) + if( ServerSide() ) BeamUpdateVars(); } void CLightning::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "LightningStart")) + if( FStrEq( pkvd->szKeyName, "LightningStart" ) ) { m_iszStartEntity = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "LightningEnd")) + else if( FStrEq( pkvd->szKeyName, "LightningEnd" ) ) { m_iszEndEntity = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "life")) + else if( FStrEq( pkvd->szKeyName, "life" ) ) { - m_life = atof(pkvd->szValue); + m_life = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "BoltWidth")) + else if( FStrEq( pkvd->szKeyName, "BoltWidth" ) ) { - m_boltWidth = atoi(pkvd->szValue); + m_boltWidth = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) + else if( FStrEq( pkvd->szKeyName, "NoiseAmplitude" ) ) { - m_noiseAmplitude = atoi(pkvd->szValue); + m_noiseAmplitude = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) + else if( FStrEq( pkvd->szKeyName, "TextureScroll" ) ) { - m_speed = atoi(pkvd->szValue); + m_speed = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "StrikeTime")) + else if( FStrEq( pkvd->szKeyName, "StrikeTime" ) ) { - m_restrike = atof(pkvd->szValue); + m_restrike = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "texture")) + else if( FStrEq( pkvd->szKeyName, "texture" ) ) { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); + m_iszSpriteName = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "framestart")) + else if( FStrEq( pkvd->szKeyName, "framestart" ) ) { - m_frameStart = atoi(pkvd->szValue); + m_frameStart = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "Radius")) + else if( FStrEq( pkvd->szKeyName, "Radius" ) ) { m_radius = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "damage")) + else if( FStrEq( pkvd->szKeyName, "damage" ) ) { - pev->dmg = atof(pkvd->szValue); + pev->dmg = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -560,9 +559,9 @@ void CLightning::KeyValue( KeyValueData *pkvd ) void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_active ) ) + if( !ShouldToggle( useType, m_active ) ) return; - if ( m_active ) + if( m_active ) { m_active = 0; pev->effects |= EF_NODRAW; @@ -573,7 +572,7 @@ void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T m_active = 1; pev->effects &= ~EF_NODRAW; DoSparks( GetStartPos(), GetEndPos() ); - if ( pev->dmg > 0 ) + if( pev->dmg > 0 ) { pev->nextthink = gpGlobals->time; pev->dmgtime = gpGlobals->time; @@ -583,10 +582,10 @@ void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_active ) ) + if( !ShouldToggle( useType, m_active ) ) return; - if ( m_active ) + if( m_active ) { m_active = 0; SetThink( NULL ); @@ -597,15 +596,15 @@ void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T pev->nextthink = gpGlobals->time + 0.1; } - if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) + if( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) SetUse( NULL ); } int IsPointEntity( CBaseEntity *pEnt ) { - if ( !pEnt->pev->modelindex ) + if( !pEnt->pev->modelindex ) return 1; - if ( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) + if( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) return 1; return 0; @@ -613,40 +612,40 @@ int IsPointEntity( CBaseEntity *pEnt ) void CLightning::StrikeThink( void ) { - if ( m_life != 0 ) + if( m_life != 0 ) { - if ( pev->spawnflags & SF_BEAM_RANDOM ) + 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_iszEndEntity ) ) { - if (FStringNull(m_iszStartEntity)) + if( FStringNull( m_iszStartEntity ) ) { - RandomArea( ); + RandomArea(); } else { - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - if (pStart != NULL) + 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) ); + 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) ); + CBaseEntity *pStart = RandomTargetname( STRING( m_iszStartEntity ) ); + CBaseEntity *pEnd = RandomTargetname( STRING( m_iszEndEntity ) ); - if ( pStart != NULL && pEnd != NULL ) + if( pStart != NULL && pEnd != NULL ) { - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) + if( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) { - if ( pev->spawnflags & SF_BEAM_RING) + if( pev->spawnflags & SF_BEAM_RING ) { // don't work return; @@ -654,39 +653,38 @@ void CLightning::StrikeThink( void ) } MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) + if( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) { - if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd + if( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd { CBaseEntity *pTemp; pTemp = pStart; pStart = pEnd; pEnd = pTemp; } - if ( !IsPointEntity( pStart ) ) // One sided + 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); + 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); + 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) + if( pev->spawnflags & SF_BEAM_RING ) WRITE_BYTE( TE_BEAMRING ); else WRITE_BYTE( TE_BEAMENTS ); @@ -696,8 +694,8 @@ void CLightning::StrikeThink( void ) 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( (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 @@ -707,7 +705,7 @@ void CLightning::StrikeThink( void ) WRITE_BYTE( m_speed ); // speed MESSAGE_END(); DoSparks( pStart->pev->origin, pEnd->pev->origin ); - if ( pev->dmg > 0 ) + if( pev->dmg > 0 ) { TraceResult tr; UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); @@ -719,18 +717,18 @@ void CLightning::StrikeThink( void ) void CBeam::BeamDamage( TraceResult *ptr ) { RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) + if( ptr->flFraction != 1.0 && ptr->pHit != NULL ) { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) + 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 ); + 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( pev->spawnflags & SF_BEAM_DECALS ) { - if ( pHit->IsBSPModel() ) - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); + if( pHit->IsBSPModel() ) + UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG( 0, 4 ) ); } } } @@ -749,17 +747,17 @@ 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_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( (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 @@ -770,17 +768,17 @@ void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) 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); + 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 ); @@ -788,37 +786,38 @@ void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) void CLightning::RandomArea( void ) { - int iLoops = 0; + int iLoops; - for (iLoops = 0; iLoops < 10; iLoops++) + 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 ); + TraceResult tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT( pev ), &tr1 ); - if (tr1.flFraction == 1.0) + if( tr1.flFraction == 1.0 ) continue; Vector vecDir2; - do { + 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); + } while( DotProduct( vecDir1, vecDir2 ) > 0 ); vecDir2 = vecDir2.Normalize(); - TraceResult tr2; - UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 ); + TraceResult tr2; + UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT( pev ), &tr2 ); - if (tr2.flFraction == 1.0) + if( tr2.flFraction == 1.0 ) continue; - if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1) + if( ( tr1.vecEndPos - tr2.vecEndPos ).Length() < m_radius * 0.1 ) continue; - UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 ); + UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT( pev ), &tr2 ); - if (tr2.flFraction != 1.0) + if( tr2.flFraction != 1.0 ) continue; Zap( tr1.vecEndPos, tr2.vecEndPos ); @@ -829,19 +828,19 @@ void CLightning::RandomArea( void ) void CLightning::RandomPoint( Vector &vecSrc ) { - int iLoops = 0; + int iLoops; - for (iLoops = 0; iLoops < 10; iLoops++) + 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 ); + TraceResult tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT( pev ), &tr1 ); - if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1) + if( ( tr1.vecEndPos - vecSrc ).Length() < m_radius * 0.1 ) continue; - if (tr1.flFraction == 1.0) + if( tr1.flFraction == 1.0 ) continue; Zap( vecSrc, tr1.vecEndPos ); @@ -854,10 +853,10 @@ 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) ); + 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; @@ -867,9 +866,9 @@ void CLightning::BeamUpdateVars( void ) SetTexture( m_spriteTexture ); beamType = BEAM_ENTS; - if ( pointStart || pointEnd ) + if( pointStart || pointEnd ) { - if ( !pointStart ) // One point entity must be in pStart + if( !pointStart ) // One point entity must be in pStart { edict_t *pTemp; // Swap start & end @@ -880,25 +879,25 @@ void CLightning::BeamUpdateVars( void ) pointStart = pointEnd; pointEnd = swap; } - if ( !pointEnd ) + if( !pointEnd ) beamType = BEAM_ENTPOINT; else beamType = BEAM_POINTS; } SetType( beamType ); - if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) + if( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) { SetStartPos( pStart->v.origin ); - if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) + if( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) SetEndPos( pEnd->v.origin ); else - SetEndEntity( ENTINDEX(pEnd) ); + SetEndEntity( ENTINDEX( pEnd ) ); } else { - SetStartEntity( ENTINDEX(pStart) ); - SetEndEntity( ENTINDEX(pEnd) ); + SetStartEntity( ENTINDEX( pStart ) ); + SetEndEntity( ENTINDEX( pEnd ) ); } RelinkBeam(); @@ -907,15 +906,15 @@ void CLightning::BeamUpdateVars( void ) SetNoise( m_noiseAmplitude ); SetFrame( m_frameStart ); SetScrollRate( m_speed ); - if ( pev->spawnflags & SF_BEAM_SHADEIN ) + if( pev->spawnflags & SF_BEAM_SHADEIN ) SetFlags( BEAM_FSHADEIN ); - else if ( pev->spawnflags & SF_BEAM_SHADEOUT ) + else if( pev->spawnflags & SF_BEAM_SHADEOUT ) SetFlags( BEAM_FSHADEOUT ); } LINK_ENTITY_TO_CLASS( env_laser, CLaser ) -TYPEDESCRIPTION CLaser::m_SaveData[] = +TYPEDESCRIPTION CLaser::m_SaveData[] = { DEFINE_FIELD( CLaser, m_pSprite, FIELD_CLASSPTR ), DEFINE_FIELD( CLaser, m_iszSpriteName, FIELD_STRING ), @@ -926,28 +925,28 @@ IMPLEMENT_SAVERESTORE( CLaser, CBeam ) void CLaser::Spawn( void ) { - if ( FStringNull( pev->model ) ) + if( FStringNull( pev->model ) ) { SetThink( &CBaseEntity::SUB_Remove ); return; } pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); + 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 ); + if( !m_pSprite && m_iszSpriteName ) + m_pSprite = CSprite::SpriteCreate( STRING( m_iszSpriteName ), pev->origin, TRUE ); else m_pSprite = NULL; - if ( m_pSprite ) + if( m_pSprite ) m_pSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); - if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) ) + if( pev->targetname && !( pev->spawnflags & SF_BEAM_STARTON ) ) TurnOff(); else TurnOn(); @@ -955,51 +954,51 @@ void CLaser::Spawn( void ) void CLaser::Precache( void ) { - pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - if ( m_iszSpriteName ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); + 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")) + if( FStrEq( pkvd->szKeyName, "LaserTarget" ) ) { pev->message = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "width")) + else if( FStrEq( pkvd->szKeyName, "width" ) ) { - SetWidth( (int)atof(pkvd->szValue) ); + SetWidth( (int)atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) + else if( FStrEq( pkvd->szKeyName, "NoiseAmplitude" ) ) { - SetNoise( atoi(pkvd->szValue) ); + SetNoise( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) + else if( FStrEq( pkvd->szKeyName, "TextureScroll" ) ) { - SetScrollRate( atoi(pkvd->szValue) ); + SetScrollRate( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "texture")) + else if( FStrEq( pkvd->szKeyName, "texture" ) ) { - pev->model = ALLOC_STRING(pkvd->szValue); + pev->model = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "EndSprite")) + else if( FStrEq( pkvd->szKeyName, "EndSprite" ) ) { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); + m_iszSpriteName = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "framestart")) + else if( FStrEq( pkvd->szKeyName, "framestart" ) ) { - pev->frame = atoi(pkvd->szValue); + pev->frame = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "damage")) + else if( FStrEq( pkvd->szKeyName, "damage" ) ) { - pev->dmg = atof(pkvd->szValue); + pev->dmg = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1008,7 +1007,7 @@ void CLaser::KeyValue( KeyValueData *pkvd ) int CLaser::IsOn( void ) { - if (pev->effects & EF_NODRAW) + if( pev->effects & EF_NODRAW ) return 0; return 1; } @@ -1017,14 +1016,14 @@ void CLaser::TurnOff( void ) { pev->effects |= EF_NODRAW; pev->nextthink = 0; - if ( m_pSprite ) + if( m_pSprite ) m_pSprite->TurnOff(); } void CLaser::TurnOn( void ) { pev->effects &= ~EF_NODRAW; - if ( m_pSprite ) + if( m_pSprite ) m_pSprite->TurnOn(); pev->dmgtime = gpGlobals->time; pev->nextthink = gpGlobals->time; @@ -1034,9 +1033,9 @@ void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp { int active = IsOn(); - if ( !ShouldToggle( useType, active ) ) + if( !ShouldToggle( useType, active ) ) return; - if ( active ) + if( active ) { TurnOff(); } @@ -1049,7 +1048,7 @@ void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp void CLaser::FireAtPoint( TraceResult &tr ) { SetEndPos( tr.vecEndPos ); - if ( m_pSprite ) + if( m_pSprite ) UTIL_SetOrigin( m_pSprite->pev, tr.vecEndPos ); BeamDamage( &tr ); @@ -1058,9 +1057,9 @@ void CLaser::FireAtPoint( TraceResult &tr ) void CLaser::StrikeThink( void ) { - CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) ); + CBaseEntity *pEnd = RandomTargetname( STRING( pev->message ) ); - if ( pEnd ) + if( pEnd ) m_firePosition = pEnd->pev->origin; TraceResult tr; @@ -1076,17 +1075,17 @@ 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - float m_lastTime; - float m_maxFrame; + float m_lastTime; + float m_maxFrame; }; LINK_ENTITY_TO_CLASS( env_glow, CGlow ) -TYPEDESCRIPTION CGlow::m_SaveData[] = +TYPEDESCRIPTION CGlow::m_SaveData[] = { DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ), DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), @@ -1096,16 +1095,16 @@ IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ) void CGlow::Spawn( void ) { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; + 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) ); + 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 ) + if( m_maxFrame > 1.0 && pev->framerate != 0 ) pev->nextthink = gpGlobals->time + 0.1; m_lastTime = gpGlobals->time; @@ -1113,21 +1112,21 @@ void CGlow::Spawn( void ) void CGlow::Think( void ) { - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + Animate( pev->framerate * ( gpGlobals->time - m_lastTime ) ); - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; } void CGlow::Animate( float frames ) { - if ( m_maxFrame > 0 ) + if( m_maxFrame > 0 ) pev->frame = fmod( pev->frame + frames, m_maxFrame ); } LINK_ENTITY_TO_CLASS( env_sprite, CSprite ) -TYPEDESCRIPTION CSprite::m_SaveData[] = +TYPEDESCRIPTION CSprite::m_SaveData[] = { DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ), DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), @@ -1137,22 +1136,22 @@ IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ) void CSprite::Spawn( void ) { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; Precache(); - SET_MODEL( ENT(pev), STRING(pev->model) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) + 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 ) + if( pev->angles.y != 0 && pev->angles.z == 0 ) { pev->angles.z = pev->angles.y; pev->angles.y = 0; @@ -1161,10 +1160,10 @@ void CSprite::Spawn( void ) void CSprite::Precache( void ) { - PRECACHE_MODEL( (char *)STRING(pev->model) ); + PRECACHE_MODEL( (char *)STRING( pev->model ) ); // Reset attachment after save/restore - if ( pev->aiment ) + if( pev->aiment ) SetAttachment( pev->aiment, pev->body ); else { @@ -1176,7 +1175,7 @@ void CSprite::Precache( void ) void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) { - pev->model = MAKE_STRING(pSpriteName); + pev->model = MAKE_STRING( pSpriteName ); pev->origin = origin; Spawn(); } @@ -1185,10 +1184,10 @@ CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, B { CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); pSprite->SpriteInit( pSpriteName, origin ); - pSprite->pev->classname = MAKE_STRING("env_sprite"); + pSprite->pev->classname = MAKE_STRING( "env_sprite" ); pSprite->pev->solid = SOLID_NOT; pSprite->pev->movetype = MOVETYPE_NOCLIP; - if ( animate ) + if( animate ) pSprite->TurnOn(); return pSprite; @@ -1196,16 +1195,16 @@ CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, B void CSprite::AnimateThink( void ) { - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + Animate( pev->framerate * ( gpGlobals->time - m_lastTime ) ); - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; + pev->nextthink = gpGlobals->time + 0.1; + m_lastTime = gpGlobals->time; } void CSprite::AnimateUntilDead( void ) { - if ( gpGlobals->time > pev->dmgtime ) - UTIL_Remove(this); + if( gpGlobals->time > pev->dmgtime ) + UTIL_Remove( this ); else { AnimateThink(); @@ -1220,7 +1219,7 @@ void CSprite::Expand( float scaleSpeed, float fadeSpeed ) SetThink( &CSprite::ExpandThink ); pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; + m_lastTime = gpGlobals->time; } void CSprite::ExpandThink( void ) @@ -1228,30 +1227,30 @@ void CSprite::ExpandThink( void ) float frametime = gpGlobals->time - m_lastTime; pev->scale += pev->speed * frametime; pev->renderamt -= pev->health * frametime; - if ( pev->renderamt <= 0 ) + if( pev->renderamt <= 0 ) { pev->renderamt = 0; UTIL_Remove( this ); } else { - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; + 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->frame > m_maxFrame ) { - if ( pev->spawnflags & SF_SPRITE_ONCE ) + if( pev->spawnflags & SF_SPRITE_ONCE ) { TurnOff(); } else { - if ( m_maxFrame > 0 ) + if( m_maxFrame > 0 ) pev->frame = fmod( pev->frame, m_maxFrame ); } } @@ -1266,7 +1265,7 @@ void CSprite::TurnOff( void ) void CSprite::TurnOn( void ) { pev->effects = 0; - if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) + if( ( pev->framerate && m_maxFrame > 1.0 ) || ( pev->spawnflags & SF_SPRITE_ONCE ) ) { SetThink( &CSprite::CSprite::AnimateThink ); pev->nextthink = gpGlobals->time; @@ -1278,9 +1277,9 @@ void CSprite::TurnOn( void ) void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int on = pev->effects != EF_NODRAW; - if ( ShouldToggle( useType, on ) ) + if( ShouldToggle( useType, on ) ) { - if ( on ) + if( on ) { TurnOff(); } @@ -1294,19 +1293,19 @@ void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy class CGibShooter : public CBaseDelay { public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_iGibs; + int m_iGibs; int m_iGibCapacity; int m_iGibMaterial; int m_iGibModelIndex; @@ -1329,38 +1328,38 @@ TYPEDESCRIPTION CGibShooter::m_SaveData[] = IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ) LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ) -void CGibShooter :: Precache ( void ) +void CGibShooter::Precache( void ) { - if ( g_Language == LANGUAGE_GERMAN ) + if( g_Language == LANGUAGE_GERMAN ) { - m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl"); + m_iGibModelIndex = PRECACHE_MODEL( "models/germanygibs.mdl" ); } else { - m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl"); + m_iGibModelIndex = PRECACHE_MODEL( "models/hgibs.mdl" ); } } void CGibShooter::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "m_iGibs")) + if( FStrEq( pkvd->szKeyName, "m_iGibs" ) ) { - m_iGibs = m_iGibCapacity = atoi(pkvd->szValue); + m_iGibs = m_iGibCapacity = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flVelocity")) + else if( FStrEq( pkvd->szKeyName, "m_flVelocity" ) ) { - m_flGibVelocity = atof(pkvd->szValue); + m_flGibVelocity = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flVariance")) + else if( FStrEq( pkvd->szKeyName, "m_flVariance" ) ) { - m_flVariance = atof(pkvd->szValue); + m_flVariance = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flGibLife")) + else if( FStrEq( pkvd->szKeyName, "m_flGibLife" ) ) { - m_flGibLife = atof(pkvd->szValue); + m_flGibLife = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1382,40 +1381,40 @@ void CGibShooter::Spawn( void ) pev->solid = SOLID_NOT; pev->effects = EF_NODRAW; - if ( m_flDelay == 0 ) + if( m_flDelay == 0 ) { m_flDelay = 0.1; } - if ( m_flGibLife == 0 ) + if( m_flGibLife == 0 ) { m_flGibLife = 25; } - SetMovedir ( pev ); + SetMovedir( pev ); pev->body = MODEL_FRAMES( m_iGibModelIndex ); } -CGib *CGibShooter :: CreateGib ( void ) +CGib *CGibShooter::CreateGib( void ) { - if ( CVAR_GET_FLOAT("violence_hgibs") == 0 ) + 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 ) + if( pev->body <= 1 ) { - ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" ); + 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). + pGib->pev->body = RANDOM_LONG( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull). return pGib; } -void CGibShooter :: ShootThink ( void ) +void CGibShooter::ShootThink( void ) { pev->nextthink = gpGlobals->time + m_flDelay; @@ -1423,35 +1422,34 @@ void CGibShooter :: ShootThink ( void ) 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 + 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 ) + 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 ); + + 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->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( --m_iGibs <= 0 ) { - if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) + if( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) { m_iGibs = m_iGibCapacity; SetThink( NULL ); @@ -1467,24 +1465,24 @@ void CGibShooter :: ShootThink ( void ) class CEnvShooter : public CGibShooter { - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); - CGib *CreateGib( void ); + CGib *CreateGib( void ); }; LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ) -void CEnvShooter :: KeyValue( KeyValueData *pkvd ) +void CEnvShooter::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "shootmodel")) + if( FStrEq( pkvd->szKeyName, "shootmodel" ) ) { - pev->model = ALLOC_STRING(pkvd->szValue); + pev->model = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "shootsounds")) + else if ( FStrEq( pkvd->szKeyName, "shootsounds" ) ) { - int iNoise = atoi(pkvd->szValue); + int iNoise = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; switch( iNoise ) { @@ -1503,7 +1501,6 @@ void CEnvShooter :: KeyValue( KeyValueData *pkvd ) case 4: m_iGibMaterial = matRocks; break; - default: case -1: m_iGibMaterial = matNone; @@ -1516,22 +1513,22 @@ void CEnvShooter :: KeyValue( KeyValueData *pkvd ) } } -void CEnvShooter :: Precache ( void ) +void CEnvShooter::Precache( void ) { - m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) ); + m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING( pev->model ) ); CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); } -CGib *CEnvShooter :: CreateGib ( void ) +CGib *CEnvShooter::CreateGib( void ) { CGib *pGib = GetClassPtr( (CGib *)NULL ); - pGib->Spawn( STRING(pev->model) ); - + pGib->Spawn( STRING( pev->model ) ); + int bodyPart = 0; - if ( pev->body > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); + if( pev->body > 1 ) + bodyPart = RANDOM_LONG( 0, pev->body - 1 ); pGib->pev->body = bodyPart; pGib->m_bloodColor = DONT_BLEED; @@ -1550,24 +1547,24 @@ CGib *CEnvShooter :: CreateGib ( void ) class CTestEffect : public CBaseDelay { public: - void Spawn( void ); - void Precache( void ); + 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; + 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( ); + Precache(); } void CTestEffect::Precache( void ) @@ -1578,18 +1575,18 @@ void CTestEffect::Precache( void ) void CTestEffect::TestThink( void ) { int i; - float t = (gpGlobals->time - m_flStartTime); + float t = gpGlobals->time - m_flStartTime; - if (m_iBeam < 24) + if( m_iBeam < 24 ) { CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 ); - TraceResult tr; + 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); + UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT( pev ), &tr ); pbeam->PointsInit( vecSrc, tr.vecEndPos ); // pbeam->SetColor( 80, 100, 255 ); @@ -1601,12 +1598,12 @@ void CTestEffect::TestThink( void ) m_pBeam[m_iBeam] = pbeam; m_iBeam++; #if 0 - Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5; + 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( 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 @@ -1617,11 +1614,11 @@ void CTestEffect::TestThink( void ) #endif } - if (t < 3.0) + if( t < 3.0 ) { - for (i = 0; i < m_iBeam; i++) + for( i = 0; i < m_iBeam; i++ ) { - t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]); + t = ( gpGlobals->time - m_flBeamTime[i] ) / ( 3 + m_flStartTime - m_flBeamTime[i] ); m_pBeam[i]->SetBrightness( 255 * t ); // m_pBeam[i]->SetScrollRate( 20 * t ); } @@ -1629,7 +1626,7 @@ void CTestEffect::TestThink( void ) } else { - for (i = 0; i < m_iBeam; i++) + for( i = 0; i < m_iBeam; i++ ) { UTIL_Remove( m_pBeam[i] ); } @@ -1651,19 +1648,32 @@ void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u class CBlood : public CPointEntity { public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); + 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 int Color( void ) + { + return pev->impulse; + } - inline void SetColor( int color ) { pev->impulse = color; } - inline void SetBloodAmount( float amount ) { pev->dmg = amount; } + inline float BloodAmount( void ) + { + return pev->dmg; + } + + inline void SetColor( int color ) + { + pev->impulse = color; + } - Vector Direction( void ); - Vector BloodPosition( CBaseEntity *pActivator ); - + inline void SetBloodAmount( float amount ) + { + pev->dmg = amount; + } + + Vector Direction( void ); + Vector BloodPosition( CBaseEntity *pActivator ); private: }; @@ -1676,18 +1686,18 @@ LINK_ENTITY_TO_CLASS( env_blood, CBlood ) void CBlood::Spawn( void ) { - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; + 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")) + if( FStrEq( pkvd->szKeyName, "color" ) ) { - int color = atoi(pkvd->szValue); + int color = atoi( pkvd->szValue ); switch( color ) { case 1: @@ -1700,9 +1710,9 @@ void CBlood::KeyValue( KeyValueData *pkvd ) pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "amount")) + else if( FStrEq( pkvd->szKeyName, "amount" ) ) { - SetBloodAmount( atof(pkvd->szValue) ); + SetBloodAmount( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else @@ -1711,26 +1721,26 @@ void CBlood::KeyValue( KeyValueData *pkvd ) Vector CBlood::Direction( void ) { - if ( pev->spawnflags & SF_BLOOD_RANDOM ) + if( pev->spawnflags & SF_BLOOD_RANDOM ) return UTIL_RandomBloodVector(); - + return pev->movedir; } Vector CBlood::BloodPosition( CBaseEntity *pActivator ) { - if ( pev->spawnflags & SF_BLOOD_PLAYER ) + if( pev->spawnflags & SF_BLOOD_PLAYER ) { edict_t *pPlayer; - if ( pActivator && pActivator->IsPlayer() ) + 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) ); + 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; @@ -1738,19 +1748,19 @@ Vector CBlood::BloodPosition( CBaseEntity *pActivator ) 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(), BloodAmount() ); + if( pev->spawnflags & SF_BLOOD_STREAM ) + UTIL_BloodStream( BloodPosition( pActivator ), Direction(), ( Color() == BLOOD_COLOR_RED ) ? 70 : Color(), BloodAmount() ); else - UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); + UTIL_BloodDrips( BloodPosition( pActivator ), Direction(), Color(), BloodAmount() ); - if ( pev->spawnflags & SF_BLOOD_DECAL ) + 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 ) + if( tr.flFraction != 1.0 ) UTIL_BloodDecalTrace( &tr, Color() ); } } @@ -1759,19 +1769,49 @@ void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp class CShake : public CPointEntity { public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); + 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 float Amplitude( void ) + { + return pev->scale; + } - 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; } + 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: }; @@ -1791,35 +1831,35 @@ LINK_ENTITY_TO_CLASS( env_shake, CShake ) 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->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")) + if( FStrEq( pkvd->szKeyName, "amplitude" ) ) { - SetAmplitude( atof(pkvd->szValue) ); + SetAmplitude( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "frequency")) + else if( FStrEq( pkvd->szKeyName, "frequency" ) ) { - SetFrequency( atof(pkvd->szValue) ); + SetFrequency( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "duration")) + else if( FStrEq( pkvd->szKeyName, "duration" ) ) { - SetDuration( atof(pkvd->szValue) ); + SetDuration( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "radius")) + else if( FStrEq( pkvd->szKeyName, "radius" ) ) { - SetRadius( atof(pkvd->szValue) ); + SetRadius( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else @@ -1835,15 +1875,29 @@ void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp class CFade : public CPointEntity { public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); + 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 float Duration( void ) + { + return pev->dmg_take; + } - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } + 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: }; @@ -1851,28 +1905,28 @@ 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_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; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->effects = 0; + pev->frame = 0; } void CFade::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "duration")) + if( FStrEq( pkvd->szKeyName, "duration" ) ) { - SetDuration( atof(pkvd->szValue) ); + SetDuration( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "holdtime")) + else if( FStrEq( pkvd->szKeyName, "holdtime" ) ) { - SetHoldTime( atof(pkvd->szValue) ); + SetHoldTime( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else @@ -1883,15 +1937,15 @@ void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType { int fadeFlags = 0; - if ( !(pev->spawnflags & SF_FADE_IN) ) + if( !( pev->spawnflags & SF_FADE_IN ) ) fadeFlags |= FFADE_OUT; - if ( pev->spawnflags & SF_FADE_MODULATE ) + if( pev->spawnflags & SF_FADE_MODULATE ) fadeFlags |= FFADE_MODULATE; - if ( pev->spawnflags & SF_FADE_ONLYONE ) + if( pev->spawnflags & SF_FADE_ONLYONE ) { - if ( pActivator->IsNetClient() ) + if( pActivator->IsNetClient() ) { UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); } @@ -1906,10 +1960,10 @@ void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType 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 ); + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); private: }; @@ -1919,23 +1973,23 @@ void CMessage::Spawn( void ) { Precache(); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; switch( pev->impulse ) { - case 1: // Medium radius + case 1: + // Medium radius pev->speed = ATTN_STATIC; break; - - case 2: // Large radius + case 2: + // Large radius pev->speed = ATTN_NORM; break; - - case 3: //EVERYWHERE + case 3: + //EVERYWHERE pev->speed = ATTN_NONE; break; - default: case 0: // Small radius pev->speed = ATTN_IDLE; @@ -1944,31 +1998,31 @@ void CMessage::Spawn( void ) pev->impulse = 0; // No volume, use normal - if ( pev->scale <= 0 ) + if( pev->scale <= 0 ) pev->scale = 1.0; } void CMessage::Precache( void ) { - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); + if( pev->noise ) + PRECACHE_SOUND( (char *)STRING( pev->noise ) ); } void CMessage::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "messagesound")) + if( FStrEq( pkvd->szKeyName, "messagesound" ) ) { - pev->noise = ALLOC_STRING(pkvd->szValue); + pev->noise = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "messagevolume")) + else if( FStrEq(pkvd->szKeyName, "messagevolume" ) ) { - pev->scale = atof(pkvd->szValue) * 0.1; + pev->scale = atof( pkvd->szValue ) * 0.1; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "messageattenuation")) + else if( FStrEq( pkvd->szKeyName, "messageattenuation" ) ) { - pev->impulse = atoi(pkvd->szValue); + pev->impulse = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1979,24 +2033,24 @@ void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT { CBaseEntity *pPlayer = NULL; - if ( pev->spawnflags & SF_MESSAGE_ALL ) - UTIL_ShowMessageAll( STRING(pev->message) ); + if( pev->spawnflags & SF_MESSAGE_ALL ) + UTIL_ShowMessageAll( STRING( pev->message ) ); else { - if ( pActivator && pActivator->IsPlayer() ) + if( pActivator && pActivator->IsPlayer() ) pPlayer = pActivator; else { pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); } - if ( pPlayer ) - UTIL_ShowMessage( STRING(pev->message), pPlayer ); + if( pPlayer ) + UTIL_ShowMessage( STRING( pev->message ), pPlayer ); } - if ( pev->noise ) + if( pev->noise ) { - EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed ); + EMIT_SOUND( edict(), CHAN_BODY, STRING( pev->noise ), pev->scale, pev->speed ); } - if ( pev->spawnflags & SF_MESSAGE_ONCE ) + if( pev->spawnflags & SF_MESSAGE_ONCE ) UTIL_Remove( this ); SUB_UseTargets( this, USE_TOGGLE, 0 ); @@ -2008,14 +2062,14 @@ void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT class CEnvFunnel : public CBaseDelay { public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iSprite; // Don't save, precache + int m_iSprite; // Don't save, precache }; -void CEnvFunnel :: Precache ( void ) +void CEnvFunnel::Precache( void ) { m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); } @@ -2031,7 +2085,7 @@ void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us WRITE_COORD( pev->origin.z ); WRITE_SHORT( m_iSprite ); - if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? + if( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? { WRITE_SHORT( 1 ); } @@ -2061,12 +2115,12 @@ void CEnvFunnel::Spawn( void ) class CEnvBeverage : public CBaseDelay { public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Spawn( void ); + void Precache( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; -void CEnvBeverage :: Precache ( void ) +void CEnvBeverage::Precache( void ) { PRECACHE_MODEL( "models/can.mdl" ); PRECACHE_SOUND( "weapons/g_bounce3.wav" ); @@ -2076,7 +2130,7 @@ 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 ) + 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; @@ -2084,7 +2138,7 @@ void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() ); - if ( pev->skin == 6 ) + if( pev->skin == 6 ) { // random pCan->pev->skin = RANDOM_LONG( 0, 5 ); @@ -2097,7 +2151,7 @@ void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE pev->frags = 1; pev->health--; - //SetThink( &SUB_Remove); + //SetThink( &SUB_Remove ); //pev->nextthink = gpGlobals->time; } @@ -2108,7 +2162,7 @@ void CEnvBeverage::Spawn( void ) pev->effects = EF_NODRAW; pev->frags = 0; - if ( pev->health == 0 ) + if( pev->health == 0 ) { pev->health = 10; } @@ -2120,13 +2174,13 @@ void CEnvBeverage::Spawn( void ) class CItemSoda : public CBaseEntity { public: - void Spawn( void ); - void Precache( void ); - void EXPORT CanThink ( void ); - void EXPORT CanTouch ( CBaseEntity *pOther ); + void Spawn( void ); + void Precache( void ); + void EXPORT CanThink( void ); + void EXPORT CanTouch( CBaseEntity *pOther ); }; -void CItemSoda :: Precache ( void ) +void CItemSoda::Precache( void ) { } @@ -2138,26 +2192,26 @@ void CItemSoda::Spawn( void ) 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 ) ); + SET_MODEL( ENT( pev ), "models/can.mdl" ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - SetThink( &CItemSoda::CanThink); + SetThink( &CItemSoda::CanThink ); pev->nextthink = gpGlobals->time + 0.5; } -void CItemSoda::CanThink ( void ) +void CItemSoda::CanThink( void ) { - EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM ); + 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 ) ); + UTIL_SetSize( pev, Vector( -8, -8, 0 ), Vector( 8, 8, 8 ) ); SetThink( NULL ); SetTouch( &CItemSoda::CanTouch ); } -void CItemSoda::CanTouch ( CBaseEntity *pOther ) +void CItemSoda::CanTouch( CBaseEntity *pOther ) { - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { return; } @@ -2165,7 +2219,7 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) // spoit sound here pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. - if ( !FNullEnt( pev->owner ) ) + if( !FNullEnt( pev->owner ) ) { // tell the machine the can was taken pev->owner->v.frags = 0; diff --git a/dlls/effects.h b/dlls/effects.h index 3c72d06a..031b8273 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -36,12 +36,12 @@ public: void Spawn( void ); void Precache( void ); - int ObjectCaps( void ) + int ObjectCaps( void ) { int flags = 0; - if ( pev->spawnflags & SF_SPRITE_TEMPORARY ) + if( pev->spawnflags & SF_SPRITE_TEMPORARY ) flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | flags; } void EXPORT AnimateThink( void ); void EXPORT ExpandThink( void ); @@ -52,9 +52,9 @@ public: inline void SetAttachment( edict_t *pEntity, int attachment ) { - if ( pEntity ) + if( pEntity ) { - pev->skin = ENTINDEX(pEntity); + pev->skin = ENTINDEX( pEntity ); pev->body = attachment; pev->aiment = pEntity; pev->movetype = MOVETYPE_FOLLOW; @@ -62,7 +62,11 @@ public: } void TurnOff( void ); void TurnOn( void ); - inline float Frames( void ) { return m_maxFrame; } + 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; @@ -72,89 +76,201 @@ public: 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 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); + SetThink( &CSprite::AnimateUntilDead ); pev->framerate = framerate; - pev->dmgtime = gpGlobals->time + (m_maxFrame / 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[]; + 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; + float m_lastTime; + float m_maxFrame; }; - class CBeam : public CBaseEntity { public: - void Spawn( void ); - void Precache( void ); - int ObjectCaps( void ) + void Spawn( void ); + void Precache( void ); + int ObjectCaps( void ) { int flags = 0; - if ( pev->spawnflags & SF_BEAM_TEMPORARY ) + if( pev->spawnflags & SF_BEAM_TEMPORARY ) flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + 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; } + 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 SetStartAttachment( int attachment ) + { + pev->sequence = ( pev->sequence & 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 void SetEndAttachment( int attachment ) + { + pev->skin = ( pev->skin & 0x0FFF ) | ( ( attachment & 0xF ) << 12 ); + } - 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; } + 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 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 pev->renderamt; } - inline int GetFrame( void ) { return pev->frame; } - inline int GetScrollRate( void ) { return pev->animtime; } + inline int GetTexture( void ) + { + return pev->modelindex; + } + + inline int GetWidth( void ) + { + return 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 pev->renderamt; + } + + inline int GetFrame( void ) + { + return pev->frame; + } + + inline int GetScrollRate( void ) + { + return pev->animtime; + } // Call after you change start/end positions void RelinkBeam( void ); -// void SetObjectCollisionBox( void ); + //void SetObjectCollisionBox( void ); void DoSparks( const Vector &start, const Vector &end ); CBaseEntity *RandomTargetname( const char *szName ); @@ -168,20 +284,23 @@ public: static CBeam *BeamCreate( const char *pSpriteName, int width ); - inline void LiveForTime( float time ) { SetThink( &CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + time; } - inline void BeamDamageInstant( TraceResult *ptr, float damage ) + inline void LiveForTime( float time ) + { + SetThink( &CBaseEntity::SUB_Remove ); + pev->nextthink = gpGlobals->time + time; + } + + inline void BeamDamageInstant( TraceResult *ptr, float damage ) { pev->dmg = damage; pev->dmgtime = gpGlobals->time - 1; - BeamDamage(ptr); + 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: @@ -191,7 +310,7 @@ public: void TurnOn( void ); void TurnOff( void ); - int IsOn( void ); + int IsOn( void ); void FireAtPoint( TraceResult &point ); @@ -202,8 +321,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; CSprite *m_pSprite; - int m_iszSpriteName; - Vector m_firePosition; + int m_iszSpriteName; + Vector m_firePosition; }; - #endif //EFFECTS_H diff --git a/dlls/egon.cpp b/dlls/egon.cpp index b624cea8..433704ce 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -51,11 +51,11 @@ enum egon_e { LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ) -void CEgon::Spawn( ) +void CEgon::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_EGON; - SET_MODEL(ENT(pev), "models/w_egon.mdl"); + SET_MODEL( ENT( pev ), "models/w_egon.mdl" ); m_iDefaultAmmo = EGON_DEFAULT_GIVE; @@ -64,12 +64,12 @@ void CEgon::Spawn( ) 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_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_MODEL( "models/w_9mmclip.mdl" ); + PRECACHE_SOUND( "items/9mmclip1.wav" ); PRECACHE_SOUND( EGON_SOUND_OFF ); PRECACHE_SOUND( EGON_SOUND_RUN ); @@ -78,13 +78,12 @@ void CEgon::Precache( void ) PRECACHE_MODEL( EGON_BEAM_SPRITE ); PRECACHE_MODEL( EGON_FLARE_SPRITE ); - PRECACHE_SOUND ("weapons/357_cock1.wav"); + PRECACHE_SOUND( "weapons/357_cock1.wav" ); - m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); - m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); + 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; @@ -94,7 +93,7 @@ BOOL CEgon::Deploy( void ) int CEgon::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -104,19 +103,17 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } - - void CEgon::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( EGON_HOLSTER ); - EndAttack(); + EndAttack(); } -int CEgon::GetItemInfo(ItemInfo *p) +int CEgon::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "uranium"; p->iMaxAmmo1 = URANIUM_MAX_CARRY; p->pszAmmo2 = NULL; @@ -131,7 +128,7 @@ int CEgon::GetItemInfo(ItemInfo *p) return 1; } -#define EGON_PULSE_INTERVAL 0.1 +#define EGON_PULSE_INTERVAL 0.1 #define EGON_DISCHARGE_INTERVAL 0.1 float CEgon::GetPulseInterval( void ) @@ -146,7 +143,7 @@ float CEgon::GetDischargeInterval( void ) BOOL CEgon::HasAmmo( void ) { - if ( m_pPlayer->ammo_uranium <= 0 ) + if( m_pPlayer->ammo_uranium <= 0 ) return FALSE; return TRUE; @@ -154,7 +151,7 @@ BOOL CEgon::HasAmmo( void ) void CEgon::UseAmmo( int count ) { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; else m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; @@ -163,23 +160,22 @@ void CEgon::UseAmmo( int count ) void CEgon::Attack( void ) { // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) + if( m_pPlayer->pev->waterlevel == 3 ) { - - if ( m_fireState != FIRE_OFF || m_pBeam ) + if( m_fireState != FIRE_OFF || m_pBeam ) { EndAttack(); } else { - PlayEmptySound( ); + PlayEmptySound(); } return; } UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecSrc = m_pPlayer->GetGunPosition(); int flags; #if defined( CLIENT_WEAPONS ) @@ -192,7 +188,7 @@ void CEgon::Attack( void ) { case FIRE_OFF: { - if ( !HasAmmo() ) + if( !HasAmmo() ) { m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; PlayEmptySound( ); @@ -202,37 +198,35 @@ void CEgon::Attack( void ) 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->fuser1 = UTIL_WeaponTimeBase() + 2; pev->dmgtime = gpGlobals->time + GetPulseInterval(); m_fireState = FIRE_CHARGE; + break; } - break; - case FIRE_CHARGE: { Fire( vecSrc, vecAiming ); m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) + + 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() ) + if( !HasAmmo() ) { EndAttack(); m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; } - + break; } - break; } } @@ -240,13 +234,12 @@ 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; + edict_t *pentIgnore; TraceResult tr; pentIgnore = m_pPlayer->edict(); @@ -256,22 +249,22 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - if (tr.fAllSolid) + if( tr.fAllSolid ) return; #ifndef CLIENT_DLL - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if (pEntity == NULL) + if( pEntity == NULL ) return; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { - if ( m_pSprite && pEntity->pev->takedamage ) + if( m_pSprite && pEntity->pev->takedamage ) { m_pSprite->pev->effects &= ~EF_NODRAW; } - else if ( m_pSprite ) + else if( m_pSprite ) { m_pSprite->pev->effects |= EF_NODRAW; } @@ -279,24 +272,24 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) #endif float timedist; - switch ( m_fireMode ) + switch( m_fireMode ) { case FIRE_NARROW: #ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) + if( pev->dmgtime < gpGlobals->time ) { // Narrow mode only does damage to the entity it hits ClearMultiDamage(); - if (pEntity->pev->takedamage) + if( pEntity->pev->takedamage ) { pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { // multiplayer uses 1 ammo every 1/10th second - if ( gpGlobals->time >= m_flAmmoUseTime ) + if( gpGlobals->time >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.1; @@ -305,7 +298,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) else { // single player, use 3 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) + if( gpGlobals->time >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.166; @@ -317,32 +310,31 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) #endif timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); break; - case FIRE_WIDE: #ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) + if( pev->dmgtime < gpGlobals->time ) { // wide mode does damage to the ent, and radius damage ClearMultiDamage(); - if (pEntity->pev->takedamage) + if( pEntity->pev->takedamage ) { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); + pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB ); } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - if ( g_pGameRules->IsMultiplayer() ) + 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() ) + if( !m_pPlayer->IsAlive() ) return; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { //multiplayer uses 5 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) + if( gpGlobals->time >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.2; @@ -351,7 +343,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) else { // Wide mode uses 10 charges per second in single player - if ( gpGlobals->time >= m_flAmmoUseTime ) + if( gpGlobals->time >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.1; @@ -359,7 +351,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) } pev->dmgtime = gpGlobals->time + GetDischargeInterval(); - if ( m_shakeTime < gpGlobals->time ) + if( m_shakeTime < gpGlobals->time ) { UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); m_shakeTime = gpGlobals->time + 1.5; @@ -370,37 +362,35 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) break; } - if ( timedist < 0 ) + if( timedist < 0 ) timedist = 0; - else if ( timedist > 1 ) + else if( timedist > 1 ) timedist = 1; - timedist = 1-timedist; + 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 ) + if( !m_pBeam ) { CreateEffect(); } m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( 255 - (timeBlend*180) ); - m_pBeam->SetWidth( 40 - (timeBlend*20) ); + m_pBeam->SetBrightness( 255 - ( timeBlend * 180 ) ); + m_pBeam->SetWidth( 40 - ( timeBlend * 20 ) ); - if ( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + if( m_fireMode == FIRE_WIDE ) + m_pBeam->SetColor( 30 + ( 25 * timeBlend ), 30 + ( 30 * timeBlend ), 64 + 80 * fabs( sin( gpGlobals->time * 10 ) ) ); else - m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); - + m_pBeam->SetColor( 60 + ( 25 * timeBlend ), 120 + ( 30 * timeBlend ), 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() ) + if( m_pSprite->pev->frame > m_pSprite->Frames() ) m_pSprite->pev->frame = 0; m_pNoise->SetStartPos( endPoint ); @@ -436,7 +426,7 @@ void CEgon::CreateEffect( void ) m_pSprite->pev->flags |= FL_SKIPLOCALHOST; m_pSprite->pev->owner = m_pPlayer->edict(); - if ( m_fireMode == FIRE_WIDE ) + if( m_fireMode == FIRE_WIDE ) { m_pBeam->SetScrollRate( 50 ); m_pBeam->SetNoise( 20 ); @@ -455,21 +445,21 @@ void CEgon::CreateEffect( void ) void CEgon::DestroyEffect( void ) { - #ifndef CLIENT_DLL - if ( m_pBeam ) + if( m_pBeam ) { UTIL_Remove( m_pBeam ); m_pBeam = NULL; } - if ( m_pNoise ) + + if( m_pNoise ) { UTIL_Remove( m_pNoise ); m_pNoise = NULL; } - if ( m_pSprite ) + if( m_pSprite ) { - if ( m_fireMode == FIRE_WIDE ) + if( m_fireMode == FIRE_WIDE ) m_pSprite->Expand( 10, 500 ); else UTIL_Remove( m_pSprite ); @@ -480,19 +470,19 @@ void CEgon::DestroyEffect( void ) void CEgon::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if ( m_fireState != FIRE_OFF ) + if( m_fireState != FIRE_OFF ) EndAttack(); - + int iAnim; - float flRand = RANDOM_FLOAT(0,1); + float flRand = RANDOM_FLOAT( 0, 1 ); - if ( flRand <= 0.5 ) + if( flRand <= 0.5 ) { iAnim = EGON_IDLE1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); @@ -507,13 +497,11 @@ void CEgon::WeaponIdle( void ) m_deployed = TRUE; } - - void CEgon::EndAttack( void ) { bool bMakeNoise = false; - - if ( m_fireState != FIRE_OFF ) //Checking the button just in case!. + + 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 ); @@ -526,31 +514,31 @@ void CEgon::EndAttack( void ) DestroyEffect(); } - - class CEgonAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + 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) + + 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); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; } }; -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ) +LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ) #endif diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index a8b21b27..1c5ec1b2 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -69,7 +69,8 @@ extern enginefuncs_t g_engfuncs; #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 ) { +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) @@ -90,9 +91,10 @@ inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NU #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 ) + if( pent ) return pent->pvPrivateData; return NULL; } @@ -155,4 +157,4 @@ inline void *GET_PRIVATE( edict_t *pent ) #define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) -#endif //ENGINECALLBACK_H \ No newline at end of file +#endif //ENGINECALLBACK_H diff --git a/dlls/explode.cpp b/dlls/explode.cpp index 6d40960b..f605dc02 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -39,9 +39,9 @@ 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.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; @@ -49,8 +49,8 @@ void CShower::Spawn( void ) 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 ); + 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 ); @@ -62,7 +62,7 @@ void CShower::Think( void ) UTIL_Sparks( pev->origin ); pev->speed -= 0.1; - if ( pev->speed > 0 ) + if( pev->speed > 0 ) pev->nextthink = gpGlobals->time + 0.1; else UTIL_Remove( this ); @@ -71,32 +71,32 @@ void CShower::Think( void ) void CShower::Touch( CBaseEntity *pOther ) { - if ( pev->flags & FL_ONGROUND ) + 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 ) + 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 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[]; + 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[] = +TYPEDESCRIPTION CEnvExplosion::m_SaveData[] = { DEFINE_FIELD( CEnvExplosion, m_iMagnitude, FIELD_INTEGER ), DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ), @@ -107,9 +107,9 @@ LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ) void CEnvExplosion::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "iMagnitude")) + if( FStrEq( pkvd->szKeyName, "iMagnitude" ) ) { - m_iMagnitude = atoi(pkvd->szValue); + m_iMagnitude = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -123,22 +123,22 @@ void CEnvExplosion::Spawn( void ) pev->movetype = MOVETYPE_NONE; /* - if ( m_iMagnitude > 250 ) + if( m_iMagnitude > 250 ) { m_iMagnitude = 250; } */ float flSpriteScale; - flSpriteScale = ( m_iMagnitude - 50) * 0.6; - + flSpriteScale = ( m_iMagnitude - 50 ) * 0.6; + /* - if ( flSpriteScale > 50 ) + if( flSpriteScale > 50 ) { flSpriteScale = 50; } */ - if ( flSpriteScale < 10 ) + if( flSpriteScale < 10 ) { flSpriteScale = 10; } @@ -153,16 +153,16 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE pev->model = iStringNull;//invisible pev->solid = SOLID_NOT;// intangible - Vector vecSpot;// trace starts here! + 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 ); - 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 ) + if( tr.flFraction != 1.0 ) { - pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6); + pev->origin = tr.vecEndPos + ( tr.vecPlaneNormal * ( m_iMagnitude - 24 ) * 0.6 ); } else { @@ -170,9 +170,9 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } // draw decal - if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL)) + if( !( pev->spawnflags & SF_ENVEXPLOSION_NODECAL ) ) { - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) + if( RANDOM_FLOAT( 0, 1 ) < 0.5 ) { UTIL_DecalTrace( &tr, DECAL_SCORCH1 ); } @@ -183,7 +183,7 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } // draw fireball - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) ) + if( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) ) { MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_EXPLOSION); @@ -192,39 +192,39 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE WRITE_COORD( pev->origin.z ); WRITE_SHORT( g_sModelIndexFireball ); WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate + 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_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( 15 ); // framerate WRITE_BYTE( TE_EXPLFLAG_NONE ); MESSAGE_END(); } // do damage - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) + if( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) { - RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); + 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 ) ) + if( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) ) { - int sparkCount = RANDOM_LONG(0,3); + int sparkCount = RANDOM_LONG( 0, 3 ); - for ( int i = 0; i < sparkCount; i++ ) + for( int i = 0; i < sparkCount; i++ ) { Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL ); } @@ -233,7 +233,7 @@ void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE void CEnvExplosion::Smoke( void ) { - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) ) + if( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) ) { MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_SMOKE ); @@ -242,11 +242,11 @@ void CEnvExplosion::Smoke( void ) WRITE_COORD( pev->origin.z ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 12 ); // framerate + WRITE_BYTE( 12 ); // framerate MESSAGE_END(); } - - if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) ) + + if( !( pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE ) ) { UTIL_Remove( this ); } @@ -255,15 +255,15 @@ void CEnvExplosion::Smoke( void ) // 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]; + 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 ) + if( !doDamage ) pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; pExplosion->Spawn(); diff --git a/dlls/explode.h b/dlls/explode.h index 3feb011c..e1c6cce0 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -15,7 +15,6 @@ #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 @@ -23,10 +22,8 @@ #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 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/dlls/exportdef.h b/dlls/exportdef.h index 90268c44..995613ff 100644 --- a/dlls/exportdef.h +++ b/dlls/exportdef.h @@ -7,11 +7,11 @@ #define EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. #endif #else - #if __GNUC__ >= 4 - #define EXPORT __attribute__ ((visibility ("default"))) - #else - #define EXPORT - #endif + #if __GNUC__ >= 4 + #define EXPORT __attribute__ ((visibility ("default"))) + #else + #define EXPORT + #endif #endif #define DLLEXPORT EXPORT #define _DLLEXPORT EXPORT diff --git a/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp index bc037e1b..c9822898 100644 --- a/dlls/flyingmonster.cpp +++ b/dlls/flyingmonster.cpp @@ -23,14 +23,14 @@ #define FLYING_AE_FLAP (8) #define FLYING_AE_FLAPSOUND (9) -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; +extern DLL_GLOBAL edict_t *g_pBodyQueueHead; -int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +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)) + if( FBitSet( pev->flags, FL_SWIM ) && ( UTIL_PointContents( vecEnd ) != CONTENTS_WATER ) ) { - // ALERT(at_aiconsole, "can't swim out of water\n"); + // ALERT( at_aiconsole, "can't swim out of water\n" ); return FALSE; } @@ -41,15 +41,15 @@ int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vec // 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) + if( pflDist ) { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. + *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( tr.fStartSolid || tr.flFraction < 1.0 ) { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + if( pTarget && pTarget->edict() == gpGlobals->trace_ent ) return LOCALMOVE_VALID; return LOCALMOVE_INVALID; } @@ -57,23 +57,23 @@ int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vec return LOCALMOVE_VALID; } -BOOL CFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) +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 ) +Activity CFlyingMonster::GetStoppedActivity( void ) { - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else + if( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else return ACT_IDLE; return ACT_HOVER; } -void CFlyingMonster :: Stop( void ) -{ +void CFlyingMonster::Stop( void ) +{ Activity stopped = GetStoppedActivity(); - if ( m_IdealActivity != stopped ) + if( m_IdealActivity != stopped ) { m_flightSpeed = 0; m_IdealActivity = stopped; @@ -83,18 +83,18 @@ void CFlyingMonster :: Stop( void ) m_vecTravel = g_vecZero; } -float CFlyingMonster :: ChangeYaw( int speed ) +float CFlyingMonster::ChangeYaw( int speed ) { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) { float diff = FlYawDiff(); float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) + if( m_IdealActivity != GetStoppedActivity() ) { - if ( diff < -20 ) + if( diff < -20 ) target = 90; - else if ( diff > 20 ) + else if( diff > 20 ) target = -90; } pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime ); @@ -102,7 +102,7 @@ float CFlyingMonster :: ChangeYaw( int speed ) return CBaseMonster::ChangeYaw( speed ); } -void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) +void CFlyingMonster::Killed( entvars_t *pevAttacker, int iGib ) { pev->movetype = MOVETYPE_STEP; ClearBits( pev->flags, FL_ONGROUND ); @@ -111,7 +111,7 @@ void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) CBaseMonster::Killed( pevAttacker, iGib ); } -void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CFlyingMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -119,7 +119,7 @@ void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) m_flightSpeed = 400; break; case FLYING_AE_FLAPSOUND: - if ( m_pFlapSound ) + if( m_pFlapSound ) EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM ); break; default: @@ -128,20 +128,20 @@ void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } -void CFlyingMonster :: Move( float flInterval ) +void CFlyingMonster::Move( float flInterval ) { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) m_flGroundSpeed = m_flightSpeed; CBaseMonster::Move( flInterval ); } -BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) +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( 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) ) + if( flWaypointDist <= 64 + ( m_flGroundSpeed * gpGlobals->frametime ) ) return TRUE; return FALSE; @@ -149,32 +149,32 @@ BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) { - if ( gpGlobals->time - m_stopTime > 1.0 ) + if( gpGlobals->time - m_stopTime > 1.0 ) { - if ( m_IdealActivity != m_movementActivity ) + 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)); + Vector vecMove = pev->origin + ( ( vecDir + ( m_vecTravel * m_momentum ) ).Normalize() * (m_flGroundSpeed * flInterval ) ); - if ( m_IdealActivity != m_movementActivity ) + if( m_IdealActivity != m_movementActivity ) { m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime ); - if ( m_flightSpeed < 100 ) + 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 ) ) + if( CheckLocalMove( pev->origin, vecMove, pTargetEnt, NULL ) ) { - m_vecTravel = (vecMove - pev->origin); + m_vecTravel = vecMove - pev->origin; m_vecTravel = m_vecTravel.Normalize(); - UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE); + UTIL_MoveToOrigin( ENT( pev ), vecMove, ( m_flGroundSpeed * flInterval ), MOVE_STRAFE ); } else { @@ -195,21 +195,21 @@ float CFlyingMonster::CeilingZ( const Vector &position ) Vector maxUp = position; maxUp.z += 4096.0; - UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr); - if (tr.flFraction != 1.0) + UTIL_TraceLine( position, maxUp, ignore_monsters, NULL, &tr ); + if( tr.flFraction != 1.0 ) maxUp.z = tr.vecEndPos.z; - if ((pev->flags) & FL_SWIM) + 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) +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)) + int conPosition = UTIL_PointContents( position ); + if( ( ( ( pev->flags ) & FL_SWIM ) == FL_SWIM ) ^ ( conPosition == CONTENTS_WATER ) ) { // SWIMING & !WATER // or FLYING & WATER @@ -217,8 +217,8 @@ BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *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) + 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). @@ -227,17 +227,17 @@ BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float return FALSE; } - Vector ProbeUnit = (probe-position).Normalize(); - float ProbeLength = (probe-position).Length(); + Vector ProbeUnit = ( probe - position ).Normalize(); + float ProbeLength = ( probe - position ).Length(); float maxProbeLength = ProbeLength; float minProbeLength = 0; float diff = maxProbeLength - minProbeLength; - while (diff > 1.0) + while( diff > 1.0 ) { - float midProbeLength = minProbeLength + diff/2.0; + float midProbeLength = minProbeLength + diff / 2.0; Vector midProbeVec = midProbeLength * ProbeUnit; - if (UTIL_PointContents(position+midProbeVec) == conPosition) + if( UTIL_PointContents( position + midProbeVec ) == conPosition ) { minProbeLength = midProbeLength; } @@ -261,7 +261,7 @@ float CFlyingMonster::FloorZ( const Vector &position ) UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr ); - if ( tr.flFraction != 1.0 ) + if( tr.flFraction != 1.0 ) return tr.vecEndPos.z; return down.z; diff --git a/dlls/flyingmonster.h b/dlls/flyingmonster.h index 17d4e90a..4dd87fb4 100644 --- a/dlls/flyingmonster.h +++ b/dlls/flyingmonster.h @@ -20,8 +20,8 @@ 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 ); + 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 ); diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 7c9705e6..38b05f7b 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -27,7 +27,7 @@ #include "decals.h" #include "explode.h" -extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL Vector g_vecAttackDir; // =================== FUNC_Breakable ============================================== @@ -36,10 +36,10 @@ extern DLL_GLOBAL Vector g_vecAttackDir; // be spawned, and still remain fairly flexible const char *CBreakable::pSpawnObjects[] = { - NULL, // 0 + NULL, // 0 "item_battery", // 1 "item_healthkit", // 2 - "weapon_9mmhandgun",// 3 + "weapon_9mmhandgun", // 3 "ammo_9mmclip", // 4 "weapon_9mmAR", // 5 "ammo_9mmAR", // 6 @@ -49,11 +49,11 @@ const char *CBreakable::pSpawnObjects[] = "weapon_crossbow", // 10 "ammo_crossbow", // 11 "weapon_357", // 12 - "ammo_357", // 13 + "ammo_357", // 13 "weapon_rpg", // 14 "ammo_rpgclip", // 15 "ammo_gaussclip", // 16 - "weapon_handgrenade",// 17 + "weapon_handgrenade", // 17 "weapon_tripmine", // 18 "weapon_satchel", // 19 "weapon_snark", // 20 @@ -63,63 +63,62 @@ const char *CBreakable::pSpawnObjects[] = 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( FStrEq( pkvd->szKeyName, "explosion" ) ) { - if (!stricmp(pkvd->szValue, "directed")) + if( !stricmp( pkvd->szValue, "directed" ) ) m_Explosion = expDirected; - else if (!stricmp(pkvd->szValue, "random")) + else if( !stricmp( pkvd->szValue, "random" ) ) m_Explosion = expRandom; else m_Explosion = expRandom; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "material")) + else if( FStrEq( pkvd->szKeyName, "material" ) ) { - int i = atoi( pkvd->szValue); + int i = atoi( pkvd->szValue ); // 0:glass, 1:metal, 2:flesh, 3:wood - if ((i < 0) || (i >= matLastMaterial)) + if( ( i < 0 ) || ( i >= matLastMaterial ) ) m_Material = matWood; else m_Material = (Materials)i; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "deadmodel")) + else if( FStrEq( pkvd->szKeyName, "deadmodel" ) ) { pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "shards")) + else if( FStrEq( pkvd->szKeyName, "shards" ) ) { - //m_iShards = atof(pkvd->szValue); + //m_iShards = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) + else if( FStrEq( pkvd->szKeyName, "gibmodel" ) ) { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); + m_iszGibModel = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "spawnobject") ) + else if( FStrEq( pkvd->szKeyName, "spawnobject" ) ) { int object = atoi( pkvd->szValue ); - if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) ) + if( object > 0 && object < ARRAYSIZE( pSpawnObjects ) ) m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) + else if( FStrEq( pkvd->szKeyName, "explodemagnitude" ) ) { ExplosionSetMagnitude( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "lip") ) + else if( FStrEq( pkvd->szKeyName, "lip" ) ) pkvd->fHandled = TRUE; else CBaseDelay::KeyValue( pkvd ); } - // // func_breakable - bmodel that breaks into pieces after taking damage // @@ -144,44 +143,44 @@ IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ) void CBreakable::Spawn( void ) { - Precache( ); + Precache(); - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) + 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; + 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 ) + if( m_Material == matGlass ) { pev->playerclass = 1; } - SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. + 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 + 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 ) + if( !IsBreakable() && pev->rendermode != kRenderNormal ) pev->flags |= FL_WORLDBRUSH; } -const char *CBreakable::pSoundsWood[] = +const char *CBreakable::pSoundsWood[] = { "debris/wood1.wav", "debris/wood2.wav", "debris/wood3.wav", }; -const char *CBreakable::pSoundsFlesh[] = +const char *CBreakable::pSoundsFlesh[] = { "debris/flesh1.wav", "debris/flesh2.wav", @@ -191,21 +190,21 @@ const char *CBreakable::pSoundsFlesh[] = "debris/flesh7.wav", }; -const char *CBreakable::pSoundsMetal[] = +const char *CBreakable::pSoundsMetal[] = { "debris/metal1.wav", "debris/metal2.wav", "debris/metal3.wav", }; -const char *CBreakable::pSoundsConcrete[] = +const char *CBreakable::pSoundsConcrete[] = { "debris/concrete1.wav", "debris/concrete2.wav", "debris/concrete3.wav", }; -const char *CBreakable::pSoundsGlass[] = +const char *CBreakable::pSoundsGlass[] = { "debris/glass1.wav", "debris/glass2.wav", @@ -216,35 +215,31 @@ const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &sou { const char **pSoundList = NULL; - switch ( precacheMaterial ) + switch( precacheMaterial ) { case matWood: pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); + soundCount = ARRAYSIZE( pSoundsWood ); break; case matFlesh: pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); + soundCount = ARRAYSIZE( pSoundsFlesh ); break; case matComputer: case matUnbreakableGlass: case matGlass: pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); + soundCount = ARRAYSIZE( pSoundsGlass ); break; - case matMetal: pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); + soundCount = ARRAYSIZE( pSoundsMetal ); break; - case matCinderBlock: case matRocks: pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); + soundCount = ARRAYSIZE( pSoundsConcrete ); break; - - case matCeilingTile: case matNone: default: @@ -257,12 +252,12 @@ const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &sou void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) { - const char **pSoundList; - int i, soundCount = 0; + const char **pSoundList; + int i, soundCount = 0; pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - for ( i = 0; i < soundCount; i++ ) + for( i = 0; i < soundCount; i++ ) { PRECACHE_SOUND( (char *)pSoundList[i] ); } @@ -270,71 +265,70 @@ void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) { - const char **pSoundList; - int soundCount = 0; + 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 ); + 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) + switch( m_Material ) { case matWood: pGibName = "models/woodgibs.mdl"; - - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); + + 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"); + + PRECACHE_SOUND( "debris/bustflesh1.wav" ); + PRECACHE_SOUND( "debris/bustflesh2.wav" ); break; case matComputer: - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); + 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; + 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"); + + 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"); + + 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"); + + 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"); + + PRECACHE_SOUND( "debris/bustconcrete1.wav" ); + PRECACHE_SOUND( "debris/bustconcrete2.wav" ); break; case matCeilingTile: pGibName = "models/ceilinggibs.mdl"; - - PRECACHE_SOUND ("debris/bustceiling.wav"); + + PRECACHE_SOUND( "debris/bustceiling.wav" ); break; case matNone: case matLastMaterial: @@ -343,20 +337,18 @@ void CBreakable::Precache( void ) break; } MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); + if( m_iszGibModel ) + pGibName = STRING( m_iszGibModel ); m_idShard = PRECACHE_MODEL( (char *)pGibName ); // Precache the spawn item's data - if ( m_iszSpawnObject ) + 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; @@ -365,20 +357,20 @@ void CBreakable::DamageSound( void ) int i = 0; int material = m_Material; -// if (RANDOM_LONG(0,1)) -// return; + //if( RANDOM_LONG( 0, 1 ) ) + // return; - if (RANDOM_LONG(0,2)) + if( RANDOM_LONG( 0, 2 ) ) pitch = PITCH_NORM; else - pitch = 95 + RANDOM_LONG(0,34); + pitch = 95 + RANDOM_LONG( 0, 34 ); - fvol = RANDOM_FLOAT(0.75, 1.0); + fvol = RANDOM_FLOAT( 0.75, 1.0 ); - if (material == matComputer && RANDOM_LONG(0,1)) + if( material == matComputer && RANDOM_LONG( 0, 1 ) ) material = matMetal; - switch (material) + switch( material ) { case matComputer: case matGlass: @@ -422,37 +414,37 @@ void CBreakable::DamageSound( void ) break; } - if (i) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); + 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; - + entvars_t* pevToucher = pOther->pev; + // only players can break these right now - if ( !pOther->IsPlayer() || !IsBreakable() ) + if( !pOther->IsPlayer() || !IsBreakable() ) { - return; + return; } - if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) + if( FBitSet( pev->spawnflags, SF_BREAK_TOUCH ) ) { // can be broken when run into flDamage = pevToucher->velocity.Length() * 0.01; - if (flDamage >= pev->health) + if( flDamage >= pev->health ) { SetTouch( NULL ); - TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); + 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 ) + if( FBitSet( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) { // can be broken when stood upon // play creaking sound here. @@ -461,7 +453,7 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) SetThink( &CBreakable::Die ); SetTouch( NULL ); - if ( m_flDelay == 0 ) + if( m_flDelay == 0 ) { // !!!BUGBUG - why doesn't zero delay work? m_flDelay = 0.1; @@ -478,21 +470,20 @@ void CBreakable::BreakTouch( CBaseEntity *pOther ) // Break when triggered void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( IsBreakable() ) + if( IsBreakable() ) { pev->angles.y = m_angle; - UTIL_MakeVectors(pev->angles); + 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) ) + if( RANDOM_LONG( 0, 1 ) ) { switch( m_Material ) { @@ -500,16 +491,20 @@ void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec { UTIL_Sparks( ptr->vecEndPos ); - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) + 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; + 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) ); + UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 0.5, 1.5 ) ); break; default: break; @@ -524,19 +519,19 @@ void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec // 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 ) +int CBreakable::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - Vector vecTemp; + 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 ) + 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)) + if( FBitSet ( pevAttacker->flags, FL_CLIENT ) && + FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && ( bitsDamageType & DMG_CLUB ) ) flDamage = pev->health; } else @@ -545,15 +540,15 @@ int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); } - if (!IsBreakable()) + if( !IsBreakable() ) return 0; // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) + 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 ) + if( bitsDamageType & DMG_POISON ) flDamage *= 0.1; // this global is still used for glass and other non-monster killables, along with decals. @@ -561,7 +556,7 @@ int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f // do the damage pev->health -= flDamage; - if (pev->health <= 0) + if( pev->health <= 0 ) { Killed( pevAttacker, GIB_NORMAL ); Die(); @@ -575,7 +570,6 @@ int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, f return 1; } - void CBreakable::Die( void ) { Vector vecSpot;// shard origin @@ -584,76 +578,86 @@ void CBreakable::Die( void ) char cFlag = 0; int pitch; float fvol; - - pitch = 95 + RANDOM_LONG(0,29); - if (pitch > 97 && pitch < 103) + 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) + (fabs(pev->health) / 100.0); + fvol = RANDOM_FLOAT( 0.85, 1.0 ) + ( fabs( pev->health ) / 100.0 ); - if (fvol > 1.0) + if( fvol > 1.0 ) fvol = 1.0; - switch (m_Material) + switch( m_Material ) { case matGlass: - switch ( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch ); break; case matNone: case matLastMaterial: @@ -663,7 +667,7 @@ void CBreakable::Die( void ) break; } - if (m_Explosion == expDirected) + if( m_Explosion == expDirected ) vecVelocity = g_vecAttackDir * 200; else { @@ -672,9 +676,9 @@ void CBreakable::Die( void ) vecVelocity.z = 0; } - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); + WRITE_BYTE( TE_BREAKMODEL ); // position WRITE_COORD( vecSpot.x ); @@ -682,9 +686,9 @@ void CBreakable::Die( void ) WRITE_COORD( vecSpot.z ); // size - WRITE_COORD( pev->size.x); - WRITE_COORD( pev->size.y); - WRITE_COORD( pev->size.z); + WRITE_COORD( pev->size.x ); + WRITE_COORD( pev->size.y ); + WRITE_COORD( pev->size.z ); // velocity WRITE_COORD( vecVelocity.x ); @@ -692,7 +696,7 @@ void CBreakable::Die( void ) WRITE_COORD( vecVelocity.z ); // randomization - WRITE_BYTE( 10 ); + WRITE_BYTE( 10 ); // Model WRITE_SHORT( m_idShard ); //model id# @@ -708,9 +712,9 @@ void CBreakable::Die( void ) MESSAGE_END(); float size = pev->size.x; - if ( size < pev->size.y ) + if( size < pev->size.y ) size = pev->size.y; - if ( size < pev->size.z ) + if( size < pev->size.z ) size = pev->size.z; // !!! HACK This should work! @@ -723,9 +727,9 @@ void CBreakable::Die( void ) // 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 ) + if( count ) { - for ( int i = 0; i < count; i++ ) + for( int i = 0; i < count; i++ ) { ClearBits( pList[i]->pev->flags, FL_ONGROUND ); pList[i]->pev->groundentity = NULL; @@ -742,26 +746,26 @@ void CBreakable::Die( void ) SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = pev->ltime + 0.1; - if ( m_iszSpawnObject ) - CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); + if( m_iszSpawnObject ) + CBaseEntity::Create( (char *)STRING( m_iszSpawnObject ), VecBModelOrigin( pev ), pev->angles, edict() ); - if ( Explodable() ) + if( Explodable() ) { ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); } } -BOOL CBreakable :: IsBreakable( void ) +BOOL CBreakable::IsBreakable( void ) { return m_Material != matUnbreakableGlass; } -int CBreakable :: DamageDecal( int bitsDamageType ) +int CBreakable::DamageDecal( int bitsDamageType ) { - if ( m_Material == matGlass ) - return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); + if( m_Material == matGlass ) + return DECAL_GLASSBREAK1 + RANDOM_LONG( 0, 2 ); - if ( m_Material == matUnbreakableGlass ) + if( m_Material == matUnbreakableGlass ) return DECAL_BPROOF1; return CBaseEntity::DamageDecal( bitsDamageType ); @@ -770,30 +774,30 @@ int CBreakable :: DamageDecal( int 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 ); + 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 ); + 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 ); + virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; static 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; + 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[] = @@ -806,20 +810,25 @@ IMPLEMENT_SAVERESTORE( CPushable, CBreakable ) LINK_ENTITY_TO_CLASS( func_pushable, CPushable ) -char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; - -void CPushable :: Spawn( void ) +char *CPushable::m_soundNames[3] = { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + "debris/pushbox1.wav", + "debris/pushbox2.wav", + "debris/pushbox3.wav" +}; + +void CPushable::Spawn( void ) +{ + if( pev->spawnflags & SF_PUSH_BREAKABLE ) CBreakable::Spawn(); else - Precache( ); + Precache(); - pev->movetype = MOVETYPE_PUSHSTEP; - pev->solid = SOLID_BBOX; - SET_MODEL( ENT(pev), STRING(pev->model) ); + pev->movetype = MOVETYPE_PUSHSTEP; + pev->solid = SOLID_BBOX; + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if ( pev->friction > 399 ) + if( pev->friction > 399 ) pev->friction = 399; m_maxSpeed = 400 - pev->friction; @@ -830,46 +839,50 @@ void CPushable :: Spawn( void ) UTIL_SetOrigin( pev, pev->origin ); // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005; + pev->skin = ( pev->skin * ( pev->maxs.x - pev->mins.x ) * ( pev->maxs.y - pev->mins.y ) ) * 0.0005; m_soundTime = 0; } -void CPushable :: Precache( void ) +void CPushable::Precache( void ) { - for ( int i = 0; i < 3; i++ ) + for( int i = 0; i < 3; i++ ) PRECACHE_SOUND( m_soundNames[i] ); - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Precache( ); + if( pev->spawnflags & SF_PUSH_BREAKABLE ) + CBreakable::Precache(); } -void CPushable :: KeyValue( KeyValueData *pkvd ) +void CPushable::KeyValue( KeyValueData *pkvd ) { - if ( FStrEq(pkvd->szKeyName, "size") ) + if( FStrEq( pkvd->szKeyName, "size" ) ) { - int bbox = atoi(pkvd->szValue); + int bbox = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; switch( bbox ) { - case 0: // Point - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + 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); + 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); + 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); + case 1: + // Player + UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); break; } } - else if ( FStrEq(pkvd->szKeyName, "buoyancy") ) + else if( FStrEq( pkvd->szKeyName, "buoyancy" ) ) { - pev->skin = atof(pkvd->szValue); + pev->skin = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -877,58 +890,58 @@ void CPushable :: KeyValue( KeyValueData *pkvd ) } // Pull the func_pushable -void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CPushable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !pActivator || !pActivator->IsPlayer() ) + if( !pActivator || !pActivator->IsPlayer() ) { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + if( pev->spawnflags & SF_PUSH_BREAKABLE ) this->CBreakable::Use( pActivator, pCaller, useType, value ); return; } - if ( pActivator->pev->velocity != g_vecZero ) + if( pActivator->pev->velocity != g_vecZero ) Move( pActivator, 0 ); } -void CPushable :: Touch( CBaseEntity *pOther ) +void CPushable::Touch( CBaseEntity *pOther ) { - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) + if( FClassnameIs( pOther->pev, "worldspawn" ) ) return; Move( pOther, 1 ); } -void CPushable :: Move( CBaseEntity *pOther, int push ) +void CPushable::Move( CBaseEntity *pOther, int push ) { - entvars_t* pevToucher = pOther->pev; + 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 ) + if( FBitSet( pevToucher->flags,FL_ONGROUND ) && pevToucher->groundentity && VARS( pevToucher->groundentity ) == pev ) { // Only push if floating - if ( pev->waterlevel > 0 ) + if( pev->waterlevel > 0 ) pev->velocity.z += pevToucher->velocity.z * 0.1; return; } // g-cont. fix pushable acceleration bug (reverted as it used in mods) - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { // Don't push unless the player is pushing forward and NOT use (pull) - if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) + if( push && !( pevToucher->button & ( IN_FORWARD | IN_USE ) ) ) return; playerTouch = 1; } float factor; - if ( playerTouch ) + if( playerTouch ) { - if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water + if( !( pevToucher->flags & FL_ONGROUND ) ) // Don't push away from jumping/falling players unless in water { - if ( pev->waterlevel < 1 ) + if( pev->waterlevel < 1 ) return; else factor = 0.1; @@ -943,27 +956,27 @@ void CPushable :: Move( CBaseEntity *pOther, int push ) 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()) ) + if( push && ( length > MaxSpeed() ) ) { pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); } - if ( playerTouch ) + if( playerTouch ) { pevToucher->velocity.x = pev->velocity.x; pevToucher->velocity.y = pev->velocity.y; - if ( (gpGlobals->time - m_soundTime) > 0.7 ) + if( ( gpGlobals->time - m_soundTime ) > 0.7 ) { m_soundTime = gpGlobals->time; - if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) ) + 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); + 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] ); + STOP_SOUND( ENT( pev ), CHAN_WEAPON, m_soundNames[m_lastSound] ); } } } @@ -972,14 +985,14 @@ void CPushable :: Move( CBaseEntity *pOther, int push ) void CPushable::StopSound( void ) { Vector dist = pev->oldorigin - pev->origin; - if ( dist.Length() <= 0 ) - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); + 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 ) +int CPushable::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) + if( pev->spawnflags & SF_PUSH_BREAKABLE ) return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); return 1; diff --git a/dlls/func_break.h b/dlls/func_break.h index 9bb281d6..ab5dda41 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -15,8 +15,25 @@ #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; +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; @@ -32,23 +49,23 @@ public: void DamageSound( void ); // breakables use an overridden takedamage - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + 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 ); + 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 ); + 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; } + 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 ); @@ -61,14 +78,13 @@ public: static const char *pSoundsConcrete[]; static const char *pSpawnObjects[]; - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; - Materials m_Material; - Explosions m_Explosion; - int m_idShard; - float m_angle; - int m_iszGibModel; - int m_iszSpawnObject; + 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/dlls/func_tank.cpp b/dlls/func_tank.cpp index a61e5c14..eab9e621 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -46,12 +46,12 @@ enum TANKBULLET 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 ); + 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 ) @@ -59,17 +59,17 @@ public: return pTarget->BodyTarget( pev->origin ); } - void StartRotSound( void ); - void StopRotSound( void ); + void StartRotSound( void ); + void StopRotSound( void ); // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + 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 ); + BOOL InRange( float range ); // Acquire a target. pPlayer is a player in the PVS edict_t *FindTarget( edict_t *pPlayer ); @@ -129,7 +129,7 @@ protected: int m_iszMaster; // Master entity (game_team_master or multisource) }; -TYPEDESCRIPTION CFuncTank::m_SaveData[] = +TYPEDESCRIPTION CFuncTank::m_SaveData[] = { DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), @@ -170,148 +170,149 @@ static Vector gTankSpread[] = Vector( 0.25, 0.25, 0.25 ), // extra-large cone }; -#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) +#define MAX_FIRING_SPREADS ARRAYSIZE( gTankSpread ) -void CFuncTank :: Spawn( void ) +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) ); + 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() ) + if( IsActive() ) pev->nextthink = pev->ltime + 1.0; m_sightOrigin = BarrelPosition(); // Point at the end of the barrel - if ( m_fireRate <= 0 ) + if( m_fireRate <= 0 ) m_fireRate = 1; - if ( m_spread > MAX_FIRING_SPREADS ) + if( m_spread > MAX_FIRING_SPREADS ) m_spread = 0; pev->oldorigin = pev->origin; } -void CFuncTank :: Precache( void ) +void CFuncTank::Precache( void ) { - if ( m_iszSpriteSmoke ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteSmoke) ); - if ( m_iszSpriteFlash ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteFlash) ); + if( m_iszSpriteSmoke ) + PRECACHE_MODEL( (char *)STRING( m_iszSpriteSmoke ) ); - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); + if( m_iszSpriteFlash ) + PRECACHE_MODEL( (char *)STRING( m_iszSpriteFlash ) ); + + if( pev->noise ) + PRECACHE_SOUND( (char *)STRING( pev->noise ) ); } -void CFuncTank :: KeyValue( KeyValueData *pkvd ) +void CFuncTank::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "yawrate")) + if( FStrEq( pkvd->szKeyName, "yawrate" ) ) { - m_yawRate = atof(pkvd->szValue); + m_yawRate = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "yawrange")) + else if( FStrEq( pkvd->szKeyName, "yawrange" ) ) { - m_yawRange = atof(pkvd->szValue); + m_yawRange = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "yawtolerance")) + else if( FStrEq( pkvd->szKeyName, "yawtolerance" ) ) { - m_yawTolerance = atof(pkvd->szValue); + m_yawTolerance = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "pitchrange")) + else if( FStrEq( pkvd->szKeyName, "pitchrange" ) ) { - m_pitchRange = atof(pkvd->szValue); + m_pitchRange = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "pitchrate")) + else if( FStrEq( pkvd->szKeyName, "pitchrate" ) ) { - m_pitchRate = atof(pkvd->szValue); + m_pitchRate = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) + else if( FStrEq( pkvd->szKeyName, "pitchtolerance" ) ) { - m_pitchTolerance = atof(pkvd->szValue); + m_pitchTolerance = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "firerate")) + else if( FStrEq( pkvd->szKeyName, "firerate" ) ) { - m_fireRate = atof(pkvd->szValue); + m_fireRate = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "barrel")) + else if( FStrEq( pkvd->szKeyName, "barrel" ) ) { - m_barrelPos.x = atof(pkvd->szValue); + m_barrelPos.x = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "barrely")) + else if( FStrEq( pkvd->szKeyName, "barrely" ) ) { - m_barrelPos.y = atof(pkvd->szValue); + m_barrelPos.y = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "barrelz")) + else if( FStrEq( pkvd->szKeyName, "barrelz" ) ) { - m_barrelPos.z = atof(pkvd->szValue); + m_barrelPos.z = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "spritescale")) + else if( FStrEq( pkvd->szKeyName, "spritescale" ) ) { - m_spriteScale = atof(pkvd->szValue); + m_spriteScale = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "spritesmoke")) + else if( FStrEq( pkvd->szKeyName, "spritesmoke" ) ) { - m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); + m_iszSpriteSmoke = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "spriteflash")) + else if( FStrEq( pkvd->szKeyName, "spriteflash" ) ) { - m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); + m_iszSpriteFlash = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "rotatesound")) + else if( FStrEq( pkvd->szKeyName, "rotatesound" ) ) { - pev->noise = ALLOC_STRING(pkvd->szValue); + pev->noise = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "persistence")) + else if( FStrEq( pkvd->szKeyName, "persistence" ) ) { - m_persist = atof(pkvd->szValue); + m_persist = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "bullet")) + else if( FStrEq( pkvd->szKeyName, "bullet" ) ) { - m_bulletType = (TANKBULLET)atoi(pkvd->szValue); + m_bulletType = (TANKBULLET)atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) + else if( FStrEq( pkvd->szKeyName, "bullet_damage" ) ) { - m_iBulletDamage = atoi(pkvd->szValue); + m_iBulletDamage = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "firespread")) + else if( FStrEq(pkvd->szKeyName, "firespread" ) ) { - m_spread = atoi(pkvd->szValue); + m_spread = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "minRange")) + else if( FStrEq( pkvd->szKeyName, "minRange" ) ) { - m_minRange = atof(pkvd->szValue); + m_minRange = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "maxRange")) + else if( FStrEq( pkvd->szKeyName, "maxRange" ) ) { - m_maxRange = atof(pkvd->szValue); + m_maxRange = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "master")) + else if( FStrEq( pkvd->szKeyName, "master" ) ) { - m_iszMaster = ALLOC_STRING(pkvd->szValue); + m_iszMaster = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -322,57 +323,56 @@ void CFuncTank :: KeyValue( KeyValueData *pkvd ) //================================================================================== // TANK CONTROLLING -BOOL CFuncTank :: OnControls( entvars_t *pevTest ) +BOOL CFuncTank::OnControls( entvars_t *pevTest ) { - if ( !(pev->spawnflags & SF_TANK_CANCONTROL) ) + if( !( pev->spawnflags & SF_TANK_CANCONTROL ) ) return FALSE; Vector offset = pevTest->origin - pev->origin; - if ( (m_vecControllerUsePos - pevTest->origin).Length() < 30 ) + if( ( m_vecControllerUsePos - pevTest->origin ).Length() < 30 ) return TRUE; return FALSE; } -BOOL CFuncTank :: StartControl( CBasePlayer *pController ) +BOOL CFuncTank::StartControl( CBasePlayer *pController ) { - if ( m_pController != NULL ) + if( m_pController != NULL ) return FALSE; // Team only or disabled? - if ( m_iszMaster ) + if( m_iszMaster ) { - if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) + if( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) return FALSE; } ALERT( at_console, "using TANK!\n"); m_pController = pController; - if ( m_pController->m_pActiveItem ) + if( m_pController->m_pActiveItem ) { m_pController->m_pActiveItem->Holster(); m_pController->pev->weaponmodel = 0; - m_pController->pev->viewmodel = 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() +void CFuncTank::StopControl() { // TODO: bring back the controllers current weapon - if ( !m_pController ) + if( !m_pController ) return; - if ( m_pController->m_pActiveItem ) + if( m_pController->m_pActiveItem ) m_pController->m_pActiveItem->Deploy(); ALERT( at_console, "stopped using TANK\n"); @@ -382,51 +382,51 @@ void CFuncTank :: StopControl() pev->nextthink = 0; m_pController = NULL; - if ( IsActive() ) + if( IsActive() ) pev->nextthink = pev->ltime + 1.0; } // Called each frame by the player's ItemPostFrame -void CFuncTank :: ControllerPostFrame( void ) +void CFuncTank::ControllerPostFrame( void ) { - ASSERT(m_pController != NULL); + ASSERT( m_pController != NULL ); - if ( gpGlobals->time < m_flNextAttack ) + if( gpGlobals->time < m_flNextAttack ) return; - if ( m_pController->pev->button & IN_ATTACK ) + 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 + 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; + if( m_pController && m_pController->IsPlayer() ) + ( (CBasePlayer *)m_pController )->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_flNextAttack = gpGlobals->time + (1/m_fireRate); + m_flNextAttack = gpGlobals->time + ( 1 / m_fireRate ); } } ////////////// END NEW STUFF ////////////// -void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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 ) + if( pev->spawnflags & SF_TANK_CANCONTROL ) + { + // player controlled turret + if( pActivator->Classify() != CLASS_PLAYER ) return; - if ( value == 2 && useType == USE_SET ) + if( value == 2 && useType == USE_SET ) { ControllerPostFrame(); } - else if ( !m_pController && useType != USE_OFF ) + else if( !m_pController && useType != USE_OFF ) { - ((CBasePlayer*)pActivator)->m_pTank = this; + ( (CBasePlayer*)pActivator )->m_pTank = this; StartControl( (CBasePlayer*)pActivator ); } else @@ -436,37 +436,37 @@ void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u } else { - if ( !ShouldToggle( useType, IsActive() ) ) + if( !ShouldToggle( useType, IsActive() ) ) return; - if ( IsActive() ) + if( IsActive() ) TankDeactivate(); else TankActivate(); } } -edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) +edict_t *CFuncTank::FindTarget( edict_t *pPlayer ) { return pPlayer; } -BOOL CFuncTank :: InRange( float range ) +BOOL CFuncTank::InRange( float range ) { - if ( range < m_minRange ) + if( range < m_minRange ) return FALSE; - if ( m_maxRange > 0 && range > m_maxRange ) + if( m_maxRange > 0 && range > m_maxRange ) return FALSE; return TRUE; } -void CFuncTank :: Think( void ) +void CFuncTank::Think( void ) { pev->avelocity = g_vecZero; TrackTarget(); - if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) + if( fabs( pev->avelocity.x ) > 1 || fabs( pev->avelocity.y ) > 1 ) StartRotSound(); else StopRotSound(); @@ -481,7 +481,7 @@ void CFuncTank::TrackTarget( void ) edict_t *pTarget; // Get a position to aim for - if (m_pController) + if( m_pController ) { // Tanks attempt to mirror the player's angles angles = m_pController->pev->v_angle; @@ -490,39 +490,39 @@ void CFuncTank::TrackTarget( void ) } else { - if ( IsActive() ) + if( IsActive() ) pev->nextthink = pev->ltime + 0.1; else return; - if ( FNullEnt( pPlayer ) ) + if( FNullEnt( pPlayer ) ) { - if ( IsActive() ) + if( IsActive() ) pev->nextthink = pev->ltime + 2; // Wait 2 secs return; } pTarget = FindTarget( pPlayer ); - if ( !pTarget ) + 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 ) ) + float range = ( targetPosition - barrelEnd ).Length(); + + if( !InRange( range ) ) return; UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - + lineOfSight = FALSE; // No line of sight, don't track - if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) + if( tr.flFraction == 1.0 || tr.pHit == pTarget ) { lineOfSight = TRUE; CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); - if ( InRange( range ) && pInstance && pInstance->IsAlive() ) + if( InRange( range ) && pInstance && pInstance->IsAlive() ) { updateTime = TRUE; m_sightOrigin = UpdateTargetPosition( pInstance ); @@ -546,63 +546,63 @@ void CFuncTank::TrackTarget( void ) angles.x = m_pitchCenter + UTIL_AngleDistance( angles.x, m_pitchCenter ); // Limit against range in y - if ( angles.y > m_yawCenter + m_yawRange ) + 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) ) + else if( angles.y < ( m_yawCenter - m_yawRange ) ) { - 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 ) + 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 ) + if( pev->avelocity.y > m_yawRate ) pev->avelocity.y = m_yawRate; - else if ( 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 ) + if( angles.x > m_pitchCenter + m_pitchRange ) angles.x = m_pitchCenter + m_pitchRange; - else if ( 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 ) + if( pev->avelocity.x > m_pitchRate ) pev->avelocity.x = m_pitchRate; - else if ( pev->avelocity.x < -m_pitchRate ) + else if( pev->avelocity.x < -m_pitchRate ) pev->avelocity.x = -m_pitchRate; - if ( m_pController ) + if( m_pController ) return; - if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) + 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 ) + 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 ) + if( tr.pHit == pTarget ) fire = TRUE; } else fire = TRUE; - if ( fire ) + if( fire ) { Fire( BarrelPosition(), forward, pev ); } @@ -618,20 +618,19 @@ void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) { float r2, d2; - - if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) + if( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) { distance -= m_barrelPos.z; d2 = distance * distance; - if ( m_barrelPos.y ) + if( m_barrelPos.y ) { r2 = m_barrelPos.y * m_barrelPos.y; - angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); + angles.y += ( 180.0 / M_PI ) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); } - if ( m_barrelPos.z ) + if( m_barrelPos.z ) { r2 = m_barrelPos.z * m_barrelPos.z; - angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); + angles.x += ( 180.0 / M_PI ) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); } } } @@ -639,19 +638,19 @@ void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) // Fire targets and spawn sprites void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { - if ( m_fireLast != 0 ) + if( m_fireLast != 0 ) { - if ( m_iszSpriteSmoke ) + if( m_iszSpriteSmoke ) { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); + CSprite *pSprite = CSprite::SpriteCreate( STRING( m_iszSpriteSmoke ), barrelEnd, TRUE ); pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); - pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); + pSprite->pev->velocity.z = RANDOM_FLOAT( 40, 80 ); pSprite->SetScale( m_spriteScale ); } - if ( m_iszSpriteFlash ) + if( m_iszSpriteFlash ) { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); + CSprite *pSprite = CSprite::SpriteCreate( STRING( m_iszSpriteFlash ), barrelEnd, TRUE ); pSprite->AnimateAndDie( 60 ); pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); pSprite->SetScale( m_spriteScale ); @@ -668,32 +667,33 @@ void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, con { // 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); + 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) ) + 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); + 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) ); + if( pev->spawnflags & SF_TANK_SOUNDON ) + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING( pev->noise ) ); pev->spawnflags &= ~SF_TANK_SOUNDON; } @@ -709,30 +709,27 @@ void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars { int i; - if ( m_fireLast != 0 ) + if( m_fireLast != 0 ) { // FireBullets needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); + UTIL_MakeAimVectors( pev->angles ); - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) + int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + if( bulletCount > 0 ) { - for ( i = 0; i < bulletCount; i++ ) + 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; @@ -748,24 +745,24 @@ void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars 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 ); + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; private: - CLaser *m_pLaser; - float m_laserTime; + CLaser *m_pLaser; + float m_laserTime; }; LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ) -TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = +TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = { DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), @@ -775,9 +772,9 @@ IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ) void CFuncTankLaser::Activate( void ) { - if ( !GetLaser() ) + if( !GetLaser() ) { - UTIL_Remove(this); + UTIL_Remove( this ); ALERT( at_error, "Laser tank with no env_laser!\n" ); } else @@ -788,9 +785,9 @@ void CFuncTankLaser::Activate( void ) void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "laserentity")) + if( FStrEq( pkvd->szKeyName, "laserentity" ) ) { - pev->message = ALLOC_STRING(pkvd->szValue); + pev->message = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -799,22 +796,22 @@ void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) CLaser *CFuncTankLaser::GetLaser( void ) { - if ( m_pLaser ) + if( m_pLaser ) return m_pLaser; edict_t *pentLaser; - pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->message) ); - while ( !FNullEnt( pentLaser ) ) + pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->message ) ); + while( !FNullEnt( pentLaser ) ) { // Found the landmark - if ( FClassnameIs( pentLaser, "env_laser" ) ) + if( FClassnameIs( pentLaser, "env_laser" ) ) { - m_pLaser = (CLaser *)CBaseEntity::Instance(pentLaser); + m_pLaser = (CLaser *)CBaseEntity::Instance( pentLaser ); break; } else - pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING(pev->message) ); + pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING( pev->message ) ); } return m_pLaser; @@ -822,7 +819,7 @@ CLaser *CFuncTankLaser::GetLaser( void ) void CFuncTankLaser::Think( void ) { - if ( m_pLaser && (gpGlobals->time > m_laserTime) ) + if( m_pLaser && (gpGlobals->time > m_laserTime) ) m_pLaser->TurnOff(); CFuncTank::Think(); @@ -833,19 +830,19 @@ void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entva int i; TraceResult tr; - if ( m_fireLast != 0 && GetLaser() ) + if( m_fireLast != 0 && GetLaser() ) { // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); + UTIL_MakeAimVectors( pev->angles ); - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount ) + int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + if( bulletCount ) { - for ( i = 0; i < bulletCount; i++ ) + 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; @@ -880,12 +877,12 @@ void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entv { int i; - if ( m_fireLast != 0 ) + if( m_fireLast != 0 ) { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; - if ( bulletCount > 0 ) + int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + if( bulletCount > 0 ) { - for ( i = 0; i < bulletCount; i++ ) + for( i = 0; i < bulletCount; i++ ) { CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); } @@ -907,7 +904,7 @@ LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ) void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "iMagnitude")) + if( FStrEq( pkvd->szKeyName, "iMagnitude" ) ) { pev->impulse = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -918,16 +915,16 @@ void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) { - if ( m_fireLast != 0 ) + if( m_fireLast != 0 ) { - int bulletCount = (gpGlobals->time - m_fireLast) * m_fireRate; + int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; // Only create 1 explosion - if ( bulletCount > 0 ) + if( bulletCount > 0 ) { TraceResult tr; // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); + UTIL_MakeAimVectors( pev->angles ); TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); @@ -946,13 +943,13 @@ void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entv class CFuncTankControls : public CBaseEntity { public: - virtual int ObjectCaps( void ); + 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; CFuncTank *m_pTank; @@ -960,43 +957,43 @@ public: LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ) -TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = +TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = { DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), }; IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ) -int CFuncTankControls :: ObjectCaps( void ) +int CFuncTankControls::ObjectCaps( void ) { - return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; + return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | FCAP_IMPULSE_USE; } -void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncTankControls::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // pass the Use command onto the controls - if ( m_pTank ) + 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 ) +void CFuncTankControls::Think( void ) { edict_t *pTarget = NULL; - do + do { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && strncmp( STRING(pTarget->v.classname), "func_tank", 9 ) ); + pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING( pev->target ) ); + } while( !FNullEnt( pTarget ) && strncmp( STRING( pTarget->v.classname ), "func_tank", 9 ) ); - if ( FNullEnt( pTarget ) ) + if( FNullEnt( pTarget ) ) { - ALERT( at_console, "No tank %s\n", STRING(pev->target) ); + ALERT( at_console, "No tank %s\n", STRING( pev->target ) ); return; } - m_pTank = (CFuncTank*)Instance(pTarget); + m_pTank = (CFuncTank*)Instance( pTarget ); } void CFuncTankControls::Spawn( void ) @@ -1004,11 +1001,11 @@ void CFuncTankControls::Spawn( void ) pev->solid = SOLID_TRIGGER; pev->movetype = MOVETYPE_NONE; pev->effects |= EF_NODRAW; - SET_MODEL( ENT(pev), STRING(pev->model) ); + 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/dlls/game.cpp b/dlls/game.cpp index 1017da1b..3aec1810 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -17,34 +17,34 @@ #include "util.h" #include "game.h" -cvar_t displaysoundlist = {"displaysoundlist","0"}; +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 }; // " " +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 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 mp_chattime = {"mp_chattime","10", FCVAR_SERVER }; +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; +cvar_t *g_psv_gravity = NULL; +cvar_t *g_psv_aim = NULL; +cvar_t *g_footsteps = NULL; //CVARS FOR SKILL LEVEL SETTINGS // Agrunt @@ -57,14 +57,14 @@ 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"}; +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"}; +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"}; @@ -230,7 +230,6 @@ 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"}; @@ -244,8 +243,6 @@ 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"}; @@ -259,25 +256,21 @@ 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 @@ -430,13 +423,13 @@ 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_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_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" }; @@ -458,428 +451,402 @@ void GameDLLInit( void ) g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); - CVAR_REGISTER (&displaysoundlist); + CVAR_REGISTER( &displaysoundlist ); - CVAR_REGISTER (&teamplay); - CVAR_REGISTER (&fraglimit); - CVAR_REGISTER (&timelimit); + CVAR_REGISTER( &teamplay ); + CVAR_REGISTER( &fraglimit ); + CVAR_REGISTER( &timelimit ); - CVAR_REGISTER (&fragsleft); - CVAR_REGISTER (&timeleft); + 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( &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); + 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_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"}; + 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"}; + 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"}; + 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_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_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_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_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_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_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_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"}; + 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_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_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"}; + 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"}; - + 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_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"}; + 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"}; - // 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_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_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 ); + 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"}; + 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_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_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"}; + 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"}; - + 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"}; + 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_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_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_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 ); + 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_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 ); + 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"}; - + 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"}; + 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_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"}; + 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"}; - + 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"}; - + 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"}; + 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"}; + 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"}; + 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"}; + 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"}; - + 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"}; - + 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"}; - + 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"}; + 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"}; - + 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"}; - + 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"}; + 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"}; - + 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"}; - + 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"}; - + 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_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"}; + 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"}; + 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_suitcharger1 ); + CVAR_REGISTER( &sk_suitcharger2 ); + CVAR_REGISTER( &sk_suitcharger3 ); - CVAR_REGISTER ( &sk_battery1 ); - CVAR_REGISTER ( &sk_battery2 ); - CVAR_REGISTER ( &sk_battery3 ); + 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_healthcharger1 ); + CVAR_REGISTER( &sk_healthcharger2 ); + CVAR_REGISTER( &sk_healthcharger3 ); - CVAR_REGISTER ( &sk_healthkit1 ); - CVAR_REGISTER ( &sk_healthkit2 ); - CVAR_REGISTER ( &sk_healthkit3 ); + 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 ); + 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 ); + // 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_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_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_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 ); + 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 ); + // 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_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_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_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 ); + 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/dlls/game.h b/dlls/game.h index 58e7e759..925010f3 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -18,28 +18,26 @@ extern void GameDLLInit( void ); - -extern cvar_t displaysoundlist; +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; +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 +extern cvar_t *g_psv_gravity; +extern cvar_t *g_psv_aim; +extern cvar_t *g_footsteps; +#endif // GAME_H diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index 829cae0f..059b4d61 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -28,8 +28,8 @@ extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); -DLL_GLOBAL CGameRules* g_pGameRules = NULL; -extern DLL_GLOBAL BOOL g_fGameOver; +DLL_GLOBAL CGameRules *g_pGameRules = NULL; +extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages extern int gmsgMOTD; @@ -41,13 +41,13 @@ BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int { int iAmmoIndex; - if ( pszAmmoName ) + if( pszAmmoName ) { iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName ); - if ( iAmmoIndex > -1 ) + if( iAmmoIndex > -1 ) { - if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) + if( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) { // player has room for more of this type of ammo return TRUE; @@ -60,17 +60,17 @@ BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int //========================================================= //========================================================= -edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) +edict_t *CGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) { edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); - pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); + 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->angles = VARS( pentSpawnSpot )->angles; pPlayer->pev->punchangle = g_vecZero; pPlayer->pev->fixangle = TRUE; - + return pentSpawnSpot; } @@ -79,16 +79,16 @@ edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { // only living players can have items - if ( pPlayer->pev->deadflag != DEAD_NO ) + if( pPlayer->pev->deadflag != DEAD_NO ) return FALSE; - if ( pWeapon->pszAmmo1() ) + if( pWeapon->pszAmmo1() ) { - if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) + 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 ) ) + if( pPlayer->HasPlayerItem( pWeapon ) ) { return FALSE; } @@ -97,7 +97,7 @@ BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeap else { // weapon doesn't use ammo, don't take another if you already have it. - if ( pPlayer->HasPlayerItem( pWeapon ) ) + if( pPlayer->HasPlayerItem( pWeapon ) ) { return FALSE; } @@ -112,33 +112,33 @@ BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeap //========================================================= void CGameRules::RefreshSkillData ( void ) { - int iSkill; + int iSkill; - iSkill = (int)CVAR_GET_FLOAT("skill"); + iSkill = (int)CVAR_GET_FLOAT( "skill" ); g_iSkillLevel = iSkill; - if ( iSkill < 1 ) + if( iSkill < 1 ) { iSkill = 1; } - else if ( iSkill > 3 ) + else if( iSkill > 3 ) { iSkill = 3; } gSkillData.iSkillLevel = iSkill; - ALERT ( at_console, "\nGAME SKILL LEVEL:%d\n",iSkill ); + ALERT( at_console, "\nGAME SKILL LEVEL:%d\n",iSkill ); //Agrunt gSkillData.agruntHealth = GetSkillCvar( "sk_agrunt_health" ); - gSkillData.agruntDmgPunch = GetSkillCvar( "sk_agrunt_dmg_punch"); + gSkillData.agruntDmgPunch = GetSkillCvar( "sk_agrunt_dmg_punch" ); // Apache - gSkillData.apacheHealth = GetSkillCvar( "sk_apache_health"); + gSkillData.apacheHealth = GetSkillCvar( "sk_apache_health" ); // Barney - gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health"); + gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health" ); // Big Momma gSkillData.bigmommaHealthFactor = GetSkillCvar( "sk_bigmomma_health_factor" ); @@ -147,131 +147,131 @@ void CGameRules::RefreshSkillData ( void ) 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"); + 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"); + 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"); + gSkillData.hassassinHealth = GetSkillCvar( "sk_hassassin_health" ); // Headcrab - gSkillData.headcrabHealth = GetSkillCvar( "sk_headcrab_health"); - gSkillData.headcrabDmgBite = GetSkillCvar( "sk_headcrab_dmg_bite"); + 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"); + 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"); + 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"); + 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"); + gSkillData.ichthyosaurHealth = GetSkillCvar( "sk_ichthyosaur_health" ); + gSkillData.ichthyosaurDmgShake = GetSkillCvar( "sk_ichthyosaur_shake" ); // Leech - gSkillData.leechHealth = GetSkillCvar( "sk_leech_health"); + gSkillData.leechHealth = GetSkillCvar( "sk_leech_health" ); - gSkillData.leechDmgBite = GetSkillCvar( "sk_leech_dmg_bite"); + 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"); + 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"); + gSkillData.nihilanthHealth = GetSkillCvar( "sk_nihilanth_health" ); + gSkillData.nihilanthZap = GetSkillCvar( "sk_nihilanth_zap" ); // Scientist - gSkillData.scientistHealth = GetSkillCvar( "sk_scientist_health"); + 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"); + 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"); + 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"); + gSkillData.turretHealth = GetSkillCvar( "sk_turret_health" ); // MiniTurret - gSkillData.miniturretHealth = GetSkillCvar( "sk_miniturret_health"); - - // Sentry Turret - gSkillData.sentryHealth = GetSkillCvar( "sk_sentry_health"); + gSkillData.miniturretHealth = GetSkillCvar( "sk_miniturret_health" ); -// PLAYER WEAPONS + // Sentry Turret + gSkillData.sentryHealth = GetSkillCvar( "sk_sentry_health" ); + + // PLAYER WEAPONS // Crowbar whack - gSkillData.plrDmgCrowbar = GetSkillCvar( "sk_plr_crowbar"); + gSkillData.plrDmgCrowbar = GetSkillCvar( "sk_plr_crowbar" ); // Glock Round - gSkillData.plrDmg9MM = GetSkillCvar( "sk_plr_9mm_bullet"); + gSkillData.plrDmg9MM = GetSkillCvar( "sk_plr_9mm_bullet" ); // 357 Round - gSkillData.plrDmg357 = GetSkillCvar( "sk_plr_357_bullet"); + gSkillData.plrDmg357 = GetSkillCvar( "sk_plr_357_bullet" ); // MP5 Round - gSkillData.plrDmgMP5 = GetSkillCvar( "sk_plr_9mmAR_bullet"); + gSkillData.plrDmgMP5 = GetSkillCvar( "sk_plr_9mmAR_bullet" ); // M203 grenade - gSkillData.plrDmgM203Grenade = GetSkillCvar( "sk_plr_9mmAR_grenade"); + gSkillData.plrDmgM203Grenade = GetSkillCvar( "sk_plr_9mmAR_grenade" ); // Shotgun buckshot - gSkillData.plrDmgBuckshot = GetSkillCvar( "sk_plr_buckshot"); + gSkillData.plrDmgBuckshot = GetSkillCvar( "sk_plr_buckshot" ); // Crossbow - gSkillData.plrDmgCrossbowClient = GetSkillCvar( "sk_plr_xbow_bolt_client"); - gSkillData.plrDmgCrossbowMonster = GetSkillCvar( "sk_plr_xbow_bolt_monster"); + gSkillData.plrDmgCrossbowClient = GetSkillCvar( "sk_plr_xbow_bolt_client" ); + gSkillData.plrDmgCrossbowMonster = GetSkillCvar( "sk_plr_xbow_bolt_monster" ); // RPG - gSkillData.plrDmgRPG = GetSkillCvar( "sk_plr_rpg"); + gSkillData.plrDmgRPG = GetSkillCvar( "sk_plr_rpg" ); // Gauss gun - gSkillData.plrDmgGauss = GetSkillCvar( "sk_plr_gauss"); + gSkillData.plrDmgGauss = GetSkillCvar( "sk_plr_gauss" ); // Egon Gun - gSkillData.plrDmgEgonNarrow = GetSkillCvar( "sk_plr_egon_narrow"); - gSkillData.plrDmgEgonWide = GetSkillCvar( "sk_plr_egon_wide"); + gSkillData.plrDmgEgonNarrow = GetSkillCvar( "sk_plr_egon_narrow" ); + gSkillData.plrDmgEgonWide = GetSkillCvar( "sk_plr_egon_wide" ); // Hand Grendade - gSkillData.plrDmgHandGrenade = GetSkillCvar( "sk_plr_hand_grenade"); + gSkillData.plrDmgHandGrenade = GetSkillCvar( "sk_plr_hand_grenade" ); // Satchel Charge - gSkillData.plrDmgSatchel = GetSkillCvar( "sk_plr_satchel"); + gSkillData.plrDmgSatchel = GetSkillCvar( "sk_plr_satchel" ); // Tripmine - gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine"); + gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine" ); // MONSTER WEAPONS - gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet"); + gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet" ); gSkillData.monDmgMP5 = GetSkillCvar ("sk_9mmAR_bullet" ); - gSkillData.monDmg9MM = GetSkillCvar( "sk_9mm_bullet"); + gSkillData.monDmg9MM = GetSkillCvar( "sk_9mm_bullet" ); // MONSTER HORNET - gSkillData.monDmgHornet = GetSkillCvar( "sk_hornet_dmg"); + gSkillData.monDmgHornet = GetSkillCvar( "sk_hornet_dmg" ); // PLAYER HORNET // Up to this point, player hornet damage and monster hornet damage were both using @@ -281,7 +281,6 @@ void CGameRules::RefreshSkillData ( void ) // 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" ); @@ -311,9 +310,9 @@ void CGameRules::RefreshSkillData ( void ) CGameRules *InstallGameRules( void ) { SERVER_COMMAND( "exec game.cfg\n" ); - SERVER_EXECUTE( ); + SERVER_EXECUTE(); - if ( !gpGlobals->deathmatch ) + if( !gpGlobals->deathmatch ) { // generic half-life g_teamplay = 0; @@ -321,14 +320,13 @@ CGameRules *InstallGameRules( void ) } else { - if ( teamplay.value > 0 ) + if( teamplay.value > 0 ) { // teamplay - g_teamplay = 1; return new CHalfLifeTeamplay; } - if ((int)gpGlobals->deathmatch == 1) + if( (int)gpGlobals->deathmatch == 1 ) { // vanilla deathmatch g_teamplay = 0; @@ -342,6 +340,3 @@ CGameRules *InstallGameRules( void ) } } } - - - diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 5dc5cb3e..ef235fc1 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -27,13 +27,13 @@ class CBasePlayerAmmo; 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, @@ -75,14 +75,14 @@ public: 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 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 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 @@ -179,7 +179,7 @@ public: 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 ); @@ -192,7 +192,7 @@ public: // Client damage rules virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - + // Client spawn/respawn control virtual void PlayerSpawn( CBasePlayer *pPlayer ); virtual void PlayerThink( CBasePlayer *pPlayer ); @@ -276,7 +276,7 @@ public: // 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 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 @@ -358,4 +358,4 @@ protected: void SendMOTDToClient( edict_t *client ); }; -extern DLL_GLOBAL CGameRules* g_pGameRules; +extern DLL_GLOBAL CGameRules *g_pGameRules; diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index 65878f7e..6c65b06f 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -41,19 +41,19 @@ const float GARG_ATTACKDIST = 80.0; //#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 -#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime +#define GARG_AE_STOMP 5 +#define GARG_AE_BREATHE 6 +#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime // 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_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 GARG_FLAME_LENGTH 330 +#define GARG_GIB_MODEL "models/metalplategibs.mdl" #define ATTN_GARG (ATTN_NORM) @@ -85,7 +85,7 @@ public: private: // UNDONE: re-use this sprite list instead of creating new ones all the time -// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; +// CSprite *m_pSprites[STOMP_SPRITE_COUNT]; }; LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ) @@ -93,28 +93,28 @@ 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); + 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->classname = MAKE_STRING( "garg_stomp" ); pev->dmgtime = gpGlobals->time; pev->framerate = 30; - pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME); + 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); + EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55 ); } #define STOMP_INTERVAL 0.025 @@ -128,37 +128,37 @@ void CStomp::Think( void ) // Do damage for this frame Vector vecStart = pev->origin; vecStart.z += 30; - Vector vecEnd = vecStart + (pev->movedir * pev->speed * STOMP_FRAMETIME); + Vector vecEnd = vecStart + ( pev->movedir * pev->speed * STOMP_FRAMETIME ); UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit && tr.pHit != pev->owner ) + + 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( pev->owner ) + pevOwner = VARS( pev->owner ); - if ( pEntity ) + if( pEntity ) pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); } - + // Accelerate the effect - pev->speed = pev->speed + (STOMP_FRAMETIME) * pev->framerate; - pev->framerate = pev->framerate + (STOMP_FRAMETIME) * 1500; - + pev->speed = pev->speed + ( STOMP_FRAMETIME ) * pev->framerate; + pev->framerate = pev->framerate + ( STOMP_FRAMETIME ) * 1500; + // Move and spawn trails - while ( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) + while( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) { pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; - for ( int i = 0; i < 2; i++ ) + for( int i = 0; i < 2; i++ ) { CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); - if ( pSprite ) + if( pSprite ) { - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,500), ignore_monsters, edict(), &tr ); + 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->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( &CBaseEntity::SUB_Remove ); @@ -169,16 +169,15 @@ void CStomp::Think( void ) // Scale has the "life" of this effect pev->scale -= STOMP_INTERVAL * pev->speed; - if ( pev->scale <= 0 ) + if( pev->scale <= 0 ) { // Life has run out - UTIL_Remove(this); + 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 ); @@ -202,7 +201,7 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( 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 ); @@ -238,9 +237,9 @@ public: 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; CUSTOM_SCHEDULES @@ -262,18 +261,18 @@ private: 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) + 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_flameX; // Flame thrower aim float m_flameY; }; LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ) -TYPEDESCRIPTION CGargantua::m_SaveData[] = +TYPEDESCRIPTION CGargantua::m_SaveData[] = { DEFINE_FIELD( CGargantua, m_pEyeGlow, FIELD_CLASSPTR ), DEFINE_FIELD( CGargantua, m_eyeBrightness, FIELD_INTEGER ), @@ -288,27 +287,27 @@ TYPEDESCRIPTION CGargantua::m_SaveData[] = IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ) -const char *CGargantua::pAttackHitSounds[] = +const char *CGargantua::pAttackHitSounds[] = { "zombie/claw_strike1.wav", "zombie/claw_strike2.wav", "zombie/claw_strike3.wav", }; -const char *CGargantua::pBeamAttackSounds[] = +const char *CGargantua::pBeamAttackSounds[] = { "garg/gar_flameoff1.wav", "garg/gar_flameon1.wav", "garg/gar_flamerun1.wav", }; -const char *CGargantua::pAttackMissSounds[] = +const char *CGargantua::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", }; -const char *CGargantua::pRicSounds[] = +const char *CGargantua::pRicSounds[] = { #if 0 "weapons/ric1.wav", @@ -324,13 +323,13 @@ const char *CGargantua::pRicSounds[] = #endif }; -const char *CGargantua::pFootSounds[] = +const char *CGargantua::pFootSounds[] = { "garg/gar_step1.wav", "garg/gar_step2.wav", }; -const char *CGargantua::pIdleSounds[] = +const char *CGargantua::pIdleSounds[] = { "garg/gar_idle1.wav", "garg/gar_idle2.wav", @@ -339,33 +338,33 @@ const char *CGargantua::pIdleSounds[] = "garg/gar_idle5.wav", }; -const char *CGargantua::pAttackSounds[] = +const char *CGargantua::pAttackSounds[] = { "garg/gar_attack1.wav", "garg/gar_attack2.wav", "garg/gar_attack3.wav", }; -const char *CGargantua::pAlertSounds[] = +const char *CGargantua::pAlertSounds[] = { "garg/gar_alert1.wav", "garg/gar_alert2.wav", "garg/gar_alert3.wav", }; -const char *CGargantua::pPainSounds[] = +const char *CGargantua::pPainSounds[] = { "garg/gar_pain1.wav", "garg/gar_pain2.wav", "garg/gar_pain3.wav", }; -const char *CGargantua::pStompSounds[] = +const char *CGargantua::pStompSounds[] = { "garg/gar_stomp1.wav", }; -const char *CGargantua::pBreatheSounds[] = +const char *CGargantua::pBreatheSounds[] = { "garg/gar_breathe1.wav", "garg/gar_breathe2.wav", @@ -387,22 +386,22 @@ enum TASK_FLAME_SWEEP }; -Task_t tlGargFlame[] = +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 }, + { 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[] = +Schedule_t slGargFlame[] = { - { + { tlGargFlame, - ARRAYSIZE ( tlGargFlame ), + ARRAYSIZE( tlGargFlame ), 0, 0, "GargFlame" @@ -410,18 +409,18 @@ Schedule_t slGargFlame[] = }; // primary melee attack -Task_t tlGargSwipe[] = +Task_t tlGargSwipe[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_MELEE_ATTACK1, (float)0 }, }; -Schedule_t slGargSwipe[] = +Schedule_t slGargSwipe[] = { - { + { tlGargSwipe, - ARRAYSIZE ( tlGargSwipe ), + ARRAYSIZE( tlGargSwipe ), bits_COND_CAN_MELEE_ATTACK2, 0, "GargSwipe" @@ -438,7 +437,7 @@ IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ) void CGargantua::EyeOn( int level ) { - m_eyeBrightness = level; + m_eyeBrightness = level; } void CGargantua::EyeOff( void ) @@ -448,10 +447,10 @@ void CGargantua::EyeOff( void ) void CGargantua::EyeUpdate( void ) { - if ( m_pEyeGlow ) + if( m_pEyeGlow ) { m_pEyeGlow->pev->renderamt = UTIL_Approach( m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26 ); - if ( m_pEyeGlow->pev->renderamt == 0 ) + if( m_pEyeGlow->pev->renderamt == 0 ) m_pEyeGlow->pev->effects |= EF_NODRAW; else m_pEyeGlow->pev->effects &= ~EF_NODRAW; @@ -471,38 +470,38 @@ void CGargantua::StompAttack( void ) 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) ); + 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 ) + if( trace.flFraction < 1.0 ) UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); } -void CGargantua :: FlameCreate( void ) +void CGargantua::FlameCreate( void ) { - int i; - Vector posGun, angleGun; + int i; + Vector posGun, angleGun; TraceResult trace; UTIL_MakeVectors( pev->angles ); - - for ( i = 0; i < 4; i++ ) + + for( i = 0; i < 4; i++ ) { - if ( i < 2 ) + 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] ) + if( m_pFlame[i] ) { int attach = i%2; // attachment is 0 based in GetAttachment - GetAttachment( attach+1, posGun, angleGun ); + GetAttachment( attach + 1, posGun, angleGun ); - Vector vecEnd = (gpGlobals->v_forward * GARG_FLAME_LENGTH) + posGun; + 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 ) + if( i < 2 ) m_pFlame[i]->SetColor( 255, 130, 90 ); else m_pFlame[i]->SetColor( 0, 120, 255 ); @@ -514,20 +513,20 @@ void CGargantua :: FlameCreate( void ) 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 ); + 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 ) +void CGargantua::FlameControls( float angleX, float angleY ) { - if ( angleY < -180 ) + if( angleY < -180 ) angleY += 360; - else if ( angleY > 180 ) + else if( angleY > 180 ) angleY -= 360; - if ( angleY < -45 ) + if( angleY < -45 ) angleY = -45; - else if ( angleY > 45 ) + else if( angleY > 45 ) angleY = 45; m_flameX = UTIL_ApproachAngle( angleX, m_flameX, 4 ); @@ -536,17 +535,17 @@ void CGargantua :: FlameControls( float angleX, float angleY ) SetBoneController( 1, m_flameX ); } -void CGargantua :: FlameUpdate( void ) +void CGargantua::FlameUpdate( void ) { - int i; + int i; static float offset[2] = { 60, -60 }; - TraceResult trace; - Vector vecStart, angleGun; - BOOL streaks = FALSE; + TraceResult trace; + Vector vecStart, angleGun; + BOOL streaks = FALSE; - for ( i = 0; i < 2; i++ ) + for( i = 0; i < 2; i++ ) { - if ( m_pFlame[i] ) + if( m_pFlame[i] ) { Vector vecAim = pev->angles; vecAim.x += m_flameX; @@ -554,19 +553,19 @@ void CGargantua :: FlameUpdate( void ) UTIL_MakeVectors( vecAim ); - GetAttachment( i+1, vecStart, angleGun ); - Vector vecEnd = vecStart + (gpGlobals->v_forward * GARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right; + 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) ); + m_pFlame[i+2]->SetStartPos( ( vecStart * 0.6 ) + ( trace.vecEndPos * 0.4 ) ); - if ( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime ) + 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) ); + UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG( 0, 2 ) ); } // RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); @@ -574,7 +573,7 @@ void CGargantua :: FlameUpdate( void ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 * (i + 2) ); // entity, attachment + WRITE_SHORT( entindex() + 0x1000 * ( i + 2 ) ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); @@ -587,56 +586,57 @@ void CGargantua :: FlameUpdate( void ) MESSAGE_END(); } } - if ( streaks ) + 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 ) +void CGargantua::FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { - CBaseEntity *pEntity = NULL; + CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage; Vector vecSpot; - Vector vecMid = (vecStart + vecEnd) * 0.5; + Vector vecMid = ( vecStart + vecEnd ) * 0.5; - float searchRadius = (vecStart - vecMid).Length(); + float searchRadius = ( vecStart - vecMid).Length(); - Vector vecAim = (vecEnd - vecStart).Normalize( ); + Vector vecAim = ( vecEnd - vecStart ).Normalize(); // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius )) != NULL) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius ) ) != NULL ) { - if ( pEntity->pev->takedamage != DAMAGE_NO ) + 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 + 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) + if( dist > searchRadius ) dist = searchRadius; - else if (dist < -searchRadius) + else if( dist < -searchRadius ) dist = searchRadius; - + Vector vecSrc = vecMid + dist * vecAim; - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); + UTIL_TraceLine( vecSrc, vecSpot, dont_ignore_monsters, ENT( pev ), &tr ); - if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) + 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) + if( dist > 64 ) { - flAdjustedDamage = flDamage - (dist - 64) * 0.4; - if (flAdjustedDamage <= 0) + flAdjustedDamage = flDamage - ( dist - 64 ) * 0.4; + if( flAdjustedDamage <= 0 ) continue; } else @@ -645,29 +645,29 @@ void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevIn } // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) + if( tr.flFraction != 1.0 ) { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); + ClearMultiDamage(); + pEntity->TraceAttack( pevInflictor, flAdjustedDamage, ( tr.vecEndPos - vecSrc ).Normalize(), &tr, bitsDamageType ); ApplyMultiDamage( pevInflictor, pevAttacker ); } else { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); + pEntity->TakeDamage( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); } } } } } -void CGargantua :: FlameDestroy( void ) +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++ ) + 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] ) + if( m_pFlame[i] ) { UTIL_Remove( m_pFlame[i] ); m_pFlame[i] = NULL; @@ -675,16 +675,16 @@ void CGargantua :: FlameDestroy( void ) } } -void CGargantua :: PrescheduleThink( void ) +void CGargantua::PrescheduleThink( void ) { - if ( !HasConditions( bits_COND_SEE_ENEMY ) ) + if( !HasConditions( bits_COND_SEE_ENEMY ) ) { m_seeTime = gpGlobals->time + 5; EyeOff(); } else EyeOn( 200 ); - + EyeUpdate(); } @@ -692,16 +692,16 @@ void CGargantua :: PrescheduleThink( void ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CGargantua :: Classify ( void ) +int CGargantua::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CGargantua :: SetYawSpeed ( void ) +void CGargantua::SetYawSpeed( void ) { int ys; @@ -729,17 +729,17 @@ void CGargantua :: SetYawSpeed ( void ) //========================================================= // Spawn //========================================================= -void CGargantua :: Spawn() +void CGargantua::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/garg.mdl"); + SET_MODEL( ENT( pev ), "models/garg.mdl" ); UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.gargantuaHealth; + 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; @@ -757,11 +757,11 @@ void CGargantua :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CGargantua :: Precache() +void CGargantua::Precache() { int i; - PRECACHE_MODEL("models/garg.mdl"); + PRECACHE_MODEL( "models/garg.mdl" ); PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME ); PRECACHE_MODEL( GARG_BEAM_SPRITE2 ); @@ -769,70 +769,70 @@ void CGargantua :: Precache() 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( pAttackHitSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pBeamAttackSounds[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( pAttackMissSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) - PRECACHE_SOUND((char *)pRicSounds[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( pFootSounds ); i++ ) + PRECACHE_SOUND( (char *)pFootSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); + for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) + PRECACHE_SOUND( (char *)pIdleSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); 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( pPainSounds ); i++ ) + PRECACHE_SOUND( (char *)pPainSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[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( pStompSounds ); i++ ) + PRECACHE_SOUND( (char *)pStompSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) - PRECACHE_SOUND((char *)pBreatheSounds[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"); + ALERT( at_aiconsole, "CGargantua::TraceAttack\n" ); - if ( !IsAlive() ) + if( !IsAlive() ) { CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); return; } // UNDONE: Hit group specific damage? - if ( bitsDamageType & (GARG_DAMAGE|DMG_BLAST) ) + if( bitsDamageType & ( GARG_DAMAGE | DMG_BLAST ) ) { - if ( m_painSoundTime < gpGlobals->time ) + 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 ); + 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( bitsDamageType == 0 ) { - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) ) + if( pev->dmgtime != gpGlobals->time || (RANDOM_LONG( 0, 100 ) < 20 ) ) { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); + 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 ); + //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; } @@ -842,13 +842,13 @@ void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - ALERT( at_aiconsole, "CGargantua::TakeDamage\n"); + ALERT( at_aiconsole, "CGargantua::TakeDamage\n" ); - if ( IsAlive() ) + if( IsAlive() ) { - if ( !(bitsDamageType & GARG_DAMAGE) ) + if( !( bitsDamageType & GARG_DAMAGE ) ) flDamage *= 0.01; - if ( bitsDamageType & DMG_BLAST ) + if( bitsDamageType & DMG_BLAST ) SetConditions( bits_COND_LIGHT_DAMAGE ); } @@ -858,17 +858,17 @@ int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo void CGargantua::DeathEffect( void ) { int i; - UTIL_MakeVectors(pev->angles); + 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 ); + 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 ) + for( i = 0; i < 7; i+=2 ) { - SpawnExplosion( position, 70, (i * 0.3), 60 + (i*20) ); + SpawnExplosion( position, 70, ( i * 0.3 ), 60 + ( i * 20 ) ); position.z += 15; } @@ -894,11 +894,11 @@ void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) //========================================================= BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) { -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); + //ALERT( at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist ); - if (flDot >= 0.7) + if( flDot >= 0.7 ) { - if (flDist <= GARG_ATTACKDIST) + if( flDist <= GARG_ATTACKDIST ) return TRUE; } return FALSE; @@ -907,11 +907,11 @@ BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) // Flame thrower madness! BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) { -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); + //ALERT( at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist ); - if ( gpGlobals->time > m_flameTime ) + if( gpGlobals->time > m_flameTime ) { - if (flDot >= 0.8 && flDist > GARG_ATTACKDIST) + if( flDot >= 0.8 && flDist > GARG_ATTACKDIST ) { if ( flDist <= GARG_FLAME_LENGTH ) return TRUE; @@ -931,9 +931,9 @@ BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) //========================================================= BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) { - if ( gpGlobals->time > m_seeTime ) + if( gpGlobals->time > m_seeTime ) { - if (flDot >= 0.7 && flDist > GARG_ATTACKDIST) + if( flDot >= 0.7 && flDist > GARG_ATTACKDIST ) { return TRUE; } @@ -945,7 +945,7 @@ BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) +void CGargantua::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -953,43 +953,39 @@ void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) { // HACKHACK!!! CBaseEntity *pHurt = GargantuaCheckTraceHullAttack( GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH ); - if (pHurt) + if( pHurt ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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 + //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) ); + 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) ); + 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) ); + 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) ); + 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); + CBaseMonster::HandleAnimEvent( pEvent ); break; } } @@ -1012,15 +1008,15 @@ CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage UTIL_MakeVectors( pev->angles ); Vector vecStart = pev->origin; vecStart.z += 64; - Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3); + 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 ) + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); + + if( tr.pHit ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if ( iDamage > 0 ) + if( iDamage > 0 ) { pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); } @@ -1034,7 +1030,7 @@ CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage Schedule_t *CGargantua::GetScheduleOfType( int Type ) { // HACKHACK - turn off the flames if they are on and garg goes scripted / dead - if ( FlameIsOn() ) + if( FlameIsOn() ) FlameDestroy(); switch( Type ) @@ -1051,7 +1047,7 @@ Schedule_t *CGargantua::GetScheduleOfType( int Type ) void CGargantua::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_FLAME_SWEEP: FlameCreate(); @@ -1060,13 +1056,11 @@ void CGargantua::StartTask( Task_t *pTask ) 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 ); + 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(); @@ -1082,10 +1076,10 @@ void CGargantua::StartTask( Task_t *pTask ) //========================================================= void CGargantua::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_DIE: - if ( gpGlobals->time > m_flWaitFinished ) + if( gpGlobals->time > m_flWaitFinished ) { pev->renderfx = kRenderFxExplode; pev->rendercolor.x = 255; @@ -1096,15 +1090,15 @@ void CGargantua::RunTask( Task_t *pTask ) SetThink( &CBaseEntity::SUB_Remove ); int i; int parts = MODEL_FRAMES( gGargGibModel ); - for ( i = 0; i < 10; i++ ) + 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 ); + if( parts > 1 ) + bodyPart = RANDOM_LONG( 0, pev->body - 1 ); pGib->pev->body = bodyPart; pGib->m_bloodColor = BLOOD_COLOR_YELLOW; @@ -1115,7 +1109,7 @@ void CGargantua::RunTask( Task_t *pTask ) pGib->SetThink( &CBaseEntity::SUB_FadeOut ); } MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BREAKMODEL); + WRITE_BYTE( TE_BREAKMODEL ); // position WRITE_COORD( pev->origin.x ); @@ -1152,10 +1146,10 @@ void CGargantua::RunTask( Task_t *pTask ) return; } else - CBaseMonster::RunTask(pTask); + CBaseMonster::RunTask( pTask ); break; case TASK_FLAME_SWEEP: - if ( gpGlobals->time > m_flWaitFinished ) + if( gpGlobals->time > m_flWaitFinished ) { FlameDestroy(); TaskComplete(); @@ -1171,26 +1165,26 @@ void CGargantua::RunTask( Task_t *pTask ) FlameUpdate(); CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy ) + if( pEnemy ) { Vector org = pev->origin; org.z += 64; - Vector dir = pEnemy->BodyTarget(org) - org; + Vector dir = pEnemy->BodyTarget( org ) - org; angles = UTIL_VecToAngles( dir ); angles.x = -angles.x; angles.y -= pev->angles.y; - if ( dir.Length() > 400 ) + if( dir.Length() > 400 ) cancel = TRUE; } - if ( fabs(angles.y) > 60 ) + if( fabs(angles.y) > 60 ) cancel = TRUE; - - if ( cancel ) + + 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 + 2 * sin( gpGlobals->time * 8 ), angles.y + 28 * sin( gpGlobals->time * 8.5 ) ); FlameControls( angles.x, angles.y ); } break; @@ -1224,17 +1218,17 @@ 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.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 + 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); + if( pev->health > 0 ) + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.2 ); else UTIL_Remove( this ); } @@ -1244,14 +1238,14 @@ void CSpiral::Spawn( void ) pev->movetype = MOVETYPE_NONE; pev->nextthink = gpGlobals->time; pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); + 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 ) + if( duration <= 0 ) return NULL; CSpiral *pSpiral = GetClassPtr( (CSpiral *)NULL ); @@ -1273,22 +1267,22 @@ void CSpiral::Think( void ) { float time = gpGlobals->time - pev->dmgtime; - while ( time > SPIRAL_INTERVAL ) + 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; + float radius = ( pev->scale * pev->health ) * fraction; - position.z += (pev->health * pev->dmg) * fraction; - pev->angles.y = (pev->health * 360 * 8) * 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(); + direction = ( direction + gpGlobals->v_forward ).Normalize(); - StreakSplash( position, Vector(0,0,1), RANDOM_LONG(8,11), 20, RANDOM_LONG(50,150), 400 ); + 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; @@ -1298,7 +1292,7 @@ void CSpiral::Think( void ) pev->nextthink = gpGlobals->time; - if ( pev->health >= pev->speed ) + if( pev->health >= pev->speed ) UTIL_Remove( this ); } @@ -1306,7 +1300,7 @@ void CSpiral::Think( void ) void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) { KeyValueData kvd; - char buf[128]; + char buf[128]; center.x += RANDOM_FLOAT( -randomRange, randomRange ); center.y += RANDOM_FLOAT( -randomRange, randomRange ); diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 0e4370b4..46415182 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -28,7 +28,8 @@ #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 { +enum gauss_e +{ GAUSS_IDLE = 0, GAUSS_IDLE2, GAUSS_FIDGET, @@ -45,9 +46,9 @@ LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ) float CGauss::GetFullChargeTime( void ) { #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { return 1.5; @@ -60,11 +61,11 @@ float CGauss::GetFullChargeTime( void ) extern int g_irunninggausspred; #endif -void CGauss::Spawn( ) +void CGauss::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_GAUSS; - SET_MODEL(ENT(pev), "models/w_gauss.mdl"); + SET_MODEL( ENT( pev ), "models/w_gauss.mdl" ); m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; @@ -73,18 +74,18 @@ void CGauss::Spawn( ) void CGauss::Precache( void ) { - PRECACHE_MODEL("models/w_gauss.mdl"); - PRECACHE_MODEL("models/v_gauss.mdl"); - PRECACHE_MODEL("models/p_gauss.mdl"); + 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( "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" ); - 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" ); @@ -95,7 +96,7 @@ void CGauss::Precache( void ) int CGauss::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -105,9 +106,9 @@ int CGauss::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -int CGauss::GetItemInfo(ItemInfo *p) +int CGauss::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "uranium"; p->iMaxAmmo1 = URANIUM_MAX_CARRY; p->pszAmmo2 = NULL; @@ -122,7 +123,7 @@ int CGauss::GetItemInfo(ItemInfo *p) return 1; } -BOOL CGauss::Deploy( ) +BOOL CGauss::Deploy() { m_pPlayer->m_flPlayAftershock = 0.0; return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); @@ -131,9 +132,9 @@ BOOL CGauss::Deploy( ) 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; } @@ -141,16 +142,16 @@ void CGauss::Holster( int skiplocal /* = 0 */ ) void CGauss::PrimaryAttack() { // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) + if( m_pPlayer->pev->waterlevel == 3 ) { - PlayEmptySound( ); + PlayEmptySound(); m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 2 ) { - PlayEmptySound( ); + PlayEmptySound(); m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; return; } @@ -169,28 +170,28 @@ void CGauss::PrimaryAttack() void CGauss::SecondaryAttack() { // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) + if( m_pPlayer->pev->waterlevel == 3 ) { - if ( m_fInAttack != 0 ) + 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)); + 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( ); + PlayEmptySound(); } m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; return; } - if ( m_fInAttack == 0 ) + if( m_fInAttack == 0 ) { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 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); + 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; } @@ -202,7 +203,7 @@ void CGauss::SecondaryAttack() // spin up m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - + SendWeaponAnim( GAUSS_SPINUP ); m_fInAttack = 1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; @@ -213,9 +214,9 @@ void CGauss::SecondaryAttack() m_iSoundState = SND_CHANGE_PITCH; } - else if (m_fInAttack == 1) + else if( m_fInAttack == 1 ) { - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) + if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { SendWeaponAnim( GAUSS_SPIN ); m_fInAttack = 2; @@ -224,12 +225,12 @@ void CGauss::SecondaryAttack() 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 ) + if( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) { #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; @@ -242,7 +243,7 @@ void CGauss::SecondaryAttack() } } - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) { // out of ammo! force the gun to fire StartFire(); @@ -251,20 +252,20 @@ void CGauss::SecondaryAttack() m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; return; } - - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) + + 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 = ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; - if ( pitch > 250 ) + if( pitch > 250 ) pitch = 250; // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); - if ( m_iSoundState == 0 ) + 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 ); @@ -272,24 +273,23 @@ void CGauss::SecondaryAttack() 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 ) + 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)); - + 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 ); + 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; } @@ -305,21 +305,21 @@ void CGauss::SecondaryAttack() 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() ) + 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() ); + flDamage = 200 * ( ( gpGlobals->time - m_pPlayer->m_flStartCharge ) / GetFullChargeTime() ); } - if ( m_fPrimaryFire ) + if( m_fPrimaryFire ) { // fixed damage on primary attack #ifdef CLIENT_DLL @@ -329,18 +329,18 @@ void CGauss::StartFire( void ) #endif } - if (m_fInAttack != 3) + if( m_fInAttack != 3 ) { - //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); + //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 ) + if( !m_fPrimaryFire ) { m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; } - if ( !g_pGameRules->IsMultiplayer() ) + if( !g_pGameRules->IsMultiplayer() ) { // in deathmatch, gauss can pop you up into the air. Not in single play. m_pPlayer->pev->velocity.z = flZVel; @@ -362,18 +362,18 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) Vector vecSrc = vecOrigSrc; Vector vecDest = vecSrc + vecDir * 8192; - edict_t *pentIgnore; + edict_t *pentIgnore; TraceResult tr, beam_tr; float flMaxFrac = 1.0; - int nTotal = 0; + int nTotal = 0; int fHasPunched = 0; int fFirstBeam = 1; - int nMaxHits = 10; + int nMaxHits = 10; pentIgnore = ENT( m_pPlayer->pev ); #ifdef CLIENT_DLL - if ( m_fPrimaryFire == false ) + if( m_fPrimaryFire == false ) g_irunninggausspred = true; #endif // The main firing event is sent unreliably so it won't be delayed. @@ -385,7 +385,6 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) 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 );*/ @@ -393,50 +392,50 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) //ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); #ifndef CLIENT_DLL - while (flDamage > 10 && nMaxHits > 0) + while( flDamage > 10 && nMaxHits > 0 ) { nMaxHits--; // ALERT( at_console, "." ); - UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); + UTIL_TraceLine( vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - if (tr.fAllSolid) + if( tr.fAllSolid ) break; - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if (pEntity == NULL) + if( pEntity == NULL ) break; - if ( fFirstBeam ) + if( fFirstBeam ) { m_pPlayer->pev->effects |= EF_MUZZLEFLASH; fFirstBeam = 0; - + nTotal += 26; } - - if (pEntity->pev->takedamage) + + if( pEntity->pev->takedamage ) { ClearMultiDamage(); pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); } - if ( pEntity->ReflectGauss() ) + if( pEntity->ReflectGauss() ) { float n; pentIgnore = NULL; - n = -DotProduct(tr.vecPlaneNormal, vecDir); + n = -DotProduct( tr.vecPlaneNormal, vecDir ); - if (n < 0.5) // 60 degrees + 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; @@ -447,34 +446,35 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) 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); + if( n == 0 ) n = 0.1; + flDamage = flDamage * ( 1 - n ); } else { nTotal += 13; // limit it to one hole punch - if (fHasPunched) + if( fHasPunched ) break; fHasPunched = 1; // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) + if( !m_fPrimaryFire ) { - UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr); - if (!beam_tr.fAllSolid) + 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); + 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 < flDamage ) { - if (n == 0) n = 1; + if( n == 0 ) + n = 1; flDamage -= n; // ALERT( at_console, "punch %f\n", n ); @@ -483,9 +483,8 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // 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() ) + if( g_pGameRules->IsMultiplayer() ) { damage_radius = flDamage * 1.75; // Old code == 2.5 } @@ -496,7 +495,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) ::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 ); + CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); nTotal += 53; @@ -512,7 +511,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) else { //ALERT( at_console, "blocked solid\n" ); - + flDamage = 0; } @@ -530,25 +529,32 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) void CGauss::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); // play aftershock static discharge - if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) + if( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) { - switch (RANDOM_LONG(0,3)) + 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 + 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()) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if (m_fInAttack != 0) + if( m_fInAttack != 0 ) { StartFire(); m_fInAttack = 0; @@ -557,13 +563,13 @@ void CGauss::WeaponIdle( void ) else { int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.5) + 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) + else if( flRand <= 0.75 ) { iAnim = GAUSS_IDLE2; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); @@ -574,7 +580,6 @@ void CGauss::WeaponIdle( void ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } SendWeaponAnim( iAnim ); - } } @@ -582,20 +587,20 @@ class CGaussAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_gaussammo.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + 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) + if( pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1 ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 482533a5..c40bb802 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -34,9 +34,9 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); + int ISoundMask( void ); }; LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ) @@ -45,20 +45,20 @@ LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CGenericMonster :: Classify ( void ) +int CGenericMonster::Classify( void ) { - return CLASS_PLAYER_ALLY; + return CLASS_PLAYER_ALLY; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CGenericMonster :: SetYawSpeed ( void ) +void CGenericMonster::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: default: @@ -72,7 +72,7 @@ void CGenericMonster :: SetYawSpeed ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CGenericMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CGenericMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -86,42 +86,40 @@ void CGenericMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // ISoundMask - generic monster can't hear. //========================================================= -int CGenericMonster :: ISoundMask ( void ) +int CGenericMonster::ISoundMask( void ) { - return NULL; + return NULL; } //========================================================= // Spawn //========================================================= -void CGenericMonster :: Spawn() +void CGenericMonster::Spawn() { Precache(); - SET_MODEL( ENT(pev), STRING(pev->model) ); - + 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); + 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); + 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); + 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); + 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; + 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 ) + if( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) { pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; @@ -131,10 +129,10 @@ void CGenericMonster :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CGenericMonster :: Precache() +void CGenericMonster::Precache() { - PRECACHE_MODEL( (char *)STRING(pev->model) ); -} + PRECACHE_MODEL( (char *)STRING( pev->model ) ); +} //========================================================= // AI Schedules Specific to this monster diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 476658c6..64d9f3cf 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -27,7 +27,6 @@ #include "soundent.h" #include "decals.h" - //===================grenade @@ -42,7 +41,7 @@ LINK_ENTITY_TO_CLASS( grenade, CGrenade ) void CGrenade::Explode( Vector vecSrc, Vector vecAim ) { TraceResult tr; - UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr); + UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -32 ), ignore_monsters, ENT( pev ), & tr ); Explode( &tr, DMG_BLAST ); } @@ -50,7 +49,7 @@ void CGrenade::Explode( Vector vecSrc, Vector vecAim ) // UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) { - float flRndSound;// sound randomizer + float flRndSound;// sound randomizer pev->model = iStringNull;//invisible pev->solid = SOLID_NOT;// intangible @@ -58,19 +57,19 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) pev->takedamage = DAMAGE_NO; // Pull out of the wall a bit - if ( pTrace->flFraction != 1.0 ) + if( pTrace->flFraction != 1.0 ) { - pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6); + pev->origin = pTrace->vecEndPos + ( pTrace->vecPlaneNormal * ( pev->dmg - 24 ) * 0.6 ); } - int iContents = UTIL_PointContents ( pev->origin ); - + 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) + if( iContents != CONTENTS_WATER ) { WRITE_SHORT( g_sModelIndexFireball ); } @@ -78,23 +77,23 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) { WRITE_SHORT( g_sModelIndexWExplosion ); } - WRITE_BYTE( (pev->dmg - 50) * .60 ); // scale * 10 - WRITE_BYTE( 15 ); // framerate + WRITE_BYTE( ( 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 ); + CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); entvars_t *pevOwner; - if ( pev->owner ) + 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 ); + RadiusDamage( pev, pevOwner, pev->dmg, CLASS_NONE, bitsDamageType ); - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) + if( RANDOM_FLOAT( 0, 1 ) < 0.5 ) { UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); } @@ -103,13 +102,19 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); } - flRndSound = RANDOM_FLOAT( 0 , 1 ); + flRndSound = RANDOM_FLOAT( 0, 1 ); - switch ( RANDOM_LONG( 0, 2 ) ) + 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; + 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; @@ -117,17 +122,17 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) pev->velocity = g_vecZero; pev->nextthink = gpGlobals->time + 0.3; - if (iContents != CONTENTS_WATER) + if( iContents != CONTENTS_WATER ) { - int sparkCount = RANDOM_LONG(0,3); - for ( int i = 0; i < sparkCount; i++ ) + 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) + if( UTIL_PointContents( pev->origin ) == CONTENTS_WATER ) { UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 ); } @@ -139,7 +144,7 @@ void CGrenade::Smoke( void ) WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10 + WRITE_BYTE( ( pev->dmg - 50 ) * 0.80 ); // scale * 10 WRITE_BYTE( 12 ); // framerate MESSAGE_END(); } @@ -148,7 +153,7 @@ void CGrenade::Smoke( void ) void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) { - Detonate( ); + Detonate(); } // Timed grenade, this think is called when time runs out. @@ -169,10 +174,10 @@ void CGrenade::PreDetonate( void ) void CGrenade::Detonate( void ) { TraceResult tr; - Vector vecSpot;// trace starts here! + 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); + vecSpot = pev->origin + Vector( 0, 0, 8 ); + UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -40 ), ignore_monsters, ENT(pev), &tr ); Explode( &tr, DMG_BLAST ); } @@ -184,28 +189,28 @@ void CGrenade::Detonate( void ) void CGrenade::ExplodeTouch( CBaseEntity *pOther ) { TraceResult tr; - Vector vecSpot;// trace starts here! + 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 ); + UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT( pev ), &tr ); Explode( &tr, DMG_BLAST ); } void CGrenade::DangerSoundThink( void ) { - if (!IsInWorld()) + if( !IsInWorld() ) { UTIL_Remove( this ); return; } - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 ); + CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length(), 0.2 ); pev->nextthink = gpGlobals->time + 0.2; - if (pev->waterlevel != 0) + if( pev->waterlevel != 0 ) { pev->velocity = pev->velocity * 0.5; } @@ -214,25 +219,25 @@ void CGrenade::DangerSoundThink( void ) void CGrenade::BounceTouch( CBaseEntity *pOther ) { // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) + if( pOther->edict() == pev->owner ) return; // only do damage if we're moving fairly fast - if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) + if( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100 ) { entvars_t *pevOwner = VARS( pev->owner ); - if (pevOwner) + if( pevOwner ) { - TraceResult tr = UTIL_GetGlobalTrace( ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB ); - ApplyMultiDamage( pev, 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); + // 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. @@ -240,19 +245,19 @@ void CGrenade::BounceTouch( CBaseEntity *pOther ) vecTestVelocity = pev->velocity; vecTestVelocity.z *= 0.45; - if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) + 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, pev->dmg / 0.4, 0.3 ); + CSoundEnt::InsertSound( bits_SOUND_DANGER, pev->origin, pev->dmg / 0.4, 0.3 ); m_fRegisteredSound = TRUE; } - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { // add a bit of static friction pev->velocity = pev->velocity * 0.8; @@ -265,27 +270,25 @@ void CGrenade::BounceTouch( CBaseEntity *pOther ) BounceSound(); } pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) + if( pev->framerate > 1.0 ) pev->framerate = 1; - else if (pev->framerate < 0.5) + 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 ) + if( pOther->edict() == pev->owner ) return; - // pev->avelocity = Vector (300, 300, 300); - - if (pev->flags & FL_ONGROUND) + // 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) + if( pev->velocity.x != 0 || pev->velocity.y != 0 ) { // maintain sliding sound } @@ -296,52 +299,58 @@ void CGrenade::SlideTouch( CBaseEntity *pOther ) } } -void CGrenade :: BounceSound( void ) +void CGrenade::BounceSound( void ) { - switch ( RANDOM_LONG( 0, 2 ) ) + 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; + 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 ) +void CGrenade::TumbleThink( void ) { - if (!IsInWorld()) + if( !IsInWorld() ) { UTIL_Remove( this ); return; } - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if (pev->dmgtime - 1 < gpGlobals->time) + if( pev->dmgtime - 1 < gpGlobals->time ) { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); + CSoundEnt::InsertSound( bits_SOUND_DANGER, pev->origin + pev->velocity * ( pev->dmgtime - gpGlobals->time ), 400, 0.1 ); } - if (pev->dmgtime <= gpGlobals->time) + if( pev->dmgtime <= gpGlobals->time ) { SetThink( &CGrenade::Detonate ); } - if (pev->waterlevel != 0) + if( pev->waterlevel != 0 ) { pev->velocity = pev->velocity * 0.5; pev->framerate = 0.2; } } -void CGrenade:: Spawn( void ) +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)); + SET_MODEL( ENT( pev ), "models/grenade.mdl" ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); pev->dmg = 100; m_fRegisteredSound = FALSE; @@ -355,16 +364,16 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v 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); - + 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 ); - + pGrenade->pev->avelocity.x = RANDOM_FLOAT( -100, -500 ); + // Explode on contact pGrenade->SetTouch( &CGrenade::ExplodeTouch ); @@ -373,17 +382,17 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v return pGrenade; } -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) +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->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(). @@ -391,12 +400,12 @@ CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->dmgtime = gpGlobals->time + time; pGrenade->SetThink( &CGrenade::TumbleThink ); pGrenade->pev->nextthink = gpGlobals->time + 0.1; - if (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; @@ -406,30 +415,30 @@ CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector v pGrenade->pev->gravity = 0.5; pGrenade->pev->friction = 0.8; - SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); + 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 *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 + 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)); + 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); - + pGrenade->pev->owner = ENT( pevOwner ); + // Detonate in "time" seconds pGrenade->SetThink( &CBaseEntity::SUB_DoNothing ); pGrenade->SetUse( &CGrenade::DetonateUse ); @@ -441,29 +450,29 @@ CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, return pGrenade; } -void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) +void CGrenade::UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) { edict_t *pentFind; edict_t *pentOwner; - if ( !pevOwner ) + if( !pevOwner ) return; - CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); + CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); pentOwner = pOwner->edict(); pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" ); - while ( !FNullEnt( pentFind ) ) + while( !FNullEnt( pentFind ) ) { CBaseEntity *pEnt = Instance( pentFind ); - if ( pEnt ) + if( pEnt ) { - if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) + if( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) { - if ( code == SATCHEL_DETONATE ) + if( code == SATCHEL_DETONATE ) pEnt->Use( pOwner, pOwner, USE_ON, 0 ); - else // SATCHEL_RELEASE + else // SATCHEL_RELEASE pEnt->pev->owner = NULL; } } diff --git a/dlls/globals.cpp b/dlls/globals.cpp index ef657c2d..28280887 100644 --- a/dlls/globals.cpp +++ b/dlls/globals.cpp @@ -35,5 +35,5 @@ 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 const Vector g_vecZero = Vector( 0, 0, 0 ); DLL_GLOBAL int g_Language; diff --git a/dlls/glock.cpp b/dlls/glock.cpp index fb390d13..1f4517e7 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -21,7 +21,8 @@ #include "nodes.h" #include "player.h" -enum glock_e { +enum glock_e +{ GLOCK_IDLE1 = 0, GLOCK_IDLE2, GLOCK_IDLE3, @@ -37,12 +38,12 @@ enum glock_e { LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ) LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ) -void CGlock::Spawn( ) +void CGlock::Spawn() { - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); + 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"); + SET_MODEL( ENT( pev ), "models/w_9mmhandgun.mdl" ); m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; @@ -51,26 +52,26 @@ void CGlock::Spawn( ) void CGlock::Precache( void ) { - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); + 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 + m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); + 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 + 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) +int CGlock::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "9mm"; p->iMaxAmmo1 = _9MM_MAX_CARRY; p->pszAmmo2 = NULL; @@ -85,7 +86,7 @@ int CGlock::GetItemInfo(ItemInfo *p) return 1; } -BOOL CGlock::Deploy( ) +BOOL CGlock::Deploy() { // pev->body = 1; return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); @@ -101,11 +102,11 @@ void CGlock::PrimaryAttack( void ) GlockFire( 0.01, 0.3, TRUE ); } -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) +void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ) { - if (m_iClip <= 0) + if( m_iClip <= 0 ) { - if (m_fFireOnEmpty) + if( m_fFireOnEmpty ) { PlayEmptySound(); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; @@ -116,7 +117,7 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; int flags; #if defined( CLIENT_WEAPONS ) @@ -128,7 +129,7 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); // silenced - if (pev->body == 1) + if( pev->body == 1 ) { m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; @@ -140,10 +141,10 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; } - Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming; - - if ( fUseAutoAim ) + + if( fUseAutoAim ) { vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); } @@ -159,26 +160,26 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 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_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 ) + if( m_pPlayer->ammo_9mm <= 0 ) return; int iResult; - if (m_iClip == 0) + if( m_iClip == 0 ) iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); else iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - if (iResult) + if( iResult ) { m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -186,25 +187,25 @@ void CGlock::Reload( void ) void CGlock::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; // only idle if the slid isn't back - if (m_iClip != 0) + 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) + 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) + else if( flRand <= 0.6 + 0 * 0.875 ) { iAnim = GLOCK_IDLE1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; @@ -222,25 +223,27 @@ class CGlockAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + 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) + + 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); + 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/dlls/gman.cpp b/dlls/gman.cpp index 771b86a3..bdfb60d4 100644 --- a/dlls/gman.cpp +++ b/dlls/gman.cpp @@ -32,17 +32,17 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify ( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); int ISoundMask ( void ); - int Save( CSave &save ); + 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 ); + 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 ); @@ -54,7 +54,7 @@ public: LINK_ENTITY_TO_CLASS( monster_gman, CGMan ) -TYPEDESCRIPTION CGMan::m_SaveData[] = +TYPEDESCRIPTION CGMan::m_SaveData[] = { DEFINE_FIELD( CGMan, m_hTalkTarget, FIELD_EHANDLE ), DEFINE_FIELD( CGMan, m_flTalkTime, FIELD_TIME ), @@ -66,20 +66,20 @@ IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CGMan :: Classify ( void ) +int CGMan::Classify( void ) { - return CLASS_NONE; + return CLASS_NONE; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CGMan :: SetYawSpeed ( void ) +void CGMan::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: default: @@ -93,7 +93,7 @@ void CGMan :: SetYawSpeed ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CGMan :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CGMan::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -107,25 +107,25 @@ void CGMan :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // ISoundMask - generic monster can't hear. //========================================================= -int CGMan :: ISoundMask ( void ) +int CGMan::ISoundMask( void ) { - return NULL; + return NULL; } //========================================================= // Spawn //========================================================= -void CGMan :: Spawn() +void CGMan::Spawn() { Precache(); - SET_MODEL( ENT(pev), "models/gman.mdl" ); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + SET_MODEL( ENT( pev ), "models/gman.mdl" ); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = DONT_BLEED; - pev->health = 100; + 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; @@ -135,21 +135,21 @@ void CGMan :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CGMan :: Precache() +void CGMan::Precache() { PRECACHE_MODEL( "models/gman.mdl" ); -} +} //========================================================= // AI Schedules Specific to this monster //========================================================= -void CGMan :: StartTask( Task_t *pTask ) +void CGMan::StartTask( Task_t *pTask ) { switch( pTask->iTask ) { case TASK_WAIT: - if (m_hPlayer == NULL) + if( m_hPlayer == NULL ) { m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); } @@ -158,29 +158,33 @@ void CGMan :: StartTask( Task_t *pTask ) CBaseMonster::StartTask( pTask ); } -void CGMan :: RunTask( Task_t *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 != NULL) + if( m_flTalkTime > gpGlobals->time && m_hTalkTarget != NULL ) { - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; + float yaw = VecToYaw( m_hTalkTarget->pev->origin - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; + 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 != NULL && pev->sequence == 0) + else if( m_hPlayer != NULL && pev->sequence == 0 ) { - float yaw = VecToYaw(m_hPlayer->pev->origin - pev->origin) - pev->angles.y; + float yaw = VecToYaw( m_hPlayer->pev->origin - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; + if( yaw > 180 ) + yaw -= 360; + if( yaw < -180 ) + yaw += 360; // turn towards vector SetBoneController( 0, yaw ); @@ -201,18 +205,18 @@ void CGMan :: RunTask( Task_t *pTask ) //========================================================= // Override all damage //========================================================= -int CGMan :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +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 ) + if( flDamage > 0 ) { - SetConditions(bits_COND_LIGHT_DAMAGE); + SetConditions( bits_COND_LIGHT_DAMAGE ); } - if ( flDamage >= 20 ) + if( flDamage >= 20 ) { - SetConditions(bits_COND_HEAVY_DAMAGE); + SetConditions( bits_COND_HEAVY_DAMAGE ); } return TRUE; } diff --git a/dlls/h_ai.cpp b/dlls/h_ai.cpp index 73a5064a..d8a35547 100644 --- a/dlls/h_ai.cpp +++ b/dlls/h_ai.cpp @@ -18,7 +18,6 @@ */ - #include "extdll.h" #include "util.h" #include "cbase.h" @@ -28,7 +27,7 @@ #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); +//float flRandom = RANDOM_FLOAT( 0, 1 ); DLL_GLOBAL BOOL g_fDrawLines = FALSE; @@ -45,25 +44,25 @@ DLL_GLOBAL BOOL g_fDrawLines = FALSE; // // !!!UNDONE - make this CBaseMonster? //========================================================= -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize ) +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)) + 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++) + 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); + 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) + 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. @@ -76,7 +75,7 @@ BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTarget // 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 ) +Vector VecCheckToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj ) { TraceResult tr; Vector vecMidPoint;// halfway point between Spot1 and Spot2 @@ -86,52 +85,52 @@ Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, f Vector vecTemp; float flGravity = g_psv_gravity->value * flGravityAdj; - if (vecSpot2.z - vecSpot1.z > 500) + if( vecSpot2.z - vecSpot1.z > 500 ) { // to high, fail return g_vecZero; } - UTIL_MakeVectors (pev->angles); + 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) ); - + 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 = 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) + 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); + 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) ); + float time1 = sqrt( distance1 / ( 0.5 * flGravity ) ); + float time2 = sqrt( distance2 / ( 0.5 * flGravity ) ); - if (time1 < 0.1) + if( time1 < 0.1 ) { // too close return g_vecZero; } // how hard to throw sideways to get there in time. - vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); + vecGrenadeVel = ( vecSpot2 - vecSpot1 ) / ( time1 + time2 ); // how hard upwards to reach the apex at the right time. vecGrenadeVel.z = flGravity * time1; @@ -139,55 +138,54 @@ Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, f vecApex = vecSpot1 + vecGrenadeVel * time1; vecApex.z = vecMidPoint.z; - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) + 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) + 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 ) +Vector VecCheckThrow( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) { - float flGravity = g_psv_gravity->value * flGravityAdj; + float flGravity = g_psv_gravity->value * flGravityAdj; - Vector vecGrenadeVel = (vecSpot2 - vecSpot1); + Vector vecGrenadeVel = vecSpot2 - vecSpot1; // throw at a constant time - float time = vecGrenadeVel.Length( ) / flSpeed; - vecGrenadeVel = vecGrenadeVel * (1.0 / 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); - + 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) + 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) + UTIL_TraceLine( vecSpot2, vecApex, ignore_monsters, ENT( pev ), &tr ); + if( tr.flFraction != 1.0 ) { // fail! return g_vecZero; @@ -195,5 +193,3 @@ Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, return vecGrenadeVel; } - - diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 5fe36c17..fdb7c645 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -30,31 +30,31 @@ class CRecharge : public CBaseToggle { public: - void Spawn( ); + 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 ); + 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[]; + 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; + 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_iReactivate, FIELD_INTEGER ), + DEFINE_FIELD( CRecharge, m_iJuice, FIELD_INTEGER ), + DEFINE_FIELD( CRecharge, m_iOn, FIELD_INTEGER ), DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ), }; @@ -64,17 +64,17 @@ 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")) + 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")) + else if( FStrEq( pkvd->szKeyName, "dmdelay" ) ) { - m_iReactivate = atoi(pkvd->szValue); + m_iReactivate = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -83,88 +83,86 @@ void CRecharge::KeyValue( KeyValueData *pkvd ) void CRecharge::Spawn() { - Precache( ); + Precache(); - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + 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) ); + 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 = gSkillData.suitchargerCapacity; pev->frame = 0; } void CRecharge::Precache() { - PRECACHE_SOUND("items/suitcharge1.wav"); - PRECACHE_SOUND("items/suitchargeno1.wav"); - PRECACHE_SOUND("items/suitchargeok1.wav"); + 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")) + if( !FClassnameIs( pActivator->pev, "player" ) ) return; // if there is no juice left, turn it off - if (m_iJuice <= 0) + 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<pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) { - if (m_flSoundTime <= gpGlobals->time) + if( m_flSoundTime <= gpGlobals->time ) { m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM ); } return; } pev->nextthink = pev->ltime + 0.25; - SetThink( &CRecharge::Off); + SetThink( &CRecharge::Off ); // Time to recharge yet? - - if (m_flNextCharge >= gpGlobals->time) + if( m_flNextCharge >= gpGlobals->time ) return; // Make sure that we have a caller - if (!pActivator) + if( !pActivator ) return; m_hActivator = pActivator; //only recharge the player - - if (!m_hActivator->IsPlayer() ) + if( !m_hActivator->IsPlayer() ) return; // Play the on sound or the looping charging sound - if (!m_iOn) + if( !m_iOn ) { m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM ); + 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)) + if( ( m_iOn == 1 ) && ( m_flSoundTime <= gpGlobals->time ) ) { m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); } // charge the player - if (m_hActivator->pev->armorvalue < 100) + if( m_hActivator->pev->armorvalue < 100 ) { m_iJuice--; m_hActivator->pev->armorvalue += 1; - if (m_hActivator->pev->armorvalue > 100) + if( m_hActivator->pev->armorvalue > 100 ) m_hActivator->pev->armorvalue = 100; } @@ -172,25 +170,25 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use m_flNextCharge = gpGlobals->time + 0.1; } -void CRecharge::Recharge(void) +void CRecharge::Recharge( void ) { m_iJuice = gSkillData.suitchargerCapacity; - pev->frame = 0; + pev->frame = 0; SetThink( &CBaseEntity::SUB_DoNothing ); } -void CRecharge::Off(void) +void CRecharge::Off( void ) { // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); + if( m_iOn > 1 ) + STOP_SOUND( ENT( pev ), CHAN_STATIC, "items/suitcharge1.wav" ); m_iOn = 0; - if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) ) + if( ( !m_iJuice ) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0 ) ) { pev->nextthink = pev->ltime + m_iReactivate; - SetThink( &CRecharge::Recharge); + SetThink( &CRecharge::Recharge ); } else SetThink( &CBaseEntity::SUB_DoNothing ); diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index 9a79e994..d685ac36 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -35,7 +35,7 @@ class CCycler : public CBaseMonster { public: void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); } + 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 ); @@ -45,14 +45,14 @@ public: // 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - int m_animate; + int m_animate; }; -TYPEDESCRIPTION CCycler::m_SaveData[] = +TYPEDESCRIPTION CCycler::m_SaveData[] = { DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ), }; @@ -65,7 +65,10 @@ IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ) class CGenericCycler : public CCycler { public: - void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); } + void Spawn( void ) + { + GenericCyclerSpawn( (char *)STRING( pev->model ), Vector( -16, -16, 0 ), Vector( 16, 16, 72 ) ); + } }; LINK_ENTITY_TO_CLASS( cycler, CGenericCycler ) @@ -82,52 +85,51 @@ public: LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe ) -void CCyclerProbe :: Spawn( void ) +void CCyclerProbe::Spawn( void ) { - pev->origin = pev->origin + Vector ( 0, 0, 16 ); - GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16)); + 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(char *szModel, Vector vecMin, Vector vecMax) +void CCycler::GenericCyclerSpawn( char *szModel, Vector vecMin, Vector vecMax ) { - if (!szModel || !*szModel) + 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)); + 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"); + pev->classname = MAKE_STRING( "cycler" ); PRECACHE_MODEL( szModel ); - SET_MODEL(ENT(pev), szModel); + SET_MODEL( ENT( pev ), szModel ); - CCycler::Spawn( ); + CCycler::Spawn(); - UTIL_SetSize(pev, vecMin, vecMax); + UTIL_SetSize( pev, vecMin, vecMax ); } -void CCycler :: Spawn( ) +void CCycler::Spawn() { InitBoneControllers(); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_NONE; pev->takedamage = DAMAGE_YES; pev->effects = 0; - pev->health = 80000;// no cycler should die + 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( ); + ResetSequenceInfo(); - if (pev->sequence != 0 || pev->frame != 0) + if( pev->sequence != 0 || pev->frame != 0 ) { m_animate = 0; pev->framerate = 0; @@ -141,15 +143,15 @@ void CCycler :: Spawn( ) // // cycler think // -void CCycler :: Think( void ) +void CCycler::Think( void ) { pev->nextthink = gpGlobals->time + 0.1; - if (m_animate) + if( m_animate ) { - StudioFrameAdvance ( ); + StudioFrameAdvance(); } - if (m_fSequenceFinished && !m_fSequenceLoops) + if( m_fSequenceFinished && !m_fSequenceLoops ) { // ResetSequenceInfo(); // hack to avoid reloading model every frame @@ -158,7 +160,7 @@ void CCycler :: Think( void ) m_fSequenceFinished = FALSE; m_flLastEventCheck = gpGlobals->time; pev->frame = 0; - if (!m_animate) + if( !m_animate ) pev->framerate = 0.0; // FIX: don't reset framerate } } @@ -166,10 +168,10 @@ void CCycler :: Think( void ) // // CyclerUse - starts a rotation trend // -void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CCycler::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { m_animate = !m_animate; - if (m_animate) + if( m_animate ) pev->framerate = 1.0; else pev->framerate = 0.0; @@ -178,26 +180,26 @@ void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us // // CyclerPain , changes sequences when shot // -//void CCycler :: Pain( float flDamage ) -int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +//void CCycler::Pain( float flDamage ) +int CCycler::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if (m_animate) + if( m_animate ) { pev->sequence++; - ResetSequenceInfo( ); + ResetSequenceInfo(); - if (m_flFrameRate == 0.0) + if( m_flFrameRate == 0.0 ) { pev->sequence = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); } pev->frame = 0; } else { pev->framerate = 1.0; - StudioFrameAdvance ( 0.1 ); + StudioFrameAdvance( 0.1 ); pev->framerate = 0; ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame ); } @@ -212,23 +214,27 @@ 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 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[]; + 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; + 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[] = +TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = { DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ), DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ), @@ -239,40 +245,40 @@ IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ) void CCyclerSprite::Spawn( void ) { - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_NONE; pev->takedamage = DAMAGE_YES; pev->effects = 0; - pev->frame = 0; + pev->frame = 0; pev->nextthink = gpGlobals->time + 0.1; - m_animate = 1; - m_lastTime = gpGlobals->time; + m_animate = 1; + m_lastTime = gpGlobals->time; - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); + PRECACHE_MODEL( (char *)STRING( pev->model ) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; } void CCyclerSprite::Think( void ) { - if ( ShouldAnimate() ) - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); + if( ShouldAnimate() ) + Animate( pev->framerate * ( gpGlobals->time - m_lastTime ) ); - pev->nextthink = gpGlobals->time + 0.1; + 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) ); + ALERT( at_console, "Sprite: %s\n", STRING( pev->model ) ); } -int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +int CCyclerSprite::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( m_maxFrame > 1.0 ) + if( m_maxFrame > 1.0 ) { Animate( 1.0 ); } @@ -282,7 +288,7 @@ int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, void CCyclerSprite::Animate( float frames ) { pev->frame += frames; - if ( m_maxFrame > 0 ) + if( m_maxFrame > 0 ) pev->frame = fmod( pev->frame, m_maxFrame ); } @@ -303,22 +309,22 @@ public: LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ) -void CWeaponCycler::Spawn( ) +void CWeaponCycler::Spawn() { - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_NONE; - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); + 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)); + UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 16 ) ); SetTouch( &CBasePlayerItem::DefaultTouch ); } -BOOL CWeaponCycler::Deploy( ) +BOOL CWeaponCycler::Deploy() { m_pPlayer->pev->viewmodel = m_iszModel; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; @@ -334,7 +340,6 @@ void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) void CWeaponCycler::PrimaryAttack() { - SendWeaponAnim( pev->sequence ); m_flNextPrimaryAttack = gpGlobals->time + 0.3; @@ -344,14 +349,14 @@ void CWeaponCycler::SecondaryAttack( void ) { float flFrameRate, flGroundSpeed; - pev->sequence = (pev->sequence + 1) % 8; + pev->sequence = ( pev->sequence + 1 ) % 8; pev->modelindex = m_iModel; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed ); pev->modelindex = 0; - if (flFrameRate == 0.0) + if( flFrameRate == 0.0 ) { pev->sequence = 0; } @@ -364,9 +369,9 @@ void CWeaponCycler::SecondaryAttack( void ) // Flaming Wreakage class CWreckage : public CBaseMonster { - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; void Spawn( void ); void Precache( void ); @@ -375,7 +380,7 @@ class CWreckage : public CBaseMonster int m_flStartTime; }; -TYPEDESCRIPTION CWreckage::m_SaveData[] = +TYPEDESCRIPTION CWreckage::m_SaveData[] = { DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ), }; @@ -386,50 +391,50 @@ 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->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->takedamage = 0; + pev->effects = 0; - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; + pev->frame = 0; + pev->nextthink = gpGlobals->time + 0.1; - if (pev->model) + if( pev->model ) { - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); + PRECACHE_MODEL( (char *)STRING( pev->model ) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); } // pev->scale = 5.0; - m_flStartTime = gpGlobals->time; + m_flStartTime = gpGlobals->time; } -void CWreckage::Precache( ) +void CWreckage::Precache() { - if ( pev->model ) - PRECACHE_MODEL( (char *)STRING(pev->model) ); + if( pev->model ) + PRECACHE_MODEL( (char *)STRING( pev->model ) ); } void CWreckage::Think( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.2; - if (pev->dmgtime) + if( pev->dmgtime ) { - if (pev->dmgtime < gpGlobals->time) + if( pev->dmgtime < gpGlobals->time ) { UTIL_Remove( this ); return; } - else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time) + 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 ); @@ -440,7 +445,7 @@ void CWreckage::Think( void ) 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 + WRITE_BYTE( RANDOM_LONG( 0,49 ) + 50 ); // scale * 10 + WRITE_BYTE( RANDOM_LONG( 0, 3 ) + 8 ); // framerate MESSAGE_END(); } diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index 1712a70a..a3f4f35e 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -27,23 +27,20 @@ // Holds engine functionality callbacks enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; +globalvars_t *gpGlobals; server_physics_api_t g_physfuncs; #ifdef _WIN32 // Required DLL entry point -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - } + if( fdwReason == DLL_PROCESS_ATTACH ) + { + } + else if( fdwReason == DLL_PROCESS_DETACH ) + { + } return TRUE; } @@ -53,8 +50,8 @@ BOOL WINAPI DllMain( #define EXPORT2 #endif -extern "C" void DLLEXPORT EXPORT2 GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +extern "C" void DLLEXPORT EXPORT2 GiveFnptrsToDll( enginefuncs_t *pengfuncsFromEngine, globalvars_t *pGlobals ) { - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + memcpy( &g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t) ); gpGlobals = pGlobals; } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 21e366b9..063b2886 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -23,7 +23,8 @@ #define HANDGRENADE_PRIMARY_VOLUME 450 -enum handgrenade_e { +enum handgrenade_e +{ HANDGRENADE_IDLE = 0, HANDGRENADE_FIDGET, HANDGRENADE_PINPULL, @@ -36,11 +37,11 @@ enum handgrenade_e { LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ) -void CHandGrenade::Spawn( ) +void CHandGrenade::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_HANDGRENADE; - SET_MODEL(ENT(pev), "models/w_grenade.mdl"); + SET_MODEL( ENT( pev ), "models/w_grenade.mdl" ); #ifndef CLIENT_DLL pev->dmg = gSkillData.plrDmgHandGrenade; @@ -52,14 +53,14 @@ void CHandGrenade::Spawn( ) void CHandGrenade::Precache( void ) { - PRECACHE_MODEL("models/w_grenade.mdl"); - PRECACHE_MODEL("models/v_grenade.mdl"); - PRECACHE_MODEL("models/p_grenade.mdl"); + PRECACHE_MODEL( "models/w_grenade.mdl" ); + PRECACHE_MODEL( "models/v_grenade.mdl" ); + PRECACHE_MODEL( "models/p_grenade.mdl" ); } -int CHandGrenade::GetItemInfo(ItemInfo *p) +int CHandGrenade::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "Hand Grenade"; p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; p->pszAmmo2 = NULL; @@ -74,7 +75,7 @@ int CHandGrenade::GetItemInfo(ItemInfo *p) return 1; } -BOOL CHandGrenade::Deploy( ) +BOOL CHandGrenade::Deploy() { m_flReleaseThrow = -1; return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" ); @@ -90,24 +91,24 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { SendWeaponAnim( HANDGRENADE_HOLSTER ); } else { // no more grenades! - m_pPlayer->pev->weapons &= ~(1<pev->weapons &= ~( 1 << WEAPON_HANDGRENADE ); SetThink( &CBasePlayerItem::DestroyItem ); pev->nextthink = gpGlobals->time + 0.1; } - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); + 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 ) + if( !m_flStartThrow && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) { m_flStartThrow = gpGlobals->time; m_flReleaseThrow = 0; @@ -119,23 +120,23 @@ void CHandGrenade::PrimaryAttack() void CHandGrenade::WeaponIdle( void ) { - if ( m_flReleaseThrow == 0 && m_flStartThrow ) + if( m_flReleaseThrow == 0 && m_flStartThrow ) m_flReleaseThrow = gpGlobals->time; - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if ( m_flStartThrow ) + if( m_flStartThrow ) { Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - if ( angThrow.x < 0 ) + 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 ) + if( flVel > 500 ) flVel = 500; UTIL_MakeVectors( angThrow ); @@ -146,16 +147,16 @@ void CHandGrenade::WeaponIdle( void ) // alway explode 3 seconds after the pin was pulled float time = m_flStartThrow - gpGlobals->time + 3.0; - if (time < 0) + if( time < 0 ) time = 0; CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time ); - if ( flVel < 500 ) + if( flVel < 500 ) { SendWeaponAnim( HANDGRENADE_THROW1 ); } - else if ( flVel < 1000 ) + else if( flVel < 1000 ) { SendWeaponAnim( HANDGRENADE_THROW2 ); } @@ -172,9 +173,9 @@ void CHandGrenade::WeaponIdle( void ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ]--; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - if ( !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 @@ -183,12 +184,12 @@ void CHandGrenade::WeaponIdle( void ) } return; } - else if ( m_flReleaseThrow > 0 ) + else if( m_flReleaseThrow > 0 ) { // we've finished the throw, restart. m_flStartThrow = 0; - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { SendWeaponAnim( HANDGRENADE_DRAW ); } @@ -203,16 +204,16 @@ void CHandGrenade::WeaponIdle( void ) return; } - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) + 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 + else { iAnim = HANDGRENADE_FIDGET; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0; diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index 0889a2dd..5aac1e53 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -57,7 +57,7 @@ enum #define ASSASSIN_AE_TOSS1 2 #define ASSASSIN_AE_JUMP 3 -#define bits_MEMORY_BADJUMP (bits_MEMORY_CUSTOM1) +#define bits_MEMORY_BADJUMP ( bits_MEMORY_CUSTOM1 ) class CHAssassin : public CBaseMonster { @@ -65,24 +65,24 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( 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 ); + 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 ); + void RunTask( Task_t *pTask ); + void DeathSound( void ); + void IdleSound( void ); CUSTOM_SCHEDULES - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; @@ -94,18 +94,18 @@ public: float m_flNextGrenadeCheck; Vector m_vecTossVelocity; - BOOL m_fThrowGrenade; + BOOL m_fThrowGrenade; - int m_iTargetRanderamt; + int m_iTargetRanderamt; - int m_iFrustration; + int m_iFrustration; - int m_iShell; + int m_iShell; }; LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ) -TYPEDESCRIPTION CHAssassin::m_SaveData[] = +TYPEDESCRIPTION CHAssassin::m_SaveData[] = { DEFINE_FIELD( CHAssassin, m_flLastShot, FIELD_TIME ), DEFINE_FIELD( CHAssassin, m_flDiviation, FIELD_FLOAT ), @@ -126,14 +126,14 @@ IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ) //========================================================= // DieSound //========================================================= -void CHAssassin :: DeathSound ( void ) +void CHAssassin::DeathSound( void ) { } //========================================================= // IdleSound //========================================================= -void CHAssassin :: IdleSound ( void ) +void CHAssassin::IdleSound( void ) { } @@ -141,38 +141,38 @@ void CHAssassin :: IdleSound ( void ) // ISoundMask - returns a bit mask indicating which types // of sounds this monster regards. //========================================================= -int CHAssassin :: ISoundMask ( void) +int CHAssassin::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; + 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 ) +int CHAssassin::Classify( void ) { - return CLASS_HUMAN_MILITARY; + return CLASS_HUMAN_MILITARY; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CHAssassin :: SetYawSpeed ( void ) +void CHAssassin::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_TURN_LEFT: case ACT_TURN_RIGHT: ys = 360; break; - default: + default: ys = 360; break; } @@ -183,9 +183,9 @@ void CHAssassin :: SetYawSpeed ( void ) //========================================================= // Shoot //========================================================= -void CHAssassin :: Shoot ( void ) +void CHAssassin::Shoot( void ) { - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { return; } @@ -193,31 +193,31 @@ void CHAssassin :: Shoot ( void ) Vector vecShootOrigin = GetGunPosition(); Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - if (m_flLastShot + 2 < gpGlobals->time) + if( m_flLastShot + 2 < gpGlobals->time ) { m_flDiviation = 0.10; } else { m_flDiviation -= 0.01; - if (m_flDiviation < 0.02) + if( m_flDiviation < 0.02 ) m_flDiviation = 0.02; } m_flLastShot = gpGlobals->time; - UTIL_MakeVectors ( pev->angles ); + 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 + 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)) + 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); + 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); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT( 0.6, 0.8 ), ATTN_NORM ); break; } @@ -235,17 +235,17 @@ void CHAssassin :: Shoot ( void ) // // Returns number of events handled, 0 if none. //========================================================= -void CHAssassin :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CHAssassin::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case ASSASSIN_AE_SHOOT1: - Shoot( ); + 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 ); + 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; @@ -271,18 +271,18 @@ void CHAssassin :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CHAssassin :: Spawn() +void CHAssassin::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/hassassin.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + SET_MODEL( ENT( pev ), "models/hassassin.mdl" ); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_RED; pev->effects = 0; - pev->health = gSkillData.hassassinHealth; + 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; @@ -300,16 +300,16 @@ void CHAssassin :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CHAssassin :: Precache() +void CHAssassin::Precache() { - PRECACHE_MODEL("models/hassassin.mdl"); + PRECACHE_MODEL( "models/hassassin.mdl" ); - PRECACHE_SOUND("weapons/pl_gun1.wav"); - PRECACHE_SOUND("weapons/pl_gun2.wav"); + PRECACHE_SOUND( "weapons/pl_gun1.wav" ); + PRECACHE_SOUND( "weapons/pl_gun2.wav" ); - PRECACHE_SOUND("debris/beamstart1.wav"); + PRECACHE_SOUND( "debris/beamstart1.wav" ); - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell } //========================================================= @@ -319,28 +319,27 @@ void CHAssassin :: Precache() //========================================================= // Fail Schedule //========================================================= -Task_t tlAssassinFail[] = +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 }, + { 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[] = +Schedule_t slAssassinFail[] = { { tlAssassinFail, - ARRAYSIZE ( tlAssassinFail ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | + 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" @@ -350,19 +349,19 @@ Schedule_t slAssassinFail[] = //========================================================= // Enemy exposed Agrunt's cover //========================================================= -Task_t tlAssassinExposed[] = +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 }, + { 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 ), + ARRAYSIZE( tlAssassinExposed ), bits_COND_CAN_MELEE_ATTACK1, 0, "AssassinExposed", @@ -375,25 +374,24 @@ Schedule_t slAssassinExposed[] = //========================================================= 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 }, + { 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[] = +Schedule_t slAssassinTakeCoverFromEnemy[] = { - { + { tlAssassinTakeCoverFromEnemy, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy ), + ARRAYSIZE( tlAssassinTakeCoverFromEnemy ), bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK1 | + bits_COND_CAN_MELEE_ATTACK1 | bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, "AssassinTakeCoverFromEnemy" }, @@ -403,29 +401,28 @@ Schedule_t slAssassinTakeCoverFromEnemy[] = // Take cover from enemy! Tries lateral cover before node // cover! //========================================================= -Task_t tlAssassinTakeCoverFromEnemy2[] = +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 }, + { 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[] = +Schedule_t slAssassinTakeCoverFromEnemy2[] = { - { + { tlAssassinTakeCoverFromEnemy2, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy2 ), + ARRAYSIZE( tlAssassinTakeCoverFromEnemy2 ), bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK2 | + bits_COND_CAN_MELEE_ATTACK2 | bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, "AssassinTakeCoverFromEnemy2" }, @@ -434,22 +431,22 @@ Schedule_t slAssassinTakeCoverFromEnemy2[] = //========================================================= // hide from the loudest sound source //========================================================= -Task_t tlAssassinTakeCoverFromBestSound[] = +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 }, + { 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[] = +Schedule_t slAssassinTakeCoverFromBestSound[] = { - { + { tlAssassinTakeCoverFromBestSound, - ARRAYSIZE ( tlAssassinTakeCoverFromBestSound ), + ARRAYSIZE( tlAssassinTakeCoverFromBestSound ), bits_COND_NEW_ENEMY, 0, "AssassinTakeCoverFromBestSound" @@ -459,27 +456,26 @@ Schedule_t slAssassinTakeCoverFromBestSound[] = //========================================================= // AlertIdle Schedules //========================================================= -Task_t tlAssassinHide[] = +Task_t tlAssassinHide[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, }; -Schedule_t slAssassinHide[] = +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 | + 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" }, @@ -488,23 +484,22 @@ Schedule_t slAssassinHide[] = //========================================================= // HUNT Schedules //========================================================= -Task_t tlAssassinHunt[] = +Task_t tlAssassinHunt[] = { - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, + { 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 | + ARRAYSIZE( tlAssassinHunt ), + bits_COND_NEW_ENEMY | + // bits_COND_SEE_ENEMY | + bits_COND_CAN_RANGE_ATTACK1 | bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, "AssassinHunt" }, @@ -513,18 +508,18 @@ Schedule_t slAssassinHunt[] = //========================================================= // Jumping Schedules //========================================================= -Task_t tlAssassinJump[] = +Task_t tlAssassinJump[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, + { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, }; -Schedule_t slAssassinJump[] = +Schedule_t slAssassinJump[] = { - { + { tlAssassinJump, - ARRAYSIZE ( tlAssassinJump ), + ARRAYSIZE( tlAssassinJump ), 0, 0, "AssassinJump" @@ -534,18 +529,18 @@ Schedule_t slAssassinJump[] = //========================================================= // repel //========================================================= -Task_t tlAssassinJumpAttack[] = +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 }, + { 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[] = +Schedule_t slAssassinJumpAttack[] = { - { + { tlAssassinJumpAttack, - ARRAYSIZE ( tlAssassinJumpAttack ), + ARRAYSIZE( tlAssassinJumpAttack ), 0, 0, "AssassinJumpAttack" @@ -557,25 +552,25 @@ Schedule_t slAssassinJumpAttack[] = //========================================================= 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 }, + { 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[] = +Schedule_t slAssassinJumpLand[] = { - { + { tlAssassinJumpLand, - ARRAYSIZE ( tlAssassinJumpLand ), - 0, + ARRAYSIZE( tlAssassinJumpLand ), + 0, 0, "AssassinJumpLand" }, @@ -600,26 +595,26 @@ IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ) //========================================================= // CheckMeleeAttack1 - jump like crazy if the enemy gets too close. //========================================================= -BOOL CHAssassin :: CheckMeleeAttack1 ( float flDot, float flDist ) +BOOL CHAssassin::CheckMeleeAttack1( float flDot, float flDist ) { - if ( m_flNextJump < gpGlobals->time && (flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP )) && m_hEnemy != NULL ) + if( m_flNextJump < gpGlobals->time && ( flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP ) ) && m_hEnemy != NULL ) { - TraceResult tr; + 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); + 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) + if( tr.fStartSolid || tr.flFraction < 1.0 ) { return FALSE; } float flGravity = g_psv_gravity->value; - float time = sqrt( 160 / (0.5 * flGravity)); + float time = sqrt( 160 / ( 0.5 * flGravity ) ); float speed = flGravity * time / 160; - m_vecJumpVelocity = (vecDest - pev->origin) * speed; + m_vecJumpVelocity = ( vecDest - pev->origin ) * speed; return TRUE; } @@ -630,18 +625,18 @@ BOOL CHAssassin :: CheckMeleeAttack1 ( float flDot, float flDist ) // CheckRangeAttack1 - drop a cap in their ass // //========================================================= -BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CHAssassin::CheckRangeAttack1( float flDot, float flDist ) { - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) + if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) { - TraceResult tr; + 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); + UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget( vecSrc ), dont_ignore_monsters, ENT( pev ), &tr ); - if ( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) + if( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) { return TRUE; } @@ -652,24 +647,24 @@ BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist ) //========================================================= // CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. //========================================================= -BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) +BOOL CHAssassin::CheckRangeAttack2( float flDot, float flDist ) { m_fThrowGrenade = FALSE; - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) + 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) + if( m_iFrustration <= 2 ) return FALSE; - if ( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) + 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 + 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 ) + if( vecToss != g_vecZero ) { m_vecTossVelocity = vecToss; @@ -686,46 +681,54 @@ BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) //========================================================= // RunAI //========================================================= -void CHAssassin :: RunAI( void ) +void CHAssassin::RunAI( void ) { - CBaseMonster :: RunAI(); + CBaseMonster::RunAI(); // always visible if moving // always visible is not on hard - if (g_iSkillLevel != SKILL_HARD || m_hEnemy == NULL || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !(pev->flags & FL_ONGROUND)) + if( g_iSkillLevel != SKILL_HARD || m_hEnemy == NULL || 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 > m_iTargetRanderamt ) { - if (pev->renderamt == 255) + if( pev->renderamt == 255 ) { - EMIT_SOUND (ENT(pev), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); + 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) + else if( pev->renderamt < m_iTargetRanderamt ) { pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt ); - if (pev->renderamt == 255) + if( pev->renderamt == 255 ) pev->rendermode = kRenderNormal; } - if (m_Activity == ACT_RUN || m_Activity == ACT_WALK) + if( m_Activity == ACT_RUN || m_Activity == ACT_WALK ) { static int iStep = 0; - iStep = ! iStep; - if (iStep) + 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; + 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; } } } @@ -734,24 +737,24 @@ void CHAssassin :: RunAI( void ) //========================================================= // StartTask //========================================================= -void CHAssassin :: StartTask ( Task_t *pTask ) +void CHAssassin::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RANGE_ATTACK2: - if (!m_fThrowGrenade) + if( !m_fThrowGrenade ) { - TaskComplete( ); + TaskComplete(); } else { - CBaseMonster :: StartTask ( pTask ); + CBaseMonster::StartTask( pTask ); } break; case TASK_ASSASSIN_FALL_TO_GROUND: break; default: - CBaseMonster :: StartTask ( pTask ); + CBaseMonster::StartTask( pTask ); break; } } @@ -759,21 +762,21 @@ void CHAssassin :: StartTask ( Task_t *pTask ) //========================================================= // RunTask //========================================================= -void CHAssassin :: RunTask ( Task_t *pTask ) +void CHAssassin::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_ASSASSIN_FALL_TO_GROUND: MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { - if (pev->velocity.z > 0) + if( pev->velocity.z > 0 ) { pev->sequence = LookupSequence( "fly_up" ); } - else if (HasConditions ( bits_COND_SEE_ENEMY )) + else if( HasConditions( bits_COND_SEE_ENEMY ) ) { pev->sequence = LookupSequence( "fly_attack" ); pev->frame = 0; @@ -783,18 +786,18 @@ void CHAssassin :: RunTask ( Task_t *pTask ) pev->sequence = LookupSequence( "fly_down" ); pev->frame = 0; } - - ResetSequenceInfo( ); + + ResetSequenceInfo(); SetYawSpeed(); } - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { - // ALERT( at_console, "on ground\n"); - TaskComplete( ); + // ALERT( at_console, "on ground\n" ); + TaskComplete(); } break; default: - CBaseMonster :: RunTask ( pTask ); + CBaseMonster::RunTask( pTask ); break; } } @@ -805,145 +808,144 @@ void CHAssassin :: RunTask ( Task_t *pTask ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CHAssassin :: GetSchedule ( void ) +Schedule_t *CHAssassin::GetSchedule( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_IDLE: case MONSTERSTATE_ALERT: { - if ( HasConditions ( bits_COND_HEAR_SOUND )) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound &&( pSound->m_iType & bits_SOUND_DANGER ) ) { return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } - if ( pSound && (pSound->m_iType & bits_SOUND_COMBAT) ) + 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 ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } // flying? - if ( pev->movetype == MOVETYPE_TOSS) + if( pev->movetype == MOVETYPE_TOSS ) { - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { - // ALERT( at_console, "landed\n"); + // ALERT( at_console, "landed\n" ); // just landed pev->movetype = MOVETYPE_STEP; return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_LAND ); } else { - // ALERT( at_console, "jump\n"); + // ALERT( at_console, "jump\n" ); // jump or jump/shoot - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP ); + if( m_MonsterState == MONSTERSTATE_COMBAT ) + return GetScheduleOfType( SCHED_ASSASSIN_JUMP ); else - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_ATTACK ); + return GetScheduleOfType( SCHED_ASSASSIN_JUMP_ATTACK ); } } - if ( HasConditions ( bits_COND_HEAR_SOUND )) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) { return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } } - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) + if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) { m_iFrustration++; } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) + if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) { m_iFrustration++; } // jump player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { - // ALERT( at_console, "melee attack 1\n"); - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); + // ALERT( at_console, "melee attack 1\n" ); + return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } // throw grenade - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) ) { // ALERT( at_console, "range attack 2\n"); - return GetScheduleOfType ( SCHED_RANGE_ATTACK2 ); + return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); } // spotted - if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) && HasConditions( bits_COND_ENEMY_FACING_ME ) ) { - // ALERT( at_console, "exposed\n"); + // ALERT( at_console, "exposed\n" ); m_iFrustration++; - return GetScheduleOfType ( SCHED_ASSASSIN_EXPOSED ); + return GetScheduleOfType( SCHED_ASSASSIN_EXPOSED ); } // can attack - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - // ALERT( at_console, "range attack 1\n"); + // ALERT( at_console, "range attack 1\n" ); m_iFrustration = 0; - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { - // ALERT( at_console, "face\n"); - return GetScheduleOfType ( SCHED_COMBAT_FACE ); + // ALERT( at_console, "face\n" ); + return GetScheduleOfType( SCHED_COMBAT_FACE ); } // new enemy - if ( HasConditions ( bits_COND_NEW_ENEMY ) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { - // ALERT( at_console, "take cover\n"); - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + // ALERT( at_console, "take cover\n" ); + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); } - // ALERT( at_console, "stand\n"); - return GetScheduleOfType ( SCHED_ALERT_STAND ); + // ALERT( at_console, "stand\n" ); + return GetScheduleOfType( SCHED_ALERT_STAND ); } break; default: break; } - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } //========================================================= //========================================================= -Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) +Schedule_t *CHAssassin::GetScheduleOfType( int Type ) { // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) + switch( Type ) { case SCHED_TAKE_COVER_FROM_ENEMY: - if (pev->health > 30) + if( pev->health > 30 ) return slAssassinTakeCoverFromEnemy; else return slAssassinTakeCoverFromEnemy2; @@ -952,19 +954,19 @@ Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) case SCHED_ASSASSIN_EXPOSED: return slAssassinExposed; case SCHED_FAIL: - if (m_MonsterState == MONSTERSTATE_COMBAT) + if( m_MonsterState == MONSTERSTATE_COMBAT ) return slAssassinFail; break; case SCHED_ALERT_STAND: - if (m_MonsterState == MONSTERSTATE_COMBAT) + if( m_MonsterState == MONSTERSTATE_COMBAT ) return slAssassinHide; break; case SCHED_CHASE_ENEMY: return slAssassinHunt; case SCHED_MELEE_ATTACK1: - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { - if (m_flNextJump > gpGlobals->time) + if( m_flNextJump > gpGlobals->time ) { // can't jump yet, go ahead and fail return slAssassinFail; @@ -985,6 +987,6 @@ Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) return slAssassinJumpLand; } - return CBaseMonster :: GetScheduleOfType( Type ); + return CBaseMonster::GetScheduleOfType( Type ); } #endif diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index a94232de..d84a692e 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -28,42 +28,42 @@ //========================================================= #define HC_AE_JUMPATTACK ( 2 ) -Task_t tlHCRangeAttack1[] = +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 }, + { 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[] = +Schedule_t slHCRangeAttack1[] = { - { + { tlHCRangeAttack1, - ARRAYSIZE ( tlHCRangeAttack1 ), - bits_COND_ENEMY_OCCLUDED | + ARRAYSIZE( tlHCRangeAttack1 ), + bits_COND_ENEMY_OCCLUDED | bits_COND_NO_AMMO_LOADED, 0, "HCRangeAttack1" }, }; -Task_t tlHCRangeAttack1Fast[] = +Task_t tlHCRangeAttack1Fast[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_IDEAL, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, }; -Schedule_t slHCRangeAttack1Fast[] = +Schedule_t slHCRangeAttack1Fast[] = { - { + { tlHCRangeAttack1Fast, - ARRAYSIZE ( tlHCRangeAttack1Fast ), - bits_COND_ENEMY_OCCLUDED | + ARRAYSIZE( tlHCRangeAttack1Fast ), + bits_COND_ENEMY_OCCLUDED | bits_COND_NO_AMMO_LOADED, 0, "HCRAFast" @@ -136,20 +136,20 @@ const char *CHeadCrab::pPainSounds[] = "headcrab/hc_pain3.wav", }; -const char *CHeadCrab::pAttackSounds[] = +const char *CHeadCrab::pAttackSounds[] = { "headcrab/hc_attack1.wav", "headcrab/hc_attack2.wav", "headcrab/hc_attack3.wav", }; -const char *CHeadCrab::pDeathSounds[] = +const char *CHeadCrab::pDeathSounds[] = { "headcrab/hc_die1.wav", "headcrab/hc_die2.wav", }; -const char *CHeadCrab::pBiteSounds[] = +const char *CHeadCrab::pBiteSounds[] = { "headcrab/hc_headbite.wav", }; @@ -158,9 +158,9 @@ const char *CHeadCrab::pBiteSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CHeadCrab :: Classify ( void ) +int CHeadCrab::Classify( void ) { - return CLASS_ALIEN_PREY; + return CLASS_ALIEN_PREY; } //========================================================= @@ -168,38 +168,38 @@ int CHeadCrab :: Classify ( void ) // bounding box is much larger than the actual creature so // this is needed for targeting //========================================================= -Vector CHeadCrab :: Center ( void ) +Vector CHeadCrab::Center( void ) { return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); } -Vector CHeadCrab :: BodyTarget( const Vector &posSrc ) +Vector CHeadCrab::BodyTarget( const Vector &posSrc ) { - return Center( ); + return Center(); } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CHeadCrab :: SetYawSpeed ( void ) +void CHeadCrab::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { - case ACT_IDLE: + case ACT_IDLE: ys = 30; break; - case ACT_RUN: - case ACT_WALK: + case ACT_RUN: + case ACT_WALK: ys = 20; break; case ACT_TURN_LEFT: case ACT_TURN_RIGHT: ys = 60; break; - case ACT_RANGE_ATTACK1: + case ACT_RANGE_ATTACK1: ys = 30; break; default: @@ -214,7 +214,7 @@ void CHeadCrab :: SetYawSpeed ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CHeadCrab::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -222,25 +222,25 @@ void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) { 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 ); + 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 != NULL) + if( m_hEnemy != NULL ) { float gravity = g_psv_gravity->value; - if (gravity <= 1) + 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) + 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 = m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin; vecJumpDir = vecJumpDir * ( 1.0 / time ); // Speed to offset gravity at the desired height @@ -248,8 +248,8 @@ void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) // Don't jump too far/fast float distance = vecJumpDir.Length(); - - if (distance > 650) + + if( distance > 650 ) { vecJumpDir = vecJumpDir * ( 650.0 / distance ); } @@ -261,14 +261,13 @@ void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) } int iSound = RANDOM_LONG(0,2); - if ( iSound != 0 ) + 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; @@ -278,19 +277,19 @@ void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CHeadCrab :: Spawn() +void CHeadCrab::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/headcrab.mdl"); - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); + SET_MODEL( ENT( pev ), "models/headcrab.mdl" ); + UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - pev->solid = SOLID_SLIDEBOX; + 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->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; @@ -301,29 +300,29 @@ void CHeadCrab :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CHeadCrab :: Precache() +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_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"); -} + PRECACHE_MODEL( "models/headcrab.mdl" ); +} //========================================================= // RunTask //========================================================= -void CHeadCrab :: RunTask ( Task_t *pTask ) +void CHeadCrab::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: case TASK_RANGE_ATTACK2: { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); SetTouch( NULL ); @@ -333,7 +332,7 @@ void CHeadCrab :: RunTask ( Task_t *pTask ) } default: { - CBaseMonster :: RunTask(pTask); + CBaseMonster::RunTask( pTask ); } } } @@ -342,23 +341,23 @@ void CHeadCrab :: RunTask ( Task_t *pTask ) // LeapTouch - this is the headcrab's touch function when it // is in the air //========================================================= -void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) +void CHeadCrab::LeapTouch( CBaseEntity *pOther ) { - if ( !pOther->pev->takedamage ) + if( !pOther->pev->takedamage ) { return; } - if ( pOther->Classify() == Classify() ) + if( pOther->Classify() == Classify() ) { return; } // Don't hit if back on ground - if ( !FBitSet( pev->flags, FL_ONGROUND ) ) + if( !FBitSet( pev->flags, FL_ONGROUND ) ) { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - + EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBiteSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); } @@ -368,20 +367,20 @@ void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) //========================================================= // PrescheduleThink //========================================================= -void CHeadCrab :: PrescheduleThink ( void ) +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 ) + if( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) { IdleSound(); } } -void CHeadCrab :: StartTask ( Task_t *pTask ) +void CHeadCrab::StartTask( Task_t *pTask ) { m_iTaskStatus = TASKSTATUS_RUNNING; - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: { @@ -392,7 +391,7 @@ void CHeadCrab :: StartTask ( Task_t *pTask ) } default: { - CBaseMonster :: StartTask( pTask ); + CBaseMonster::StartTask( pTask ); } } } @@ -400,9 +399,9 @@ void CHeadCrab :: StartTask ( Task_t *pTask ) //========================================================= // CheckRangeAttack1 //========================================================= -BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CHeadCrab::CheckRangeAttack1( float flDot, float flDist ) { - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) + if( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) { return TRUE; } @@ -412,12 +411,12 @@ BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) //========================================================= // CheckRangeAttack2 //========================================================= -BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) +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 ) + if( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) { return TRUE; } @@ -425,55 +424,56 @@ BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) #endif } -int CHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +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 ) + if( bitsDamageType & DMG_ACID ) flDamage = 0; return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } +#define CRAB_ATTN_IDLE (float)1.5 + //========================================================= // IdleSound //========================================================= -#define CRAB_ATTN_IDLE (float)1.5 -void CHeadCrab :: IdleSound ( void ) +void CHeadCrab::IdleSound( void ) { - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pIdleSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); } //========================================================= // AlertSound //========================================================= -void CHeadCrab :: AlertSound ( void ) +void CHeadCrab::AlertSound( void ) { - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAlertSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); } //========================================================= // AlertSound //========================================================= -void CHeadCrab :: PainSound ( void ) +void CHeadCrab::PainSound( void ) { - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); } //========================================================= // DeathSound //========================================================= -void CHeadCrab :: DeathSound ( void ) +void CHeadCrab::DeathSound( void ) { - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); + EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); } -Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) +Schedule_t *CHeadCrab::GetScheduleOfType( int Type ) { - switch ( Type ) + switch( Type ) { case SCHED_RANGE_ATTACK1: { - return &slHCRangeAttack1[ 0 ]; + return &slHCRangeAttack1[0]; } break; } @@ -486,62 +486,61 @@ class CBabyCrab : public CHeadCrab public: void Spawn( void ); void Precache( void ); - void SetYawSpeed ( 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); } + 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 ) +void CBabyCrab::Spawn( void ) { CHeadCrab::Spawn(); - SET_MODEL(ENT(pev), "models/baby_headcrab.mdl"); + 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)); + UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown + pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown } -void CBabyCrab :: Precache( void ) +void CBabyCrab::Precache( void ) { PRECACHE_MODEL( "models/baby_headcrab.mdl" ); CHeadCrab::Precache(); } -void CBabyCrab :: SetYawSpeed ( void ) +void CBabyCrab::SetYawSpeed( void ) { pev->yaw_speed = 120; } -BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) +BOOL CBabyCrab::CheckRangeAttack1( float flDot, float flDist ) { - if ( pev->flags & FL_ONGROUND ) + if( pev->flags & FL_ONGROUND ) { - if ( pev->groundentity && (pev->groundentity->v.flags & (FL_CLIENT|FL_MONSTER)) ) + 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 ) + if( flDist <= 180 && flDot >= 0.55 ) return TRUE; } return FALSE; } -Schedule_t* CBabyCrab :: GetScheduleOfType ( int Type ) +Schedule_t *CBabyCrab::GetScheduleOfType( int Type ) { switch( Type ) { case SCHED_FAIL: // If you fail, try to jump! - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) return slHCRangeAttack1Fast; break; - case SCHED_RANGE_ATTACK1: { return slHCRangeAttack1Fast; diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 940a8cc9..e1b22467 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -31,10 +31,9 @@ class CHealthKit : public CItem void Precache( void ); BOOL MyTouch( CBasePlayer *pPlayer ); /* - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; */ }; @@ -46,46 +45,45 @@ TYPEDESCRIPTION CHealthKit::m_SaveData[] = }; - -IMPLEMENT_SAVERESTORE( CHealthKit, CItem) +IMPLEMENT_SAVERESTORE( CHealthKit, CItem ) */ -void CHealthKit :: Spawn( void ) +void CHealthKit::Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_medkit.mdl"); + 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"); + PRECACHE_MODEL( "models/w_medkit.mdl" ); + PRECACHE_SOUND( "items/smallmedkit1.wav" ); } BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) { - if ( pPlayer->pev->deadflag != DEAD_NO ) + if( pPlayer->pev->deadflag != DEAD_NO ) { return FALSE; } - if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) ) + if( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); + WRITE_STRING( STRING( pev->classname ) ); MESSAGE_END(); - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM ); - if ( g_pGameRules->ItemShouldRespawn( this ) ) + if( g_pGameRules->ItemShouldRespawn( this ) ) { Respawn(); } else { - UTIL_Remove(this); + UTIL_Remove( this ); } return TRUE; @@ -100,51 +98,51 @@ BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) class CWallHealth : public CBaseToggle { public: - void Spawn( ); + void Spawn(); void Precache( void ); - void EXPORT Off(void); - void EXPORT Recharge(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 ); + 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[]; + 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; + 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), + 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) +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")) + 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")) + else if( FStrEq( pkvd->szKeyName, "dmdelay" ) ) { - m_iReactivate = atoi(pkvd->szValue); + m_iReactivate = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -153,48 +151,48 @@ void CWallHealth::KeyValue( KeyValueData *pkvd ) void CWallHealth::Spawn() { - Precache( ); + Precache(); - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + 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) ); + 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 = gSkillData.healthchargerCapacity; pev->frame = 0; } void CWallHealth::Precache() { - PRECACHE_SOUND("items/medshot4.wav"); - PRECACHE_SOUND("items/medshotno1.wav"); - PRECACHE_SOUND("items/medcharge4.wav"); + 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) + if( !pActivator ) return; // if it's not a player, ignore - if ( !pActivator->IsPlayer() ) + if( !pActivator->IsPlayer() ) return; // if there is no juice left, turn it off - if (m_iJuice <= 0) + 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<pev->weapons & ( 1 << WEAPON_SUIT ) ) ) ) { - if (m_flSoundTime <= gpGlobals->time) + if( m_flSoundTime <= gpGlobals->time ) { m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM ); } return; } @@ -203,24 +201,24 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u SetThink( &CWallHealth::Off ); // Time to recharge yet? - if (m_flNextCharge >= gpGlobals->time) + if( m_flNextCharge >= gpGlobals->time ) return; // Play the on sound or the looping charging sound - if (!m_iOn) + if( !m_iOn ) { m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); + 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)) + if( ( m_iOn == 1 ) && ( m_flSoundTime <= gpGlobals->time ) ) { m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); } // charge the player - if ( pActivator->TakeHealth( 1, DMG_GENERIC ) ) + if( pActivator->TakeHealth( 1, DMG_GENERIC ) ) { m_iJuice--; } @@ -229,23 +227,23 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u m_flNextCharge = gpGlobals->time + 0.1; } -void CWallHealth::Recharge(void) +void CWallHealth::Recharge( void ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); m_iJuice = gSkillData.healthchargerCapacity; pev->frame = 0; SetThink( &CBaseEntity::SUB_DoNothing ); } -void CWallHealth::Off(void) +void CWallHealth::Off( void ) { // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); + if( m_iOn > 1 ) + STOP_SOUND( ENT( pev ), CHAN_STATIC, "items/medcharge4.wav" ); m_iOn = 0; - if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) ) + if( ( !m_iJuice ) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0 ) ) { pev->nextthink = pev->ltime + m_iReactivate; SetThink( &CWallHealth::Recharge ); diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 94072d57..7b0eaa2c 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -54,18 +54,18 @@ extern DLL_GLOBAL int g_iSkillLevel; #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_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_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_COMMANDER 1 +#define HEAD_SHOTGUN 2 #define HEAD_M203 3 #define GUN_GROUP 2 #define GUN_MP5 0 @@ -81,10 +81,10 @@ extern DLL_GLOBAL int g_iSkillLevel; #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_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. +#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 @@ -124,38 +124,38 @@ class CHGrunt : public CSquadMonster public: void Spawn( void ); void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( 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 ); + 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 ); + void IdleSound( void ); Vector GetGunPosition( void ); - void Shoot ( void ); - void Shotgun ( void ); - void PrescheduleThink ( 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 ); + + 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 ); + int IRelationship( CBaseEntity *pTarget ); BOOL FOkToSpeak( void ); void JustSpoke( void ); @@ -169,19 +169,19 @@ public: float m_flNextPainTime; float m_flLastEnemySightTime; - Vector m_vecTossVelocity; + 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; + 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_iBrassShell; + int m_iShotgunShell; - int m_iSentence; + int m_iSentence; static const char *pGruntSentences[]; }; @@ -192,15 +192,15 @@ 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_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( CShotgun, m_iBrassShell, FIELD_INTEGER ), + //DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), }; @@ -241,17 +241,17 @@ enum // may still fail but in most cases, well after the grunt has // started moving. //========================================================= -void CHGrunt :: SpeakSentence( void ) +void CHGrunt::SpeakSentence( void ) { - if ( m_iSentence == HGRUNT_SENT_NONE ) + if( m_iSentence == HGRUNT_SENT_NONE ) { // no sentence cued up. return; } - if (FOkToSpeak()) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + SENTENCEG_PlayRndSz( ENT( pev ), pGruntSentences[m_iSentence], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); JustSpoke(); } } @@ -260,9 +260,9 @@ void CHGrunt :: SpeakSentence( void ) // IRelationship - overridden because Alien Grunts are // Human Grunt's nemesis. //========================================================= -int CHGrunt::IRelationship ( CBaseEntity *pTarget ) +int CHGrunt::IRelationship( CBaseEntity *pTarget ) { - if ( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) + if( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) { return R_NM; } @@ -273,18 +273,19 @@ int CHGrunt::IRelationship ( CBaseEntity *pTarget ) //========================================================= // GibMonster - make gun fly through the air. //========================================================= -void CHGrunt :: GibMonster ( void ) +void CHGrunt::GibMonster( void ) { - Vector vecGunPos; - Vector vecGunAngles; + Vector vecGunPos; + Vector vecGunAngles; - if ( GetBodygroup( 2 ) != 2 ) + if( GetBodygroup( 2 ) != 2 ) { // throw a gun if the grunt has one GetAttachment( 0, vecGunPos, vecGunAngles ); - + CBaseEntity *pGun; - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + + if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) { pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); } @@ -292,24 +293,25 @@ void CHGrunt :: GibMonster ( void ) { pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); } - if ( pGun ) + + 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 ); + 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 )) + + 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 ); + 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(); + CBaseMonster::GibMonster(); } //========================================================= @@ -317,26 +319,26 @@ void CHGrunt :: GibMonster ( void ) // hear the DANGER sound that is made by hand grenades and // other dangerous items. //========================================================= -int CHGrunt :: ISoundMask ( void ) +int CHGrunt::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_PLAYER | bits_SOUND_DANGER; } //========================================================= // someone else is talking - don't speak //========================================================= -BOOL CHGrunt :: FOkToSpeak( void ) +BOOL CHGrunt::FOkToSpeak( void ) { // if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) return FALSE; - if ( pev->spawnflags & SF_MONSTER_GAG ) + if( pev->spawnflags & SF_MONSTER_GAG ) { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) + if( m_MonsterState != MONSTERSTATE_COMBAT ) { // no talking outside of combat if gagged. return FALSE; @@ -344,17 +346,17 @@ BOOL CHGrunt :: FOkToSpeak( void ) } // if player is not in pvs, don't speak - //if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) + //if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) // return FALSE; - + return TRUE; } //========================================================= //========================================================= -void CHGrunt :: JustSpoke( void ) +void CHGrunt::JustSpoke( void ) { - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 1.5, 2.0 ); m_iSentence = HGRUNT_SENT_NONE; } @@ -362,18 +364,18 @@ void CHGrunt :: JustSpoke( void ) // PrescheduleThink - this function runs after conditions // are collected and before scheduling code is run. //========================================================= -void CHGrunt :: PrescheduleThink ( void ) +void CHGrunt::PrescheduleThink( void ) { - if ( InSquad() && m_hEnemy != NULL ) + if( InSquad() && m_hEnemy != NULL ) { - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + 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 ) + if( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) { // been a while since we've seen the enemy MySquadLeader()->m_fEnemyEluded = TRUE; @@ -394,9 +396,9 @@ void CHGrunt :: PrescheduleThink ( void ) // this is a bad bug. Friendly machine gun fire avoidance // will unecessarily prevent the throwing of a grenade as well. //========================================================= -BOOL CHGrunt :: FCanCheckAttacks ( void ) +BOOL CHGrunt::FCanCheckAttacks( void ) { - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + if( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) { return TRUE; } @@ -409,21 +411,21 @@ BOOL CHGrunt :: FCanCheckAttacks ( void ) //========================================================= // CheckMeleeAttack1 //========================================================= -BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) +BOOL CHGrunt::CheckMeleeAttack1( float flDot, float flDist ) { CBaseMonster *pEnemy; - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { pEnemy = m_hEnemy->MyMonsterPointer(); - if ( !pEnemy ) + if( !pEnemy ) { return FALSE; } } - if ( flDist <= 64 && flDot >= 0.7 && + if( flDist <= 64 && flDot >= 0.7 && pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON && pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON ) { @@ -440,13 +442,13 @@ BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) // 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 ) +BOOL CHGrunt::CheckRangeAttack1( float flDot, float flDist ) { - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) + if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) { - TraceResult tr; + TraceResult tr; - if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) + if( !m_hEnemy->IsPlayer() && flDist <= 64 ) { // kick nonclients, but don't shoot at them. return FALSE; @@ -455,9 +457,9 @@ BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) 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); + UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget( vecSrc ), ignore_monsters, ignore_glass, ENT( pev ), &tr ); - if ( tr.flFraction == 1.0 ) + if( tr.flFraction == 1.0 ) { return TRUE; } @@ -470,27 +472,27 @@ BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) // CheckRangeAttack2 - this checks the Grunt's grenade // attack. //========================================================= -BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) +BOOL CHGrunt::CheckRangeAttack2( float flDot, float flDist ) { - if (! FBitSet(pev->weapons, (HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER))) + 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 ) + 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 ) + 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 ) + 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. @@ -501,10 +503,10 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) Vector vecTarget; - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) + if( FBitSet( pev->weapons, HGRUNT_HANDGRENADE ) ) { // find feet - if (RANDOM_LONG(0,1)) + 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 ); @@ -522,16 +524,16 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) { // find target // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->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; + 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( InSquad() ) { - if (SquadMemberInRange( vecTarget, 256 )) + 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. @@ -539,7 +541,7 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) } } - if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) + if( ( vecTarget - pev->origin ).Length2D() <= 256 ) { // crap, I don't want to blow myself up m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. @@ -547,12 +549,11 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) return m_fThrowGrenade; } - - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) + if( FBitSet( pev->weapons, HGRUNT_HANDGRENADE ) ) { Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - if ( vecToss != g_vecZero ) + if( vecToss != g_vecZero ) { m_vecTossVelocity = vecToss; @@ -573,7 +574,7 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) { Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - if ( vecToss != g_vecZero ) + if( vecToss != g_vecZero ) { m_vecTossVelocity = vecToss; @@ -597,17 +598,17 @@ BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) //========================================================= // 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) +void CHGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { // check for helmet shot - if (ptr->iHitgroup == 11) + if( ptr->iHitgroup == 11 ) { // make sure we're wearing one - if (GetBodygroup( 1 ) == HEAD_GRUNT && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) + if( GetBodygroup( 1 ) == HEAD_GRUNT && ( bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB ) ) ) { // absorb damage flDamage -= 20; - if (flDamage <= 0) + if( flDamage <= 0 ) { UTIL_Ricochet( ptr->vecEndPos, 1.0 ); flDamage = 0.01; @@ -619,31 +620,30 @@ void CHGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecD 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 ) +int CHGrunt::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Forget( bits_MEMORY_INCOVER ); - return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + return CSquadMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CHGrunt :: SetYawSpeed ( void ) +void CHGrunt::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: - ys = 150; + ys = 150; break; case ACT_RUN: ys = 150; @@ -679,37 +679,42 @@ void CHGrunt :: SetYawSpeed ( void ) pev->yaw_speed = ys; } -void CHGrunt :: IdleSound( void ) +void CHGrunt::IdleSound( void ) { - if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1))) + if( FOkToSpeak() && ( g_fGruntQuestion || RANDOM_LONG( 0, 1 ) ) ) { - if (!g_fGruntQuestion) + if( !g_fGruntQuestion ) { // ask question or make statement - switch (RANDOM_LONG(0,2)) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + 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); + 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); + case 2: + // statement + SENTENCEG_PlayRndSz( ENT( pev ), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); break; } } else { - switch (g_fGruntQuestion) + switch( g_fGruntQuestion ) { - case 1: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); + 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); + case 2: + // question + SENTENCEG_PlayRndSz( ENT( pev ), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); break; } g_fGruntQuestion = 0; @@ -722,11 +727,11 @@ void CHGrunt :: IdleSound( void ) // CheckAmmo - overridden for the grunt because he actually // uses ammo! (base class doesn't) //========================================================= -void CHGrunt :: CheckAmmo ( void ) +void CHGrunt::CheckAmmo( void ) { - if ( m_cAmmoLoaded <= 0 ) + if( m_cAmmoLoaded <= 0 ) { - SetConditions(bits_COND_NO_AMMO_LOADED); + SetConditions( bits_COND_NO_AMMO_LOADED ); } } @@ -734,25 +739,25 @@ void CHGrunt :: CheckAmmo ( void ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CHGrunt :: Classify ( void ) +int CHGrunt::Classify( void ) { - return CLASS_HUMAN_MILITARY; + return CLASS_HUMAN_MILITARY; } //========================================================= //========================================================= -CBaseEntity *CHGrunt :: Kick( void ) +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); + Vector vecEnd = vecStart + ( gpGlobals->v_forward * 70 ); - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); + UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - if ( tr.pHit ) + if( tr.pHit ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); return pEntity; @@ -765,9 +770,9 @@ CBaseEntity *CHGrunt :: Kick( void ) // GetGunPosition return the end of the barrel //========================================================= -Vector CHGrunt :: GetGunPosition( ) +Vector CHGrunt::GetGunPosition() { - if (m_fStanding ) + if( m_fStanding ) { return pev->origin + Vector( 0, 0, 60 ); } @@ -780,9 +785,9 @@ Vector CHGrunt :: GetGunPosition( ) //========================================================= // Shoot //========================================================= -void CHGrunt :: Shoot ( void ) +void CHGrunt::Shoot( void ) { - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { return; } @@ -790,14 +795,14 @@ void CHGrunt :: Shoot ( void ) Vector vecShootOrigin = GetGunPosition(); Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - UTIL_MakeVectors ( pev->angles ); + 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 + 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 ); @@ -807,9 +812,9 @@ void CHGrunt :: Shoot ( void ) //========================================================= // Shoot //========================================================= -void CHGrunt :: Shotgun ( void ) +void CHGrunt::Shotgun( void ) { - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { return; } @@ -817,14 +822,14 @@ void CHGrunt :: Shotgun ( void ) Vector vecShootOrigin = GetGunPosition(); Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - UTIL_MakeVectors ( pev->angles ); + 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 + 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 ); @@ -835,17 +840,17 @@ void CHGrunt :: Shotgun ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent ) { - Vector vecShootDir; - Vector vecShootOrigin; + Vector vecShootDir; + Vector vecShootOrigin; switch( pEvent->event ) { case HGRUNT_AE_DROP_GUN: { - Vector vecGunPos; - Vector vecGunAngles; + Vector vecGunPos; + Vector vecGunAngles; GetAttachment( 0, vecGunPos, vecGunAngles ); @@ -853,7 +858,7 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) SetBodygroup( GUN_GROUP, GUN_NONE ); // now spawn a gun. - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) { DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); } @@ -861,21 +866,22 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) { DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); } - if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) + + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM ); m_cAmmoLoaded = m_cClipSize; - ClearConditions(bits_COND_NO_AMMO_LOADED); + 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, 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; @@ -883,13 +889,12 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) // !!!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); + 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) + 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. @@ -903,28 +908,28 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; case HGRUNT_AE_BURST1: { - if ( FBitSet( pev->weapons, HGRUNT_9MMAR )) + 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) ) + if( RANDOM_LONG( 0, 1 ) ) { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM ); } } else { - Shotgun( ); + Shotgun(); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); } - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); + + CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); } break; case HGRUNT_AE_BURST2: @@ -935,7 +940,7 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) { CBaseEntity *pHurt = Kick(); - if ( pHurt ) + if( pHurt ) { // SOUND HERE! UTIL_MakeVectors( pev->angles ); @@ -947,10 +952,10 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; case HGRUNT_AE_CAUGHT_ENEMY: { - if ( FOkToSpeak() ) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); + SENTENCEG_PlayRndSz( ENT( pev ), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); + JustSpoke(); } } @@ -963,32 +968,32 @@ void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CHGrunt :: Spawn() +void CHGrunt::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + SET_MODEL( ENT( pev ), "models/hgrunt.mdl" ); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_RED; pev->effects = 0; - pev->health = gSkillData.hgruntHealth; + 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_flNextGrenadeCheck = gpGlobals->time + 1; m_flNextPainTime = gpGlobals->time; - m_iSentence = HGRUNT_SENT_NONE; + 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 ); + m_HackedGunPos = Vector( 0, 0, 55 ); - if (pev->weapons == 0) + if( pev->weapons == 0 ) { // initialize to original values pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE; @@ -996,27 +1001,27 @@ void CHGrunt :: Spawn() // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; } - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) { SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - m_cClipSize = 8; + m_cClipSize = 8; } else { - m_cClipSize = GRUNT_CLIP_SIZE; + m_cClipSize = GRUNT_CLIP_SIZE; } - m_cAmmoLoaded = m_cClipSize; + m_cAmmoLoaded = m_cClipSize; - if (RANDOM_LONG( 0, 99 ) < 80) + if( RANDOM_LONG( 0, 99 ) < 80 ) pev->skin = 0; // light skin else pev->skin = 1; // dark skin - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) + if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) { - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); + SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN ); } - else if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) + else if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ) ) { SetBodygroup( HEAD_GROUP, HEAD_M203 ); pev->skin = 1; // alway dark skin @@ -1030,9 +1035,9 @@ void CHGrunt :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CHGrunt :: Precache() +void CHGrunt::Precache() { - PRECACHE_MODEL("models/hgrunt.mdl"); + PRECACHE_MODEL( "models/hgrunt.mdl" ); PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" ); PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" ); @@ -1053,29 +1058,29 @@ void CHGrunt :: Precache() PRECACHE_SOUND( "weapons/sbarrel1.wav" ); - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + 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); + 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"); -} + m_iBrassShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell + m_iShotgunShell = PRECACHE_MODEL( "models/shotgunshell.mdl" ); +} //========================================================= // start task //========================================================= -void CHGrunt :: StartTask ( Task_t *pTask ) +void CHGrunt::StartTask( Task_t *pTask ) { m_iTaskStatus = TASKSTATUS_RUNNING; - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_GRUNT_CHECK_FIRE: - if ( !NoFriendlyFire() ) + if( !NoFriendlyFire() ) { SetConditions( bits_COND_GRUNT_NOFIRE ); } @@ -1089,7 +1094,7 @@ void CHGrunt :: StartTask ( Task_t *pTask ) case TASK_RUN_PATH: // grunt no longer assumes he is covered if he moves Forget( bits_MEMORY_INCOVER ); - CSquadMonster ::StartTask( pTask ); + CSquadMonster::StartTask( pTask ); break; case TASK_RELOAD: m_IdealActivity = ACT_RELOAD; @@ -1098,14 +1103,14 @@ void CHGrunt :: StartTask ( Task_t *pTask ) break; case TASK_FACE_IDEAL: case TASK_FACE_ENEMY: - CSquadMonster :: StartTask( pTask ); - if (pev->movetype == MOVETYPE_FLY) + CSquadMonster::StartTask( pTask ); + if( pev->movetype == MOVETYPE_FLY ) { m_IdealActivity = ACT_GLIDE; } break; default: - CSquadMonster :: StartTask( pTask ); + CSquadMonster::StartTask( pTask ); break; } } @@ -1113,9 +1118,9 @@ void CHGrunt :: StartTask ( Task_t *pTask ) //========================================================= // RunTask //========================================================= -void CHGrunt :: RunTask ( Task_t *pTask ) +void CHGrunt::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_GRUNT_FACE_TOSS_DIR: { @@ -1123,7 +1128,7 @@ void CHGrunt :: RunTask ( Task_t *pTask ) MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); ChangeYaw( pev->yaw_speed ); - if ( FacingIdeal() ) + if( FacingIdeal() ) { m_iTaskStatus = TASKSTATUS_COMPLETE; } @@ -1131,7 +1136,7 @@ void CHGrunt :: RunTask ( Task_t *pTask ) } default: { - CSquadMonster :: RunTask( pTask ); + CSquadMonster::RunTask( pTask ); break; } } @@ -1140,38 +1145,38 @@ void CHGrunt :: RunTask ( Task_t *pTask ) //========================================================= // PainSound //========================================================= -void CHGrunt :: PainSound ( void ) +void CHGrunt::PainSound( void ) { - if ( gpGlobals->time > m_flNextPainTime ) + if( gpGlobals->time > m_flNextPainTime ) { #if 0 - if ( RANDOM_LONG(0,99) < 5 ) + if( RANDOM_LONG( 0, 99 ) < 5 ) { // pain sentences are rare - if (FOkToSpeak()) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); + SENTENCEG_PlayRndSz( ENT( pev ), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM ); JustSpoke(); return; } } #endif - switch ( RANDOM_LONG(0,6) ) + switch( RANDOM_LONG( 0, 6 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); break; } @@ -1182,18 +1187,18 @@ void CHGrunt :: PainSound ( void ) //========================================================= // DeathSound //========================================================= -void CHGrunt :: DeathSound ( void ) +void CHGrunt::DeathSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); break; } } @@ -1205,19 +1210,19 @@ void CHGrunt :: DeathSound ( void ) //========================================================= // GruntFail //========================================================= -Task_t tlGruntFail[] = +Task_t tlGruntFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slGruntFail[] = +Schedule_t slGruntFail[] = { { tlGruntFail, - ARRAYSIZE ( tlGruntFail ), + ARRAYSIZE( tlGruntFail ), bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK1 | @@ -1230,20 +1235,20 @@ Schedule_t slGruntFail[] = //========================================================= // Grunt Combat Fail //========================================================= -Task_t tlGruntCombatFail[] = +Task_t tlGruntCombatFail[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)2 }, + { TASK_WAIT_PVS, (float)0 }, }; -Schedule_t slGruntCombatFail[] = +Schedule_t slGruntCombatFail[] = { { tlGruntCombatFail, - ARRAYSIZE ( tlGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | + ARRAYSIZE( tlGruntCombatFail ), + bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2, 0, "Grunt Combat Fail" @@ -1253,23 +1258,23 @@ Schedule_t slGruntCombatFail[] = //========================================================= // Victory dance! //========================================================= -Task_t tlGruntVictoryDance[] = +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 }, + { 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[] = +Schedule_t slGruntVictoryDance[] = { - { + { tlGruntVictoryDance, - ARRAYSIZE ( tlGruntVictoryDance ), + ARRAYSIZE( tlGruntVictoryDance ), bits_COND_NEW_ENEMY | bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, @@ -1284,26 +1289,25 @@ Schedule_t slGruntVictoryDance[] = //========================================================= 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 }, + { 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 | + 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" }, @@ -1313,20 +1317,19 @@ Schedule_t slGruntEstablishLineOfFire[] = // GruntFoundEnemy - grunt established sight with an enemy // that was hiding from the squad. //========================================================= -Task_t tlGruntFoundEnemy[] = +Task_t tlGruntFoundEnemy[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL1 }, }; -Schedule_t slGruntFoundEnemy[] = +Schedule_t slGruntFoundEnemy[] = { - { + { tlGruntFoundEnemy, - ARRAYSIZE ( tlGruntFoundEnemy ), + ARRAYSIZE( tlGruntFoundEnemy ), bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, "GruntFoundEnemy" }, @@ -1335,23 +1338,23 @@ Schedule_t slGruntFoundEnemy[] = //========================================================= // GruntCombatFace Schedule //========================================================= -Task_t tlGruntCombatFace1[] = +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 }, + { 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[] = +Schedule_t slGruntCombatFace[] = { - { + { tlGruntCombatFace1, - ARRAYSIZE ( tlGruntCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | + ARRAYSIZE( tlGruntCombatFace1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2, 0, "Combat Face" @@ -1362,77 +1365,75 @@ Schedule_t slGruntCombatFace[] = // Suppressing fire - don't stop shooting until the clip is // empty or grunt gets hurt. //========================================================= -Task_t tlGruntSignalSuppress[] = +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 }, + { 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[] = +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 | + 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_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 }, + { 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[] = +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 | + 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" }, @@ -1443,25 +1444,24 @@ Schedule_t slGruntSuppress[] = // 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_t tlGruntWaitInCover[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_WAIT_FACE_ENEMY, (float)1 }, }; -Schedule_t slGruntWaitInCover[] = +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 | + 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" }, @@ -1471,20 +1471,20 @@ Schedule_t slGruntWaitInCover[] = // run to cover. // !!!BUGBUG - set a decent fail schedule here. //========================================================= -Task_t tlGruntTakeCover1[] = +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 }, + { 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[] = +Schedule_t slGruntTakeCover[] = { { tlGruntTakeCover1, @@ -1498,23 +1498,23 @@ Schedule_t slGruntTakeCover[] = //========================================================= // drop grenade then run to cover. //========================================================= -Task_t tlGruntGrenadeCover1[] = +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 }, + { 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[] = +Schedule_t slGruntGrenadeCover[] = { - { + { tlGruntGrenadeCover1, - ARRAYSIZE ( tlGruntGrenadeCover1 ), + ARRAYSIZE( tlGruntGrenadeCover1 ), 0, 0, "GrenadeCover" @@ -1524,18 +1524,18 @@ Schedule_t slGruntGrenadeCover[] = //========================================================= // drop grenade then run to cover. //========================================================= -Task_t tlGruntTossGrenadeCover1[] = +Task_t tlGruntTossGrenadeCover1[] = { - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_RANGE_ATTACK2, (float)0 }, + { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, }; -Schedule_t slGruntTossGrenadeCover[] = +Schedule_t slGruntTossGrenadeCover[] = { - { + { tlGruntTossGrenadeCover1, - ARRAYSIZE ( tlGruntTossGrenadeCover1 ), + ARRAYSIZE( tlGruntTossGrenadeCover1 ), 0, 0, "TossGrenadeCover" @@ -1545,22 +1545,22 @@ Schedule_t slGruntTossGrenadeCover[] = //========================================================= // hide from the loudest sound source (to run from grenade) //========================================================= -Task_t tlGruntTakeCoverFromBestSound[] = +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 }, + { 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[] = +Schedule_t slGruntTakeCoverFromBestSound[] = { - { + { tlGruntTakeCoverFromBestSound, - ARRAYSIZE ( tlGruntTakeCoverFromBestSound ), + ARRAYSIZE( tlGruntTakeCoverFromBestSound ), 0, 0, "GruntTakeCoverFromBestSound" @@ -1572,24 +1572,23 @@ Schedule_t slGruntTakeCoverFromBestSound[] = //========================================================= 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 }, + { 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[] = +Schedule_t slGruntHideReload[] = { { tlGruntHideReload, - ARRAYSIZE ( tlGruntHideReload ), - bits_COND_HEAVY_DAMAGE | + ARRAYSIZE( tlGruntHideReload ), + bits_COND_HEAVY_DAMAGE | bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, "GruntHideReload" } @@ -1598,31 +1597,28 @@ Schedule_t slGruntHideReload[] = //========================================================= // Do a turning sweep of the area //========================================================= -Task_t tlGruntSweep[] = +Task_t tlGruntSweep[] = { - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, + { TASK_TURN_LEFT, (float)179 }, + { TASK_WAIT, (float)1 }, + { TASK_TURN_LEFT, (float)179 }, + { TASK_WAIT, (float)1 }, }; -Schedule_t slGruntSweep[] = +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 | + 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_WORLD |// sound flags + bits_SOUND_DANGER | bits_SOUND_PLAYER, - "Grunt Sweep" }, }; @@ -1631,36 +1627,35 @@ Schedule_t slGruntSweep[] = // 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_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 }, + { 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[] = +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 | + 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" }, @@ -1670,36 +1665,35 @@ Schedule_t slGruntRangeAttack1A[] = // 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_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 }, + { 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[] = +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 | + 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" }, @@ -1709,19 +1703,19 @@ Schedule_t slGruntRangeAttack1B[] = // 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_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. + { 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[] = +Schedule_t slGruntRangeAttack2[] = { - { + { tlGruntRangeAttack2, - ARRAYSIZE ( tlGruntRangeAttack2 ), + ARRAYSIZE( tlGruntRangeAttack2 ), 0, 0, "RangeAttack2" @@ -1731,26 +1725,25 @@ Schedule_t slGruntRangeAttack2[] = //========================================================= // repel //========================================================= -Task_t tlGruntRepel[] = +Task_t tlGruntRepel[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, + { 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 | + 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_DANGER | + bits_SOUND_COMBAT | bits_SOUND_PLAYER, "Repel" }, @@ -1759,18 +1752,18 @@ Schedule_t slGruntRepel[] = //========================================================= // repel //========================================================= -Task_t tlGruntRepelAttack[] = +Task_t tlGruntRepelAttack[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, }; -Schedule_t slGruntRepelAttack[] = +Schedule_t slGruntRepelAttack[] = { - { + { tlGruntRepelAttack, - ARRAYSIZE ( tlGruntRepelAttack ), + ARRAYSIZE( tlGruntRepelAttack ), bits_COND_ENEMY_OCCLUDED, 0, "Repel Attack" @@ -1780,29 +1773,28 @@ Schedule_t slGruntRepelAttack[] = //========================================================= // repel land //========================================================= -Task_t tlGruntRepelLand[] = +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 }, + { 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[] = +Schedule_t slGruntRepelLand[] = { - { + { tlGruntRepelLand, - ARRAYSIZE ( tlGruntRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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_DANGER | + bits_SOUND_COMBAT | bits_SOUND_PLAYER, "Repel Land" }, @@ -1839,18 +1831,18 @@ IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ) //========================================================= // SetActivity //========================================================= -void CHGrunt :: SetActivity ( Activity NewActivity ) +void CHGrunt::SetActivity( Activity NewActivity ) { - int iSequence = ACTIVITY_NOT_AVAILABLE; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); + int iSequence = ACTIVITY_NOT_AVAILABLE; + void *pmodel = GET_MODEL_PTR( ENT( pev ) ); - switch ( NewActivity) + switch( NewActivity ) { case ACT_RANGE_ATTACK1: // grunt is either shooting standing or shooting crouched - if (FBitSet( pev->weapons, HGRUNT_9MMAR)) + if( FBitSet( pev->weapons, HGRUNT_9MMAR ) ) { - if ( m_fStanding ) + if( m_fStanding ) { // get aimable sequence iSequence = LookupSequence( "standing_mp5" ); @@ -1863,7 +1855,7 @@ void CHGrunt :: SetActivity ( Activity NewActivity ) } else { - if ( m_fStanding ) + if( m_fStanding ) { // get aimable sequence iSequence = LookupSequence( "standing_shotgun" ); @@ -1878,7 +1870,7 @@ void CHGrunt :: SetActivity ( Activity NewActivity ) 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 ) + if( pev->weapons & HGRUNT_HANDGRENADE ) { // get toss anim iSequence = LookupSequence( "throwgrenade" ); @@ -1890,25 +1882,25 @@ void CHGrunt :: SetActivity ( Activity NewActivity ) } break; case ACT_RUN: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) + if( pev->health <= HGRUNT_LIMP_HEALTH ) { // limp! - iSequence = LookupActivity ( ACT_RUN_HURT ); + iSequence = LookupActivity( ACT_RUN_HURT ); } else { - iSequence = LookupActivity ( NewActivity ); + iSequence = LookupActivity( NewActivity ); } break; case ACT_WALK: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) + if( pev->health <= HGRUNT_LIMP_HEALTH ) { // limp! - iSequence = LookupActivity ( ACT_WALK_HURT ); + iSequence = LookupActivity( ACT_WALK_HURT ); } else { - iSequence = LookupActivity ( NewActivity ); + iSequence = LookupActivity( NewActivity ); } break; case ACT_IDLE: @@ -1916,118 +1908,117 @@ void CHGrunt :: SetActivity ( Activity NewActivity ) { NewActivity = ACT_IDLE_ANGRY; } - iSequence = LookupActivity ( NewActivity ); + iSequence = LookupActivity( NewActivity ); break; default: - iSequence = LookupActivity ( NewActivity ); + 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( iSequence > ACTIVITY_NOT_AVAILABLE ) { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) + if( pev->sequence != iSequence || !m_fSequenceLoops ) { pev->frame = 0; } - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); + 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) + 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 ) +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->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) { - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { // just landed pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_GRUNT_REPEL_LAND ); + return GetScheduleOfType( SCHED_GRUNT_REPEL_LAND ); } else { // repel down a rope, - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_GRUNT_REPEL_ATTACK ); + if( m_MonsterState == MONSTERSTATE_COMBAT ) + return GetScheduleOfType( SCHED_GRUNT_REPEL_ATTACK ); else - return GetScheduleOfType ( SCHED_GRUNT_REPEL ); + return GetScheduleOfType( SCHED_GRUNT_REPEL ); } } // grunts place HIGH priority on running away from danger sounds. - if ( HasConditions(bits_COND_HEAR_SOUND) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound) + if( pSound ) { - if (pSound->m_iType & bits_SOUND_DANGER) + 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()) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz( ENT(pev), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + 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) )) + if( !HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & ( bits_SOUND_PLAYER | bits_SOUND_COMBAT ) ) ) { MakeIdealYaw( pSound->m_vecOrigin ); } */ } } - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: { // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } // new enemy - if ( HasConditions(bits_COND_NEW_ENEMY) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { - if ( InSquad() ) + if( InSquad() ) { MySquadLeader()->m_fEnemyEluded = FALSE; - if ( !IsLeader() ) + if( !IsLeader() ) { - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); } else { @@ -2039,57 +2030,56 @@ Schedule_t *CHGrunt :: GetSchedule( void ) // 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( FOkToSpeak() )// && RANDOM_LONG( 0, 1 ) ) { - if ((m_hEnemy != NULL) && m_hEnemy->IsPlayer()) + if( ( m_hEnemy != NULL ) && m_hEnemy->IsPlayer() ) // player - SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - else if ((m_hEnemy != NULL) && - (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) && - (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) && - (m_hEnemy->Classify() != CLASS_MACHINE)) + SENTENCEG_PlayRndSz( ENT( pev ), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); + else if( ( m_hEnemy != NULL ) && + ( 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); + SENTENCEG_PlayRndSz( ENT( pev ), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); JustSpoke(); } - - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) + + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS ); + return GetScheduleOfType( SCHED_GRUNT_SUPPRESS ); } else { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); + return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); } } } } // no ammo - else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) + 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 ); + return GetScheduleOfType( SCHED_GRUNT_COVER_AND_RELOAD ); } - // damaged just a little - else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) + else if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) { // if hurt: // 90% chance of taking cover // 10% chance of flinch. - int iPercent = RANDOM_LONG(0,99); + int iPercent = RANDOM_LONG( 0, 99 ); - if ( iPercent <= 90 && m_hEnemy != NULL ) + if( iPercent <= 90 && m_hEnemy != NULL ) { // 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)) + if( FOkToSpeak() ) // && RANDOM_LONG( 0, 1 ) ) { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + //SENTENCEG_PlayRndSz( ENT( pev ), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); m_iSentence = HGRUNT_SENT_COVER; //JustSpoke(); } @@ -2101,38 +2091,37 @@ Schedule_t *CHGrunt :: GetSchedule( void ) } } // can kick - else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) + else if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { - return GetScheduleOfType ( SCHED_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 ) ) + 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 ) ) + else if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - if ( InSquad() ) + 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 ) ) + if( MySquadLeader()->m_fEnemyEluded && !HasConditions( bits_COND_ENEMY_FACING_ME ) ) { MySquadLeader()->m_fEnemyEluded = FALSE; - return GetScheduleOfType ( SCHED_GRUNT_FOUND_ENEMY ); + return GetScheduleOfType( SCHED_GRUNT_FOUND_ENEMY ); } } - if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) ) + 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 ) ) + 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 ); @@ -2144,25 +2133,25 @@ Schedule_t *CHGrunt :: GetSchedule( void ) } } // can't see enemy - else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) + else if( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + 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()) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + 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 ) ) + 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)) + if( FOkToSpeak() )// && RANDOM_LONG( 0, 1 ) ) { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + //SENTENCEG_PlayRndSz( ENT( pev ), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); m_iSentence = HGRUNT_SENT_CHARGE; //JustSpoke(); } @@ -2174,18 +2163,18 @@ Schedule_t *CHGrunt :: GetSchedule( void ) //!!!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)) + if( FOkToSpeak() && RANDOM_LONG( 0, 1 ) ) { - SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + 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 ) ) + + if( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); + return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); } } break; @@ -2194,158 +2183,158 @@ Schedule_t *CHGrunt :: GetSchedule( void ) } // no special cases here, call the base class - return CSquadMonster :: GetSchedule(); + return CSquadMonster::GetSchedule(); } //========================================================= //========================================================= -Schedule_t* CHGrunt :: GetScheduleOfType ( int Type ) +Schedule_t *CHGrunt::GetScheduleOfType( int Type ) { - switch ( Type ) + switch( Type ) { case SCHED_TAKE_COVER_FROM_ENEMY: { - if ( InSquad() ) + if( InSquad() ) { - if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) + if( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) { - if (FOkToSpeak()) + if( FOkToSpeak() ) { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); + SENTENCEG_PlayRndSz( ENT( pev ), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); JustSpoke(); } return slGruntTossGrenadeCover; } else { - return &slGruntTakeCover[ 0 ]; + return &slGruntTakeCover[0]; } } else { - if ( RANDOM_LONG(0,1) ) + if( RANDOM_LONG( 0, 1 ) ) { - return &slGruntTakeCover[ 0 ]; + return &slGruntTakeCover[0]; } else { - return &slGruntGrenadeCover[ 0 ]; + return &slGruntGrenadeCover[0]; } } } case SCHED_TAKE_COVER_FROM_BEST_SOUND: { - return &slGruntTakeCoverFromBestSound[ 0 ]; + return &slGruntTakeCoverFromBestSound[0]; } case SCHED_GRUNT_TAKECOVER_FAILED: { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - return GetScheduleOfType ( SCHED_FAIL ); + 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 ); + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); } break; case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: { - return &slGruntEstablishLineOfFire[ 0 ]; + 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 ]; + if( RANDOM_LONG( 0, 9 ) == 0 ) + m_fStanding = RANDOM_LONG( 0, 1 ); + + if( m_fStanding ) + return &slGruntRangeAttack1B[0]; else - return &slGruntRangeAttack1A[ 0 ]; + return &slGruntRangeAttack1A[0]; } case SCHED_RANGE_ATTACK2: { - return &slGruntRangeAttack2[ 0 ]; + return &slGruntRangeAttack2[0]; } case SCHED_COMBAT_FACE: { - return &slGruntCombatFace[ 0 ]; + return &slGruntCombatFace[0]; } case SCHED_GRUNT_WAIT_FACE_ENEMY: { - return &slGruntWaitInCover[ 0 ]; + return &slGruntWaitInCover[0]; } case SCHED_GRUNT_SWEEP: { - return &slGruntSweep[ 0 ]; + return &slGruntSweep[0]; } case SCHED_GRUNT_COVER_AND_RELOAD: { - return &slGruntHideReload[ 0 ]; + return &slGruntHideReload[0]; } case SCHED_GRUNT_FOUND_ENEMY: { - return &slGruntFoundEnemy[ 0 ]; + return &slGruntFoundEnemy[0]; } case SCHED_VICTORY_DANCE: { - if ( InSquad() ) + if( InSquad() ) { - if ( !IsLeader() ) + if( !IsLeader() ) { - return &slGruntFail[ 0 ]; + return &slGruntFail[0]; } } - return &slGruntVictoryDance[ 0 ]; + return &slGruntVictoryDance[0]; } case SCHED_GRUNT_SUPPRESS: { - if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) + 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 ]; + return &slGruntSignalSuppress[0]; } else { - return &slGruntSuppress[ 0 ]; + return &slGruntSuppress[0]; } } case SCHED_FAIL: { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slGruntCombatFail[ 0 ]; + return &slGruntCombatFail[0]; } - return &slGruntFail[ 0 ]; + return &slGruntFail[0]; } case SCHED_GRUNT_REPEL: { - if (pev->velocity.z > -128) + if( pev->velocity.z > -128 ) pev->velocity.z -= 32; - return &slGruntRepel[ 0 ]; + return &slGruntRepel[0]; } case SCHED_GRUNT_REPEL_ATTACK: { - if (pev->velocity.z > -128) + if( pev->velocity.z > -128 ) pev->velocity.z -= 32; - return &slGruntRepelAttack[ 0 ]; + return &slGruntRepelAttack[0]; } case SCHED_GRUNT_REPEL_LAND: { - return &slGruntRepelLand[ 0 ]; + return &slGruntRepelLand[0]; } default: { - return CSquadMonster :: GetScheduleOfType ( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } } } @@ -2368,7 +2357,7 @@ LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ) void CHGruntRepel::Spawn( void ) { - Precache( ); + Precache(); pev->solid = SOLID_NOT; SetUse( &CHGruntRepel::RepelUse ); @@ -2380,17 +2369,17 @@ void CHGruntRepel::Precache( void ) m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); } -void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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); + 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) + 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( ); + CBaseMonster *pGrunt = pEntity->MyMonsterPointer(); pGrunt->pev->movetype = MOVETYPE_FLY; pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); pGrunt->SetActivity( ACT_GLIDE ); @@ -2398,7 +2387,7 @@ void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE pGrunt->m_vecLastPosition = tr.vecEndPos; CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); + pBeam->PointEntInit( pev->origin + Vector( 0, 0, 112 ), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); pBeam->SetThink( &CBaseEntity::SUB_Remove ); @@ -2414,11 +2403,11 @@ class CDeadHGrunt : public CBaseMonster { public: void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } + int Classify( void ) { return CLASS_HUMAN_MILITARY; } void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display -- temporary, don't need to save + int m_iPose;// which sequence to display -- temporary, don't need to save static char *m_szPoses[3]; }; @@ -2426,9 +2415,9 @@ char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "pose")) + if( FStrEq( pkvd->szKeyName, "pose" ) ) { - m_iPose = atoi(pkvd->szValue); + m_iPose = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -2440,10 +2429,10 @@ LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ) //========================================================= // ********** DeadHGrunt SPAWN ********** //========================================================= -void CDeadHGrunt :: Spawn( void ) +void CDeadHGrunt::Spawn( void ) { - PRECACHE_MODEL("models/hgrunt.mdl"); - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); + PRECACHE_MODEL( "models/hgrunt.mdl" ); + SET_MODEL( ENT( pev ), "models/hgrunt.mdl" ); pev->effects = 0; pev->yaw_speed = 8; @@ -2452,36 +2441,40 @@ void CDeadHGrunt :: Spawn( void ) pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) + if( pev->sequence == -1 ) { - ALERT ( at_console, "Dead hgrunt with bad pose\n" ); + ALERT( at_console, "Dead hgrunt with bad pose\n" ); } // Corpses have less health - pev->health = 8; + pev->health = 8; // map old bodies onto new bodies switch( pev->body ) { - case 0: // Grunt with Gun + 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 + 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 + 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 + case 3: + // Commander no Gun pev->body = 0; pev->skin = 0; SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index 368a4e07..1e7025a0 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -45,28 +45,28 @@ IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ) //========================================================= // don't let hornets gib, ever. //========================================================= -int CHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CHornet::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { // filter these bits a little. - bitsDamageType &= ~ ( DMG_ALWAYSGIB ); + bitsDamageType &= ~( DMG_ALWAYSGIB ); bitsDamageType |= DMG_NEVERGIB; - return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } //========================================================= //========================================================= -void CHornet :: Spawn( void ) +void CHornet::Spawn( void ) { Precache(); - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; pev->takedamage = DAMAGE_YES; - pev->flags |= FL_MONSTER; - pev->health = 1;// weak! - - if ( g_pGameRules->IsMultiplayer() ) + 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; @@ -78,7 +78,7 @@ void CHornet :: Spawn( void ) m_flFieldOfView = 0.9; // +- 25 degrees - if ( RANDOM_LONG ( 1, 5 ) <= 2 ) + if( RANDOM_LONG( 1, 5 ) <= 2 ) { m_iHornetType = HORNET_TYPE_RED; m_flFlySpeed = HORNET_RED_SPEED; @@ -89,17 +89,17 @@ void CHornet :: Spawn( void ) m_flFlySpeed = HORNET_ORANGE_SPEED; } - SET_MODEL(ENT( pev ), "models/hornet.mdl"); + 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 ) + if( !pSoundEnt ) pSoundEnt = edict(); - if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) ) + if( !FNullEnt( pev->owner ) && ( pev->owner->v.flags & FL_CLIENT ) ) { pev->dmg = gSkillData.plrDmgHornet; } @@ -108,14 +108,14 @@ void CHornet :: Spawn( void ) // no real owner, or owner isn't a client. pev->dmg = gSkillData.monDmgHornet; } - + pev->nextthink = gpGlobals->time + 0.1; - ResetSequenceInfo( ); + ResetSequenceInfo(); } -void CHornet :: Precache() +void CHornet::Precache() { - PRECACHE_MODEL("models/hornet.mdl"); + PRECACHE_MODEL( "models/hornet.mdl" ); PRECACHE_SOUND( "agrunt/ag_fire1.wav" ); PRECACHE_SOUND( "agrunt/ag_fire2.wav" ); @@ -130,29 +130,28 @@ void CHornet :: Precache() PRECACHE_SOUND( "hornet/ag_hornethit3.wav" ); iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" ); - iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.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 ) +int CHornet::IRelationship( CBaseEntity *pTarget ) { - if ( pTarget->pev->modelindex == pev->modelindex ) + if( pTarget->pev->modelindex == pev->modelindex ) { return R_NO; } - return CBaseMonster :: IRelationship( pTarget ); + return CBaseMonster::IRelationship( pTarget ); } //========================================================= // ID's Hornet as their owner //========================================================= -int CHornet::Classify ( void ) +int CHornet::Classify( void ) { - - if ( pev->owner && pev->owner->v.flags & FL_CLIENT) + if( pev->owner && pev->owner->v.flags & FL_CLIENT ) { return CLASS_PLAYER_BIOWEAPON; } @@ -163,7 +162,7 @@ int CHornet::Classify ( void ) //========================================================= // StartTrack - starts a hornet out tracking its target //========================================================= -void CHornet :: StartTrack ( void ) +void CHornet::StartTrack( void ) { IgniteTrail(); @@ -176,7 +175,7 @@ void CHornet :: StartTrack ( void ) //========================================================= // StartDart - starts a hornet out just flying straight. //========================================================= -void CHornet :: StartDart ( void ) +void CHornet::StartDart( void ) { IgniteTrail(); @@ -207,21 +206,21 @@ old colors WRITE_BYTE( 0 ); // r, g, b break; case HORNET_TYPE_ORANGE: - WRITE_BYTE( 0 ); // r, g, b + 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_BYTE( TE_BEAMFOLLOW ); WRITE_SHORT( entindex() ); // entity WRITE_SHORT( iHornetTrail ); // model WRITE_BYTE( 10 ); // life WRITE_BYTE( 2 ); // width - - switch ( m_iHornetType ) + + switch( m_iHornetType ) { case HORNET_TYPE_RED: WRITE_BYTE( 179 ); // r, g, b @@ -236,22 +235,21 @@ old colors } WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); } //========================================================= // Hornet is flying, gently tracking target //========================================================= -void CHornet :: TrackTarget ( void ) +void CHornet::TrackTarget( void ) { Vector vecFlightDir; Vector vecDirToEnemy; float flDelta; - StudioFrameAdvance( ); + StudioFrameAdvance(); - if (gpGlobals->time > m_flStopAttack) + if( gpGlobals->time > m_flStopAttack ) { SetTouch( NULL ); SetThink( &CBaseEntity::SUB_Remove ); @@ -260,14 +258,14 @@ void CHornet :: TrackTarget ( void ) } // UNDONE: The player pointer should come back after returning from another level - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { // enemy is dead. Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); + m_hEnemy = BestVisibleEnemy(); } - - if ( m_hEnemy != NULL && FVisible( m_hEnemy )) + + if( m_hEnemy != NULL && FVisible( m_hEnemy ) ) { m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); } @@ -278,42 +276,48 @@ void CHornet :: TrackTarget ( void ) vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); - if (pev->velocity.Length() < 0.1) + 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 ) + flDelta = DotProduct( vecFlightDir, vecDirToEnemy ); + + if( flDelta < 0.5 ) { // hafta turn wide again. play sound - switch (RANDOM_LONG(0,2)) + 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; + 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 ) + 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(); + pev->velocity = ( vecFlightDir + vecDirToEnemy ).Normalize(); - if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) ) + 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 ); + 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 ) + + switch( m_iHornetType ) { case HORNET_TYPE_RED: pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) @@ -325,32 +329,38 @@ void CHornet :: TrackTarget ( void ) break; } - pev->angles = UTIL_VecToAngles (pev->velocity); + 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 != NULL && !g_pGameRules->IsMultiplayer() ) + if( m_hEnemy != NULL && !g_pGameRules->IsMultiplayer() ) { - if ( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) + 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_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)) + 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; + 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; @@ -363,16 +373,16 @@ void CHornet :: TrackTarget ( void ) //========================================================= // Tracking Hornet hit something //========================================================= -void CHornet :: TrackTouch ( CBaseEntity *pOther ) +void CHornet::TrackTouch( CBaseEntity *pOther ) { - if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) + 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 ) + if( IRelationship( pOther ) <= R_NO ) { // hit something we don't want to hurt, so turn around. @@ -395,19 +405,25 @@ void CHornet::DartTouch( CBaseEntity *pOther ) DieTouch( pOther ); } -void CHornet::DieTouch ( CBaseEntity *pOther ) +void CHornet::DieTouch( CBaseEntity *pOther ) { - if ( pOther && pOther->pev->takedamage ) + if( pOther && pOther->pev->takedamage ) { // do the damage - switch (RANDOM_LONG(0,2)) + 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; + 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 ); } diff --git a/dlls/hornet.h b/dlls/hornet.h index 98d1710f..dc78fc40 100644 --- a/dlls/hornet.h +++ b/dlls/hornet.h @@ -35,24 +35,23 @@ 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[]; + 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 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 ); - + 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; + float m_flStopAttack; + int m_iHornetType; + float m_flFlySpeed; }; - diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 6daca286..cc63d6db 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -24,7 +24,8 @@ #include "hornet.h" #include "gamerules.h" -enum hgun_e { +enum hgun_e +{ HGUN_IDLE1 = 0, HGUN_FIDGETSWAY, HGUN_FIDGETSHAKE, @@ -46,11 +47,11 @@ BOOL CHgun::IsUseable( void ) return TRUE; } -void CHgun::Spawn( ) +void CHgun::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_HORNETGUN; - SET_MODEL(ENT(pev), "models/w_hgun.mdl"); + SET_MODEL( ENT( pev ), "models/w_hgun.mdl" ); m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE; m_iFirePhase = 0; @@ -60,24 +61,24 @@ void CHgun::Spawn( ) void CHgun::Precache( void ) { - PRECACHE_MODEL("models/v_hgun.mdl"); - PRECACHE_MODEL("models/w_hgun.mdl"); - PRECACHE_MODEL("models/p_hgun.mdl"); + 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" ); + m_usHornetFire = PRECACHE_EVENT( 1, "events/firehornet.sc" ); - UTIL_PrecacheOther("hornet"); + UTIL_PrecacheOther( "hornet" ); } int CHgun::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { #ifndef CLIENT_DLL - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { // in multiplayer, all hivehands come full. - pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; + pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = HORNET_MAX_CARRY; } #endif MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); @@ -88,9 +89,9 @@ int CHgun::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -int CHgun::GetItemInfo(ItemInfo *p) +int CHgun::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "Hornets"; p->iMaxAmmo1 = HORNET_MAX_CARRY; p->pszAmmo2 = NULL; @@ -105,7 +106,7 @@ int CHgun::GetItemInfo(ItemInfo *p) return 1; } -BOOL CHgun::Deploy( ) +BOOL CHgun::Deploy() { return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); } @@ -116,17 +117,17 @@ void CHgun::Holster( int skiplocal /* = 0 */ ) 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() ] ) + if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) { - m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = 1; + m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = 1; } } void CHgun::PrimaryAttack() { - Reload( ); + Reload(); - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { return; } @@ -149,7 +150,6 @@ void CHgun::PrimaryAttack() #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 @@ -157,7 +157,7 @@ void CHgun::PrimaryAttack() m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; - if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) + if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) { m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; } @@ -169,7 +169,7 @@ void CHgun::SecondaryAttack( void ) { Reload(); - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) { return; } @@ -181,10 +181,10 @@ void CHgun::SecondaryAttack( void ) UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; + vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; m_iFirePhase++; - switch ( m_iFirePhase ) + switch( m_iFirePhase ) { case 1: vecSrc = vecSrc + gpGlobals->v_up * 8; @@ -237,7 +237,7 @@ void CHgun::SecondaryAttack( void ) m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - // player "shoot" animation + // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; @@ -246,10 +246,10 @@ void CHgun::SecondaryAttack( void ) void CHgun::Reload( void ) { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY) + 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) + while( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time ) { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++; m_flRechargeTime += 0.5; @@ -258,19 +258,19 @@ void CHgun::Reload( void ) void CHgun::WeaponIdle( void ) { - Reload( ); + Reload(); - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) + if( flRand <= 0.75 ) { iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * ( 2 ); } - else if (flRand <= 0.875) + else if( flRand <= 0.875 ) { iAnim = HGUN_FIDGETSWAY; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index 6d62369b..f35b0740 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -66,10 +66,10 @@ enum // Monster's Anim Events Go Here //========================================================= #define HOUND_AE_WARN 1 -#define HOUND_AE_STARTATTACK 2 +#define HOUND_AE_STARTATTACK 2 #define HOUND_AE_THUMP 3 -#define HOUND_AE_ANGERSOUND1 4 -#define HOUND_AE_ANGERSOUND2 5 +#define HOUND_AE_ANGERSOUND1 4 +#define HOUND_AE_ANGERSOUND2 5 #define HOUND_AE_HOPBACK 6 #define HOUND_AE_CLOSE_EYE 7 @@ -78,28 +78,28 @@ class CHoundeye : public CSquadMonster public: void Spawn( void ); void Precache( void ); - int Classify ( void ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetYawSpeed ( void ); - void WarmUpSound ( void ); + 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 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 ); + 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 Save( CSave &save ); int Restore( CRestore &restore ); CUSTOM_SCHEDULES @@ -113,7 +113,7 @@ public: LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ) -TYPEDESCRIPTION CHoundeye::m_SaveData[] = +TYPEDESCRIPTION CHoundeye::m_SaveData[] = { DEFINE_FIELD( CHoundeye, m_iSpriteTexture, FIELD_INTEGER ), DEFINE_FIELD( CHoundeye, m_fAsleep, FIELD_BOOLEAN ), @@ -127,15 +127,15 @@ IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CHoundeye :: Classify ( void ) +int CHoundeye::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= // FValidateHintType //========================================================= -BOOL CHoundeye :: FValidateHintType ( short sHint ) +BOOL CHoundeye::FValidateHintType( short sHint ) { int i; @@ -147,33 +147,32 @@ BOOL CHoundeye :: FValidateHintType ( short sHint ) HINT_WORLD_ALIEN_BLOOD, }; - for ( i = 0 ; i < ARRAYSIZE ( sHoundHints ) ; i++ ) + for( i = 0; i < ARRAYSIZE( sHoundHints ); i++ ) { - if ( sHoundHints[ i ] == sHint ) + if( sHoundHints[i] == sHint ) { return TRUE; } } - ALERT ( at_aiconsole, "Couldn't validate hint type" ); + ALERT( at_aiconsole, "Couldn't validate hint type" ); return FALSE; } - //========================================================= // FCanActiveIdle //========================================================= -BOOL CHoundeye :: FCanActiveIdle ( void ) +BOOL CHoundeye::FCanActiveIdle( void ) { - if ( InSquad() ) + if( InSquad() ) { CSquadMonster *pSquadLeader = MySquadLeader(); - for (int i = 0; i < MAX_SQUAD_MEMBERS;i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - - if ( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE ) + 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; @@ -186,15 +185,14 @@ BOOL CHoundeye :: FCanActiveIdle ( void ) 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 ) +BOOL CHoundeye::CheckRangeAttack1( float flDot, float flDist ) { - if ( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) + if( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) { return TRUE; } @@ -205,13 +203,13 @@ BOOL CHoundeye :: CheckRangeAttack1 ( float flDot, float flDist ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CHoundeye :: SetYawSpeed ( void ) +void CHoundeye::SetYawSpeed( void ) { int ys; ys = 90; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_CROUCHIDLE://sleeping! ys = 0; @@ -234,14 +232,14 @@ void CHoundeye :: SetYawSpeed ( void ) //========================================================= // SetActivity //========================================================= -void CHoundeye :: SetActivity ( Activity NewActivity ) +void CHoundeye::SetActivity( Activity NewActivity ) { - int iSequence; + int iSequence; - if ( NewActivity == m_Activity ) + if( NewActivity == m_Activity ) return; - if ( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG(0,1) ) + if( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG( 0, 1 ) ) { // play pissed idle. iSequence = LookupSequence( "madidle" ); @@ -252,17 +250,17 @@ void CHoundeye :: SetActivity ( Activity NewActivity ) m_IdealActivity = m_Activity; // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + 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 + 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 ); + CSquadMonster::SetActivity( NewActivity ); } } @@ -270,19 +268,17 @@ void CHoundeye :: SetActivity ( Activity NewActivity ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CHoundeye::HandleAnimEvent( MonsterEvent_t *pEvent ) { - switch ( pEvent->event ) + 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; @@ -290,31 +286,25 @@ void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) pev->flags &= ~FL_ONGROUND; pev->velocity = gpGlobals->v_forward * -200; - pev->velocity.z += (0.6 * flGravity) * 0.5; - + 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); + 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); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM ); break; - case HOUND_AE_CLOSE_EYE: - if ( !m_fDontBlink ) + if( !m_fDontBlink ) { pev->skin = HOUNDEYE_EYE_FRAMES - 1; } break; - default: CSquadMonster::HandleAnimEvent( pEvent ); break; @@ -324,22 +314,22 @@ void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CHoundeye :: Spawn() +void CHoundeye::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/houndeye.mdl"); - UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) ); + SET_MODEL( ENT( pev ), "models/houndeye.mdl" ); + UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 36 ) ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_YELLOW; pev->effects = 0; - pev->health = gSkillData.houndeyeHealth; + 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_fAsleep = FALSE; // everyone spawns awake m_fDontBlink = FALSE; m_afCapability |= bits_CAP_SQUAD; @@ -349,37 +339,37 @@ void CHoundeye :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CHoundeye :: Precache() +void CHoundeye::Precache() { - PRECACHE_MODEL("models/houndeye.mdl"); + 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_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_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_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_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_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_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"); + 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" ); } @@ -387,18 +377,18 @@ void CHoundeye :: Precache() //========================================================= // IdleSound //========================================================= -void CHoundeye :: IdleSound ( void ) +void CHoundeye::IdleSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM ); break; } } @@ -406,15 +396,15 @@ void CHoundeye :: IdleSound ( void ) //========================================================= // IdleSound //========================================================= -void CHoundeye :: WarmUpSound ( void ) +void CHoundeye::WarmUpSound( void ) { - switch ( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM ); break; } } @@ -422,18 +412,18 @@ void CHoundeye :: WarmUpSound ( void ) //========================================================= // WarnSound //========================================================= -void CHoundeye :: WarnSound ( void ) +void CHoundeye::WarnSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM ); break; } } @@ -441,24 +431,23 @@ void CHoundeye :: WarnSound ( void ) //========================================================= // AlertSound //========================================================= -void CHoundeye :: AlertSound ( void ) +void CHoundeye::AlertSound( void ) { - - if ( InSquad() && !IsLeader() ) + if( InSquad() && !IsLeader() ) { return; // only leader makes ALERT sound. } - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM ); break; } } @@ -466,18 +455,18 @@ void CHoundeye :: AlertSound ( void ) //========================================================= // DeathSound //========================================================= -void CHoundeye :: DeathSound ( void ) +void CHoundeye::DeathSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM ); break; } } @@ -485,18 +474,18 @@ void CHoundeye :: DeathSound ( void ) //========================================================= // PainSound //========================================================= -void CHoundeye :: PainSound ( void ) +void CHoundeye::PainSound( void ) { - switch ( RANDOM_LONG(0,2) ) + switch( RANDOM_LONG( 0, 2 ) ) { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM ); break; } } @@ -505,75 +494,81 @@ void CHoundeye :: PainSound ( void ) // WriteBeamColor - writes a color vector to the network // based on the size of the group. //========================================================= -void CHoundeye :: WriteBeamColor ( void ) +void CHoundeye::WriteBeamColor( void ) { - BYTE bRed, bGreen, bBlue; + BYTE bRed, bGreen, bBlue; - if ( InSquad() ) + if( InSquad() ) { - switch ( SquadCount() ) + switch( SquadCount() ) { case 2: // no case for 0 or 1, cause those are impossible for monsters in Squads. - bRed = 101; - bGreen = 133; - bBlue = 221; + bRed = 101; + bGreen = 133; + bBlue = 221; break; case 3: - bRed = 67; - bGreen = 85; - bBlue = 255; + bRed = 67; + bGreen = 85; + bBlue = 255; break; case 4: - bRed = 62; - bGreen = 33; - bBlue = 211; + bRed = 62; + bGreen = 33; + bBlue = 211; break; default: - ALERT ( at_aiconsole, "Unsupported Houndeye SquadSize!\n" ); - bRed = 188; - bGreen = 220; - bBlue = 255; + 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; + bRed = 188; + bGreen = 220; + bBlue = 255; } - - WRITE_BYTE( bRed ); + + WRITE_BYTE( bRed ); WRITE_BYTE( bGreen ); - WRITE_BYTE( bBlue ); + WRITE_BYTE( bBlue ); } //========================================================= // SonicAttack //========================================================= -void CHoundeye :: SonicAttack ( void ) +void CHoundeye::SonicAttack( void ) { - float flAdjustedDamage; - float flDist; + float flAdjustedDamage; + float flDist; - switch ( RANDOM_LONG( 0, 2 ) ) + 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; + 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_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 @@ -589,12 +584,12 @@ void CHoundeye :: SonicAttack ( void ) 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_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 @@ -603,25 +598,25 @@ void CHoundeye :: SonicAttack ( void ) 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) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS ) ) != NULL ) { - if ( pEntity->pev->takedamage != DAMAGE_NO ) + if( pEntity->pev->takedamage != DAMAGE_NO ) { - if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) + 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 ) + if( SquadCount() > 1 ) { // squad gets attack bonus. flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); @@ -632,20 +627,20 @@ void CHoundeye :: SonicAttack ( void ) flAdjustedDamage = gSkillData.houndeyeDmgBlast; } - flDist = (pEntity->Center() - pev->origin).Length(); + flDist = ( pEntity->Center() - pev->origin ).Length(); flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; - if ( !FVisible( pEntity ) ) + if( !FVisible( pEntity ) ) { - if ( pEntity->IsPlayer() ) + 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" ) ) + 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; @@ -654,9 +649,9 @@ void CHoundeye :: SonicAttack ( void ) //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); - if (flAdjustedDamage > 0 ) + if( flAdjustedDamage > 0 ) { - pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); + pEntity->TakeDamage( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); } } } @@ -666,11 +661,11 @@ void CHoundeye :: SonicAttack ( void ) //========================================================= // start task //========================================================= -void CHoundeye :: StartTask ( Task_t *pTask ) +void CHoundeye::StartTask( Task_t *pTask ) { m_iTaskStatus = TASKSTATUS_RUNNING; - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_HOUND_FALL_ASLEEP: { @@ -711,14 +706,14 @@ void CHoundeye :: StartTask ( Task_t *pTask ) m_IdealActivity = ACT_RANGE_ATTACK1; /* - if ( InSquad() ) + if( InSquad() ) { // see if there is a battery to connect to. CSquadMonster *pSquad = m_pSquadLeader; - while ( pSquad ) + while( pSquad ) { - if ( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) + if( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) { // draw a beam. MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -731,7 +726,7 @@ void CHoundeye :: StartTask ( Task_t *pTask ) WRITE_BYTE( 10 ); // life WRITE_BYTE( 40 ); // width WRITE_BYTE( 10 ); // noise - WRITE_BYTE( 0 ); // r, g, b + WRITE_BYTE( 0 ); // r, g, b WRITE_BYTE( 50 ); // r, g, b WRITE_BYTE( 250); // r, g, b WRITE_BYTE( 255 ); // brightness @@ -758,7 +753,7 @@ void CHoundeye :: StartTask ( Task_t *pTask ) } default: { - CSquadMonster :: StartTask(pTask); + CSquadMonster::StartTask( pTask ); break; } } @@ -767,16 +762,16 @@ void CHoundeye :: StartTask ( Task_t *pTask ) //========================================================= // RunTask //========================================================= -void CHoundeye :: RunTask ( Task_t *pTask ) +void CHoundeye::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_HOUND_THREAT_DISPLAY: { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); } @@ -784,7 +779,7 @@ void CHoundeye :: RunTask ( Task_t *pTask ) } case TASK_HOUND_CLOSE_EYE: { - if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) + if( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) { pev->skin++; } @@ -792,7 +787,7 @@ void CHoundeye :: RunTask ( Task_t *pTask ) } case TASK_HOUND_HOP_BACK: { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); } @@ -800,26 +795,27 @@ void CHoundeye :: RunTask ( Task_t *pTask ) } case TASK_SPECIAL_ATTACK1: { - pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1); + pev->skin = RANDOM_LONG( 0, HOUNDEYE_EYE_FRAMES - 1 ); + + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - float life; - life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate)); - if (life < 0.1) life = 0.1; + 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( 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 ) + + if( m_fSequenceFinished ) { SonicAttack(); TaskComplete(); @@ -828,7 +824,7 @@ void CHoundeye :: RunTask ( Task_t *pTask ) } default: { - CSquadMonster :: RunTask(pTask); + CSquadMonster::RunTask( pTask ); break; } } @@ -837,23 +833,23 @@ void CHoundeye :: RunTask ( Task_t *pTask ) //========================================================= // PrescheduleThink //========================================================= -void CHoundeye::PrescheduleThink ( void ) +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 ) + 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( !m_fDontBlink ) { - if ( ( pev->skin == 0 ) && RANDOM_LONG(0,0x7F) == 0 ) + if( ( pev->skin == 0 ) && RANDOM_LONG( 0, 0x7F ) == 0 ) { // start blinking! pev->skin = HOUNDEYE_EYE_FRAMES - 1; } - else if ( pev->skin != 0 ) + else if( pev->skin != 0 ) { // already blinking pev->skin--; @@ -861,16 +857,16 @@ void CHoundeye::PrescheduleThink ( void ) } // if you are the leader, average the origins of each pack member to get an approximate center. - if ( IsLeader() ) + if( IsLeader() ) { CSquadMonster *pSquadMember; int iSquadCount = 0; - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - pSquadMember = MySquadMember(i); + pSquadMember = MySquadMember( i ); - if (pSquadMember) + if( pSquadMember ) { iSquadCount++; m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin; @@ -884,7 +880,7 @@ void CHoundeye::PrescheduleThink ( void ) //========================================================= // AI Schedules Specific to this monster //========================================================= -Task_t tlHoundGuardPack[] = +Task_t tlHoundGuardPack[] = { { TASK_STOP_MOVING, (float)0 }, { TASK_GUARD, (float)0 }, @@ -1142,107 +1138,106 @@ IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ) //========================================================= // GetScheduleOfType //========================================================= -Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) +Schedule_t *CHoundeye::GetScheduleOfType( int Type ) { - if ( m_fAsleep ) + if( m_fAsleep ) { // if the hound is sleeping, must wake and stand! - if ( HasConditions( bits_COND_HEAR_SOUND ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pWakeSound; pWakeSound = PBestSound(); ASSERT( pWakeSound != NULL ); - if ( pWakeSound ) + if( pWakeSound ) { - MakeIdealYaw ( pWakeSound->m_vecOrigin ); + MakeIdealYaw( pWakeSound->m_vecOrigin ); - if ( FLSoundVolume ( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) + if( FLSoundVolume( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) { // awakened by a loud sound - return &slHoundWakeUrgent[ 0 ]; + return &slHoundWakeUrgent[0]; } } // sound was not loud enough to scare the bejesus out of houndeye - return &slHoundWakeLazy[ 0 ]; + return &slHoundWakeLazy[0]; } - else if ( HasConditions( bits_COND_NEW_ENEMY ) ) + else if( HasConditions( bits_COND_NEW_ENEMY ) ) { // get up fast, to fight. - return &slHoundWakeUrgent[ 0 ]; + return &slHoundWakeUrgent[0]; } - else { // hound is waking up on its own - return &slHoundWakeLazy[ 0 ]; + return &slHoundWakeLazy[0]; } } - switch ( Type ) + switch( Type ) { case SCHED_IDLE_STAND: { // we may want to sleep instead of stand! - if ( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0,29) < 1 ) + if( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG( 0, 29 ) < 1 ) { - return &slHoundSleep[ 0 ]; + return &slHoundSleep[0]; } else { - return CSquadMonster :: GetScheduleOfType( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } } case SCHED_RANGE_ATTACK1: { - return &slHoundRangeAttack[ 0 ]; + return &slHoundRangeAttack[0]; /* - if ( InSquad() ) + if( InSquad() ) { - return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ]; + return &slHoundRangeAttack[RANDOM_LONG( 0, 1 )]; } - return &slHoundRangeAttack[ 1 ]; + return &slHoundRangeAttack[1]; */ } case SCHED_SPECIAL_ATTACK1: { - return &slHoundSpecialAttack1[ 0 ]; + return &slHoundSpecialAttack1[0]; } case SCHED_GUARD: { - return &slHoundGuardPack[ 0 ]; + return &slHoundGuardPack[0]; } case SCHED_HOUND_AGITATED: { - return &slHoundAgitated[ 0 ]; + return &slHoundAgitated[0]; } case SCHED_HOUND_HOP_RETREAT: { - return &slHoundHopRetreat[ 0 ]; + return &slHoundHopRetreat[0]; } case SCHED_FAIL: { - if ( m_MonsterState == MONSTERSTATE_COMBAT ) + if( m_MonsterState == MONSTERSTATE_COMBAT ) { - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { // client in PVS - return &slHoundCombatFailPVS[ 0 ]; + return &slHoundCombatFailPVS[0]; } else { // client has taken off! - return &slHoundCombatFailNoPVS[ 0 ]; + return &slHoundCombatFailNoPVS[0]; } } else { - return CSquadMonster :: GetScheduleOfType ( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } } default: { - return CSquadMonster :: GetScheduleOfType ( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } } } @@ -1250,45 +1245,45 @@ Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) //========================================================= // GetSchedule //========================================================= -Schedule_t *CHoundeye :: GetSchedule( void ) +Schedule_t *CHoundeye::GetSchedule( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: { // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } - if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { - if ( RANDOM_FLOAT( 0 , 1 ) <= 0.4 ) + 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 ) + if( tr.flFraction == 1.0 ) { // it's clear behind, so the hound will jump - return GetScheduleOfType ( SCHED_HOUND_HOP_RETREAT ); + return GetScheduleOfType( SCHED_HOUND_HOP_RETREAT ); } } - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); + return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); } - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { - if ( OccupySlot ( bits_SLOTS_HOUND_ATTACK ) ) + if( OccupySlot( bits_SLOTS_HOUND_ATTACK ) ) { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); + return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - return GetScheduleOfType ( SCHED_HOUND_AGITATED ); + return GetScheduleOfType( SCHED_HOUND_AGITATED ); } break; } @@ -1296,5 +1291,5 @@ Schedule_t *CHoundeye :: GetSchedule( void ) break; } - return CSquadMonster :: GetSchedule(); + return CSquadMonster::GetSchedule(); } diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index da37bc5d..cbc86d50 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -50,14 +50,14 @@ extern CGraph WorldGraph; class CIchthyosaur : public CFlyingMonster { public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); + void Spawn( void ); + void Precache( void ); + void SetYawSpeed( void ); + int Classify( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); CUSTOM_SCHEDULES - int Save( CSave &save ); + int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; @@ -70,23 +70,23 @@ public: 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 ); + void StartTask( Task_t *pTask ); + void RunTask( Task_t *pTask ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); + 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); + 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 VectorToPitch( const Vector &vec ); float FlPitchDiff( void ); float ChangePitch( int speed ); @@ -178,34 +178,34 @@ const char *CIchthyosaur::pDieSounds[] = }; #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) ); + 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 ) +void CIchthyosaur::IdleSound( void ) { EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); } -void CIchthyosaur :: AlertSound( void ) -{ +void CIchthyosaur::AlertSound( void ) +{ EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); } -void CIchthyosaur :: AttackSound( void ) +void CIchthyosaur::AttackSound( void ) { EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); } -void CIchthyosaur :: BiteSound( void ) +void CIchthyosaur::BiteSound( void ) { EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); } -void CIchthyosaur :: DeathSound( void ) +void CIchthyosaur::DeathSound( void ) { EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); } -void CIchthyosaur :: PainSound( void ) +void CIchthyosaur::PainSound( void ) { EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); } @@ -213,7 +213,7 @@ void CIchthyosaur :: PainSound( void ) //========================================================= // monster-specific tasks and states //========================================================= -enum +enum { TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, TASK_ICHTHYOSAUR_SWIM, @@ -306,7 +306,7 @@ Schedule_t slTwitchDie[] = DEFINE_CUSTOM_SCHEDULES( CIchthyosaur ) { - slSwimAround, + slSwimAround, slSwimAgitated, slCircleEnemy, slTwitchDie, @@ -318,17 +318,17 @@ IMPLEMENT_CUSTOM_SCHEDULES( CIchthyosaur, CFlyingMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CIchthyosaur :: Classify ( void ) +int CIchthyosaur::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } //========================================================= // CheckMeleeAttack1 //========================================================= -BOOL CIchthyosaur :: CheckMeleeAttack1 ( float flDot, float flDist ) +BOOL CIchthyosaur::CheckMeleeAttack1( float flDot, float flDist ) { - if ( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) + if( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) { return TRUE; } @@ -338,7 +338,7 @@ BOOL CIchthyosaur :: CheckMeleeAttack1 ( float flDot, float flDist ) void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) { // bite if we hit who we want to eat - if ( pOther == m_hEnemy ) + if( pOther == m_hEnemy ) { m_flEnemyTouched = gpGlobals->time; m_bOnAttack = TRUE; @@ -347,10 +347,10 @@ void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_bOnAttack ) ) + if( !ShouldToggle( useType, m_bOnAttack ) ) return; - if (m_bOnAttack) + if( m_bOnAttack ) { m_bOnAttack = 0; } @@ -364,9 +364,9 @@ void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE // CheckRangeAttack1 - swim in for a chomp // //========================================================= -BOOL CIchthyosaur :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CIchthyosaur::CheckRangeAttack1( float flDot, float flDist ) { - if ( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192))) + if( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192 ) ) ) { return TRUE; } @@ -378,7 +378,7 @@ BOOL CIchthyosaur :: CheckRangeAttack1 ( float flDot, float flDist ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CIchthyosaur :: SetYawSpeed ( void ) +void CIchthyosaur::SetYawSpeed( void ) { pev->yaw_speed = 100; } @@ -386,7 +386,7 @@ void CIchthyosaur :: SetYawSpeed ( void ) //========================================================= // Killed - overrides CFlyingMonster. // -void CIchthyosaur :: Killed( entvars_t *pevAttacker, int iGib ) +void CIchthyosaur::Killed( entvars_t *pevAttacker, int iGib ) { CBaseMonster::Killed( pevAttacker, iGib ); pev->velocity = Vector( 0, 0, 0 ); @@ -408,7 +408,7 @@ void CIchthyosaur::BecomeDead( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CIchthyosaur::HandleAnimEvent( MonsterEvent_t *pEvent ) { int bDidAttack = FALSE; switch( pEvent->event ) @@ -416,23 +416,23 @@ void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) case ICHTHYOSAUR_AE_SHAKE_RIGHT: case ICHTHYOSAUR_AE_SHAKE_LEFT: { - if (m_hEnemy != NULL && FVisible( m_hEnemy )) + if( m_hEnemy != NULL && 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)) + 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 ); + UTIL_MakeAimVectors( pev->angles ); - if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707) + 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()) + if( pHurt->IsPlayer() ) { pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); @@ -452,7 +452,7 @@ void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; } - if (bDidAttack) + if( bDidAttack ) { Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); @@ -462,18 +462,18 @@ void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CIchthyosaur :: Spawn() +void CIchthyosaur::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/icky.mdl"); + SET_MODEL( ENT( pev ), "models/icky.mdl" ); UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); - pev->solid = SOLID_BBOX; + pev->solid = SOLID_BBOX; pev->movetype = MOVETYPE_FLY; m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.ichthyosaurHealth; - pev->view_ofs = Vector ( 0, 0, 16 ); + 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); @@ -493,7 +493,7 @@ void CIchthyosaur :: Spawn() m_flMaxDist = 384; Vector Forward; - UTIL_MakeVectorsPrivate(pev->angles, Forward, 0, 0); + UTIL_MakeVectorsPrivate( pev->angles, Forward, 0, 0 ); pev->velocity = m_flightSpeed * Forward.Normalize(); m_SaveVelocity = pev->velocity; } @@ -501,9 +501,9 @@ void CIchthyosaur :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CIchthyosaur :: Precache() +void CIchthyosaur::Precache() { - PRECACHE_MODEL("models/icky.mdl"); + PRECACHE_MODEL( "models/icky.mdl" ); PRECACHE_SOUND_ARRAY( pIdleSounds ); PRECACHE_SOUND_ARRAY( pAlertSounds ); @@ -519,7 +519,7 @@ void CIchthyosaur :: Precache() Schedule_t* CIchthyosaur::GetSchedule() { // ALERT( at_console, "GetSchedule( )\n" ); - switch(m_MonsterState) + switch( m_MonsterState ) { case MONSTERSTATE_IDLE: m_flightSpeed = 80; @@ -532,20 +532,21 @@ Schedule_t* CIchthyosaur::GetSchedule() case MONSTERSTATE_COMBAT: m_flMaxSpeed = 400; // eat them - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + 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 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { return GetScheduleOfType( SCHED_CHASE_ENEMY ); } - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) + if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) { m_bOnAttack = TRUE; } - if ( pev->health < pev->max_health - 20 ) + if( pev->health < pev->max_health - 20 ) { m_bOnAttack = TRUE; } @@ -556,15 +557,15 @@ Schedule_t* CIchthyosaur::GetSchedule() break; } - return CFlyingMonster :: GetSchedule(); + return CFlyingMonster::GetSchedule(); } //========================================================= //========================================================= -Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) +Schedule_t *CIchthyosaur::GetScheduleOfType( int Type ) { // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); - switch ( Type ) + switch( Type ) { case SCHED_IDLE_WALK: return slSwimAround; @@ -575,10 +576,10 @@ Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) case SCHED_DIE: return slTwitchDie; case SCHED_CHASE_ENEMY: - AttackSound( ); + AttackSound(); } - return CBaseMonster :: GetScheduleOfType( Type ); + return CBaseMonster::GetScheduleOfType( Type ); } //========================================================= @@ -586,16 +587,16 @@ Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) // any necessary calculations to start the next task on the // schedule. //========================================================= -void CIchthyosaur::StartTask(Task_t *pTask) +void CIchthyosaur::StartTask( Task_t *pTask ) { - switch (pTask->iTask) + switch( pTask->iTask ) { case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: break; case TASK_ICHTHYOSAUR_SWIM: break; case TASK_SMALL_FLINCH: - if (m_idealDist > 128) + if( m_idealDist > 128 ) { m_flMaxDist = 512; m_idealDist = 512; @@ -604,35 +605,35 @@ void CIchthyosaur::StartTask(Task_t *pTask) { m_bOnAttack = TRUE; } - CFlyingMonster::StartTask(pTask); + CFlyingMonster::StartTask( pTask ); break; case TASK_ICHTHYOSAUR_FLOAT: pev->skin = EYE_BASE; SetSequenceByName( "bellyup" ); break; default: - CFlyingMonster::StartTask(pTask); + CFlyingMonster::StartTask( pTask ); break; } } -void CIchthyosaur :: RunTask ( Task_t *pTask ) +void CIchthyosaur::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { - TaskComplete( ); + TaskComplete(); } - else if (FVisible( m_hEnemy )) + else if( FVisible( m_hEnemy ) ) { - Vector vecFrom = m_hEnemy->EyePosition( ); + Vector vecFrom = m_hEnemy->EyePosition(); - Vector vecDelta = (pev->origin - vecFrom).Normalize( ); - Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize( ); + Vector vecDelta = ( pev->origin - vecFrom ).Normalize(); + Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize(); - if (DotProduct( vecSwim, m_SaveVelocity ) < 0) + if( DotProduct( vecSwim, m_SaveVelocity ) < 0 ) vecSwim = vecSwim * -1.0; Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; @@ -643,30 +644,31 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); - if (tr.flFraction > 0.5) + if( tr.flFraction > 0.5 ) vecPos = tr.vecEndPos; - m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * (vecPos - pev->origin).Normalize() * m_flightSpeed; + 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 )) + if( HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this ) ) { m_flNextAlert -= 0.1; - if (m_idealDist < m_flMaxDist) + if( m_idealDist < m_flMaxDist ) { m_idealDist += 4; } - if (m_flightSpeed > m_flMinSpeed) + + if( m_flightSpeed > m_flMinSpeed ) { m_flightSpeed -= 2; } - else if (m_flightSpeed < m_flMinSpeed) + else if( m_flightSpeed < m_flMinSpeed ) { m_flightSpeed += 2; } - if (m_flMinSpeed < m_flMaxSpeed) + if( m_flMinSpeed < m_flMaxSpeed ) { m_flMinSpeed += 0.5; } @@ -675,11 +677,11 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) { m_flNextAlert += 0.1; - if (m_idealDist > 128) + if( m_idealDist > 128 ) { m_idealDist -= 4; } - if (m_flightSpeed < m_flMaxSpeed) + if( m_flightSpeed < m_flMaxSpeed ) { m_flightSpeed += 4; } @@ -691,32 +693,31 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) m_flNextAlert = gpGlobals->time + 0.2; } - if (m_flNextAlert < gpGlobals->time) + if( m_flNextAlert < gpGlobals->time ) { - // ALERT( at_console, "AlertSound()\n"); - AlertSound( ); + // ALERT( at_console, "AlertSound()\n" ); + AlertSound(); m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); } - break; case TASK_ICHTHYOSAUR_SWIM: - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { - TaskComplete( ); + TaskComplete(); } break; case TASK_DIE: - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { pev->deadflag = DEAD_DEAD; - TaskComplete( ); + 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) + if( pev->waterlevel > 1 && pev->velocity.z < 64 ) { pev->velocity.z += 8; } @@ -727,7 +728,7 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) // ALERT( at_console, "%f\n", pev->velocity.z ); break; default: - CFlyingMonster :: RunTask ( pTask ); + CFlyingMonster::RunTask( pTask ); break; } } @@ -735,61 +736,61 @@ void CIchthyosaur :: RunTask ( Task_t *pTask ) float CIchthyosaur::VectorToPitch( const Vector &vec ) { float pitch; - if (vec.z == 0 && vec.x == 0) + 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 = (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) +void CIchthyosaur::Move( float flInterval ) { CFlyingMonster::Move( flInterval ); } float CIchthyosaur::FlPitchDiff( void ) { - float flPitchDiff; - float flCurrentPitch; + float flPitchDiff; + float flCurrentPitch; flCurrentPitch = UTIL_AngleMod( pev->angles.z ); - if ( flCurrentPitch == pev->idealpitch ) + if( flCurrentPitch == pev->idealpitch ) { return 0; } flPitchDiff = pev->idealpitch - flCurrentPitch; - if ( pev->idealpitch > flCurrentPitch ) + if( pev->idealpitch > flCurrentPitch ) { - if (flPitchDiff >= 180) + if( flPitchDiff >= 180 ) flPitchDiff = flPitchDiff - 360; } else { - if (flPitchDiff <= -180) + if( flPitchDiff <= -180 ) flPitchDiff = flPitchDiff + 360; } return flPitchDiff; } -float CIchthyosaur :: ChangePitch( int speed ) +float CIchthyosaur::ChangePitch( int speed ) { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) { float diff = FlPitchDiff(); float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) + if( m_IdealActivity != GetStoppedActivity() ) { - if (diff < -20) + if( diff < -20 ) target = 45; - else if (diff > 20) + else if( diff > 20 ) target = -45; } pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); @@ -799,16 +800,16 @@ float CIchthyosaur :: ChangePitch( int speed ) float CIchthyosaur::ChangeYaw( int speed ) { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) { float diff = FlYawDiff(); float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) + if( m_IdealActivity != GetStoppedActivity() ) { - if ( diff < -20 ) + if( diff < -20 ) target = 20; - else if ( diff > 20 ) + else if( diff > 20 ) target = -20; } pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); @@ -816,9 +817,9 @@ float CIchthyosaur::ChangeYaw( int speed ) return CFlyingMonster::ChangeYaw( speed ); } -Activity CIchthyosaur:: GetStoppedActivity( void ) +Activity CIchthyosaur::GetStoppedActivity( void ) { - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else + if( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else return ACT_IDLE; return ACT_WALK; } @@ -828,24 +829,24 @@ void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f m_SaveVelocity = vecDir * m_flightSpeed; } -void CIchthyosaur::MonsterThink ( void ) +void CIchthyosaur::MonsterThink( void ) { - CFlyingMonster::MonsterThink( ); + CFlyingMonster::MonsterThink(); - if (pev->deadflag == DEAD_NO) + if( pev->deadflag == DEAD_NO ) { - if (m_MonsterState != MONSTERSTATE_SCRIPT) + if( m_MonsterState != MONSTERSTATE_SCRIPT ) { - Swim( ); + Swim(); // blink the eye - if (m_flBlink < gpGlobals->time) + if( m_flBlink < gpGlobals->time ) { pev->skin = EYE_CLOSED; - if (m_flBlink + 0.2 < gpGlobals->time) + if( m_flBlink + 0.2 < gpGlobals->time ) { m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - if (m_bOnAttack) + if( m_bOnAttack ) pev->skin = EYE_MAD; else pev->skin = EYE_BASE; @@ -855,13 +856,13 @@ void CIchthyosaur::MonsterThink ( void ) } } -void CIchthyosaur :: Stop( void ) +void CIchthyosaur::Stop( void ) { - if (!m_bOnAttack) + if( !m_bOnAttack ) m_flightSpeed = 80.0; } -void CIchthyosaur::Swim( ) +void CIchthyosaur::Swim() { int retValue = 0; @@ -870,45 +871,45 @@ void CIchthyosaur::Swim( ) Vector Angles; Vector Forward, Right, Up; - if (FBitSet( pev->flags, FL_ONGROUND)) + 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); + UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); pev->velocity = Forward * 200 + Up * 200; return; } - if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) + if( m_bOnAttack && m_flightSpeed < m_flMaxSpeed ) { m_flightSpeed += 40; } - if (m_flightSpeed < 180) + if( m_flightSpeed < 180 ) { - if (m_IdealActivity == ACT_RUN) + if( m_IdealActivity == ACT_RUN ) SetActivity( ACT_WALK ); - if (m_IdealActivity == 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) + if( m_IdealActivity == ACT_WALK ) SetActivity( ACT_RUN ); - if (m_IdealActivity == ACT_RUN) + if( m_IdealActivity == ACT_RUN) pev->framerate = m_flightSpeed / 150.0; // ALERT( at_console, "run %.2f\n", pev->framerate ); } /* - if (!m_pBeam) + if( !m_pBeam ) { m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); - m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); + m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex() ); m_pBeam->SetEndAttachment( 1 ); m_pBeam->SetColor( 255, 180, 96 ); m_pBeam->SetBrightness( 192 ); @@ -917,27 +918,27 @@ void CIchthyosaur::Swim( ) #define PROBE_LENGTH 150 Angles = UTIL_VecToAngles( m_SaveVelocity ); Angles.x = -Angles.x; - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + 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); + 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(); + 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); + 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) + 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 if( flDot > 0 ) + pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * ( flDot + 0.5 ); else pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; @@ -946,7 +947,7 @@ void CIchthyosaur::Swim( ) // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); /* m_pBeam->SetStartPos( pev->origin + pev->velocity ); - m_pBeam->RelinkBeam( ); + m_pBeam->RelinkBeam(); */ // ALERT( at_console, "speed %f\n", m_flightSpeed ); @@ -954,26 +955,28 @@ void CIchthyosaur::Swim( ) // Smooth Pitch // - if (Angles.x > 180) + 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; + 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)) + 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)) + 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)) + if( fabs( Angles.y - pev->angles.y - 360 ) < fabs( turn ) ) { turn = Angles.y - pev->angles.y - 360; } @@ -981,9 +984,9 @@ void CIchthyosaur::Swim( ) float speed = m_flightSpeed * 0.1; // ALERT( at_console, "speed %.0f %f\n", turn, speed ); - if (fabs(turn) > speed) + if( fabs( turn ) > speed ) { - if (turn < 0.0) + if( turn < 0.0 ) { turn = -speed; } @@ -994,7 +997,7 @@ void CIchthyosaur::Swim( ) } pev->angles.y += turn; pev->angles.z -= turn; - pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); + pev->angles.y = fmod( ( pev->angles.y + 360.0 ), 360.0 ); static float yaw_adj; @@ -1007,26 +1010,27 @@ void CIchthyosaur::Swim( ) // Roll Smoothing // turn = 360; - if (fabs(Angles.z - pev->angles.z) < fabs(turn)) + 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)) + 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)) + 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) + speed = m_flightSpeed / 2 * 0.1; + + if( fabs( turn ) < speed ) { pev->angles.z += turn; } else { - if (turn < 0.0) + if( turn < 0.0 ) { pev->angles.z -= speed; } @@ -1035,27 +1039,32 @@ void CIchthyosaur::Swim( ) 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); + if( pev->angles.z < -20 ) + pev->angles.z = -20; + if( pev->angles.z > 20 ) + pev->angles.z = 20; - // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); + 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 CIchthyosaur::DoProbe( const Vector &Probe ) { - Vector WallNormal = Vector(0,0,-1); // WATER normal is Straight Down for fish. + Vector WallNormal = Vector( 0, 0, -1 ); // WATER normal is Straight Down for fish. float frac; - BOOL bBumpedSomething = ProbeZ(pev->origin, Probe, &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 ) + 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) + 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; @@ -1063,15 +1072,15 @@ Vector CIchthyosaur::DoProbe(const Vector &Probe) } } - if (bBumpedSomething && (m_hEnemy == NULL || tr.pHit != m_hEnemy->edict())) + if( bBumpedSomething && ( m_hEnemy == NULL || tr.pHit != m_hEnemy->edict() ) ) { Vector ProbeDir = Probe - pev->origin; - Vector NormalToProbeAndWallNormal = CrossProduct(ProbeDir, WallNormal); - Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir); + 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) + float SteeringForce = m_flightSpeed * ( 1 -frac ) * ( DotProduct( WallNormal.Normalize(), m_SaveVelocity.Normalize() ) ); + if( SteeringForce < 0.0 ) { SteeringForce = -SteeringForce; } @@ -1079,6 +1088,6 @@ Vector CIchthyosaur::DoProbe(const Vector &Probe) return SteeringVector; } - return Vector(0, 0, 0); + return Vector( 0, 0, 0 ); } #endif diff --git a/dlls/islave.cpp b/dlls/islave.cpp index c3bff559..cfb1df1b 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -31,13 +31,13 @@ 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_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 +#define ISLAVE_MAX_BEAMS 8 class CISlave : public CSquadMonster { @@ -45,15 +45,15 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( void ); - int IRelationship( CBaseEntity *pTarget ); + 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 ); + BOOL CheckRangeAttack1( float flDot, float flDist ); + BOOL CheckRangeAttack2( float flDot, float flDist ); void CallForHelp( 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 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 ); @@ -62,16 +62,16 @@ public: void Killed( entvars_t *pevAttacker, int iGib ); - void StartTask ( Task_t *pTask ); + void StartTask( Task_t *pTask ); Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); + Schedule_t *GetScheduleOfType( int Type ); CUSTOM_SCHEDULES int Save( CSave &save ); int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; - void ClearBeams( ); + void ClearBeams(); void ArmBeam( int side ); void WackBeam( int side, CBaseEntity *pEntity ); void ZapBeam( int side ); @@ -84,7 +84,7 @@ public: int m_iBeams; float m_flNextAttack; - int m_voicePitch; + int m_voicePitch; EHANDLE m_hDead; @@ -97,7 +97,7 @@ public: LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ) LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ) -TYPEDESCRIPTION CISlave::m_SaveData[] = +TYPEDESCRIPTION CISlave::m_SaveData[] = { DEFINE_FIELD( CISlave, m_iBravery, FIELD_INTEGER ), @@ -142,36 +142,36 @@ const char *CISlave::pDeathSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CISlave :: Classify ( void ) +int CISlave::Classify( void ) { - return CLASS_ALIEN_MILITARY; + 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 )) + 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( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) +void CISlave::CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) { // ALERT( at_aiconsole, "help " ); // skip ones not on my netname - if ( FStringNull( pev->netname )) + if( FStringNull( pev->netname ) ) return; CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ))) != NULL) + while( ( pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ) ) != NULL) { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) + float d = ( pev->origin - pEntity->pev->origin ).Length(); + if( d < flDist ) { - CBaseMonster *pMonster = pEntity->MyMonsterPointer( ); - if (pMonster) + CBaseMonster *pMonster = pEntity->MyMonsterPointer(); + if( pMonster ) { pMonster->m_afMemory |= bits_MEMORY_PROVOKED; pMonster->PushEnemy( hEnemy, vecLocation ); @@ -183,11 +183,11 @@ void CISlave :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Ve //========================================================= // ALertSound - scream //========================================================= -void CISlave :: AlertSound( void ) +void CISlave::AlertSound( void ) { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch); + SENTENCEG_PlayRndSz( ENT( pev ), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch ); CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP ); } @@ -196,72 +196,71 @@ void CISlave :: AlertSound( void ) //========================================================= // IdleSound //========================================================= -void CISlave :: IdleSound( void ) +void CISlave::IdleSound( void ) { - if (RANDOM_LONG( 0, 2 ) == 0) + if( RANDOM_LONG( 0, 2 ) == 0 ) { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch); + SENTENCEG_PlayRndSz( ENT( pev ), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch ); } #if 0 int side = RANDOM_LONG( 0, 1 ) * 2 - 1; - ClearBeams( ); + 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( 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( ); + MESSAGE_END(); - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); #endif } //========================================================= // PainSound //========================================================= -void CISlave :: PainSound( void ) +void CISlave::PainSound( void ) { - if (RANDOM_LONG( 0, 2 ) == 0) + 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 ); + 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 ) +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 ); + 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) +int CISlave::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_DANGER | + bits_SOUND_PLAYER; } void CISlave::Killed( entvars_t *pevAttacker, int iGib ) { - ClearBeams( ); + ClearBeams(); CSquadMonster::Killed( pevAttacker, iGib ); } @@ -269,11 +268,11 @@ void CISlave::Killed( entvars_t *pevAttacker, int iGib ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CISlave :: SetYawSpeed ( void ) +void CISlave::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_WALK: ys = 50; @@ -298,7 +297,7 @@ void CISlave :: SetYawSpeed ( void ) // // Returns number of events handled, 0 if none. //========================================================= -void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent ) { // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); switch( pEvent->event ) @@ -307,67 +306,66 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); - if ( pHurt ) + if( pHurt ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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 ); + 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 ); + 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 ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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 ); + 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 ); + 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) + if( g_iSkillLevel == SKILL_HARD ) pev->framerate = 1.5; UTIL_MakeAimVectors( pev->angles ); - if (m_iBeams == 0) + 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( 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( ); - + MESSAGE_END(); } - if (m_hDead != NULL) + if( m_hDead != NULL ) { WackBeam( -1, m_hDead ); WackBeam( 1, m_hDead ); @@ -376,24 +374,24 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) { ArmBeam( -1 ); ArmBeam( 1 ); - BeamGlow( ); + BeamGlow(); } - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); + 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( ); + ClearBeams(); - if (m_hDead != NULL) + if( m_hDead != NULL ) { 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 ) + if( !trace.fStartSolid ) { CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); @@ -401,7 +399,7 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ) ); + 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 ); @@ -416,16 +414,16 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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); + 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( ); + ClearBeams(); } break; default: @@ -437,9 +435,9 @@ void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // CheckRangeAttack1 - normal beam attack //========================================================= -BOOL CISlave :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CISlave::CheckRangeAttack1( float flDot, float flDist ) { - if (m_flNextAttack > gpGlobals->time) + if( m_flNextAttack > gpGlobals->time ) { return FALSE; } @@ -450,11 +448,11 @@ BOOL CISlave :: CheckRangeAttack1 ( float flDot, float flDist ) //========================================================= // CheckRangeAttack2 - check bravery and try to resurect dead comrades //========================================================= -BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) +BOOL CISlave::CheckRangeAttack2( float flDot, float flDist ) { return FALSE; - if (m_flNextAttack > gpGlobals->time) + if( m_flNextAttack > gpGlobals->time ) { return FALSE; } @@ -463,17 +461,17 @@ BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) m_iBravery = 0; CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" )) != 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()) + 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) + if( pEntity->pev->deadflag == DEAD_DEAD ) { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) + float d = ( pev->origin - pEntity->pev->origin ).Length(); + if( d < flDist ) { m_hDead = pEntity; flDist = d; @@ -486,7 +484,7 @@ BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) } } } - if (m_hDead != NULL) + if( m_hDead != NULL ) return TRUE; else return FALSE; @@ -495,29 +493,29 @@ BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) //========================================================= // StartTask //========================================================= -void CISlave :: StartTask ( Task_t *pTask ) +void CISlave::StartTask( Task_t *pTask ) { - ClearBeams( ); + ClearBeams(); - CSquadMonster :: StartTask ( pTask ); + CSquadMonster::StartTask( pTask ); } //========================================================= // Spawn //========================================================= -void CISlave :: Spawn() +void CISlave::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/islave.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + SET_MODEL( ENT( pev ), "models/islave.mdl" ); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - pev->solid = SOLID_SLIDEBOX; + 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. + 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; @@ -530,52 +528,52 @@ void CISlave :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CISlave :: Precache() +void CISlave::Precache() { int 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"); + 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( pAttackHitSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[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( pPainSounds ); i++ ) + PRECACHE_SOUND((char *)pPainSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) - PRECACHE_SOUND((char *)pDeathSounds[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) +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) + if( ( bitsDamageType & DMG_SLASH ) && pevAttacker && IRelationship( Instance( pevAttacker ) ) < R_DL ) return 0; m_afMemory |= bits_MEMORY_PROVOKED; - return CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); + 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) + if( bitsDamageType & DMG_SHOCK ) return; CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); @@ -616,49 +614,49 @@ IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ) //========================================================= //========================================================= -Schedule_t *CISlave :: GetSchedule( void ) +Schedule_t *CISlave::GetSchedule( void ) { - ClearBeams( ); + ClearBeams(); /* - if (pev->spawnflags) + if( pev->spawnflags ) { pev->spawnflags = 0; return GetScheduleOfType( SCHED_RELOAD ); } */ - if ( HasConditions( bits_COND_HEAR_SOUND ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - if ( pSound->m_iType & bits_SOUND_COMBAT ) + if( pSound->m_iType & bits_SOUND_COMBAT ) m_afMemory |= bits_MEMORY_PROVOKED; } - switch (m_MonsterState) + switch( m_MonsterState ) { case MONSTERSTATE_COMBAT: // dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); + return CBaseMonster::GetSchedule(); } - if (pev->health < 20 || m_iBravery < 0) + if( pev->health < 20 || m_iBravery < 0 ) { - if (!HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) + if( !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { m_failSchedule = SCHED_CHASE_ENEMY; - if (HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) + 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 ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) && HasConditions( bits_COND_ENEMY_FACING_ME ) ) { // ALERT( at_console, "exposed\n"); return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); @@ -669,17 +667,17 @@ Schedule_t *CISlave :: GetSchedule( void ) default: break; } - return CSquadMonster::GetSchedule( ); + return CSquadMonster::GetSchedule(); } -Schedule_t *CISlave :: GetScheduleOfType ( int Type ) +Schedule_t *CISlave::GetScheduleOfType( int Type ) { switch( Type ) { case SCHED_FAIL: - if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { - return CSquadMonster :: GetScheduleOfType( SCHED_MELEE_ATTACK1 ); ; + return CSquadMonster::GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } break; case SCHED_RANGE_ATTACK1: @@ -687,30 +685,29 @@ Schedule_t *CISlave :: GetScheduleOfType ( int Type ) case SCHED_RANGE_ATTACK2: return slSlaveAttack1; } - return CSquadMonster :: GetScheduleOfType( Type ); + return CSquadMonster::GetScheduleOfType( Type ); } //========================================================= // ArmBeam - small beam from arm to nearby geometry //========================================================= - -void CISlave :: ArmBeam( int side ) +void CISlave::ArmBeam( int side ) { TraceResult tr; float flDist = 1.0; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) + + 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++) + 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) + UTIL_TraceLine( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1 ); + if( flDist > tr1.flFraction ) { tr = tr1; flDist = tr.flFraction; @@ -718,16 +715,16 @@ void CISlave :: ArmBeam( int side ) } // Couldn't find anything close enough - if ( flDist == 1.0 ) + 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]) + if( !m_pBeam[m_iBeams] ) return; - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); + 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 ); @@ -739,15 +736,15 @@ void CISlave :: ArmBeam( int side ) //========================================================= // BeamGlow - brighten all beams //========================================================= -void CISlave :: BeamGlow( ) +void CISlave::BeamGlow() { int b = m_iBeams * 32; - if (b > 255) + if( b > 255 ) b = 255; - for (int i = 0; i < m_iBeams; i++) + for( int i = 0; i < m_iBeams; i++ ) { - if (m_pBeam[i]->GetBrightness() != 255) + if( m_pBeam[i]->GetBrightness() != 255 ) { m_pBeam[i]->SetBrightness( b ); } @@ -757,22 +754,22 @@ void CISlave :: BeamGlow( ) //========================================================= // WackBeam - regenerate dead colleagues //========================================================= -void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) +void CISlave::WackBeam( int side, CBaseEntity *pEntity ) { Vector vecDest; float flDist = 1.0; - if (m_iBeams >= ISLAVE_MAX_BEAMS) + if( m_iBeams >= ISLAVE_MAX_BEAMS ) return; - if (pEntity == NULL) + if( pEntity == NULL ) return; m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if (!m_pBeam[m_iBeams]) + if( !m_pBeam[m_iBeams] ) return; - m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex( ) ); + 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 ); @@ -783,48 +780,48 @@ void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) //========================================================= // ZapBeam - heavy damage directly forward //========================================================= -void CISlave :: ZapBeam( int side ) +void CISlave::ZapBeam( int side ) { Vector vecSrc, vecAim; TraceResult tr; CBaseEntity *pEntity; - if (m_iBeams >= ISLAVE_MAX_BEAMS) + 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); + 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]) + if( !m_pBeam[m_iBeams] ) return; - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); + 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 = 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 ) ); + 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( ) +void CISlave::ClearBeams() { - for (int i = 0; i < ISLAVE_MAX_BEAMS; i++) + for( int i = 0; i < ISLAVE_MAX_BEAMS; i++ ) { - if (m_pBeam[i]) + if( m_pBeam[i] ) { UTIL_Remove( m_pBeam[i] ); m_pBeam[i] = NULL; @@ -833,5 +830,5 @@ void CISlave :: ClearBeams( ) m_iBeams = 0; pev->skin = 0; - STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); + STOP_SOUND( ENT( pev ), CHAN_WEAPON, "debris/zap4.wav" ); } diff --git a/dlls/items.cpp b/dlls/items.cpp index 06d657f2..d9cc7871 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -34,18 +34,18 @@ extern int gmsgItemPickup; class CWorldItem : public CBaseEntity { public: - void KeyValue(KeyValueData *pkvd ); - void Spawn( void ); - int m_iType; + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + int m_iType; }; -LINK_ENTITY_TO_CLASS(world_items, CWorldItem) +LINK_ENTITY_TO_CLASS( world_items, CWorldItem ) -void CWorldItem::KeyValue(KeyValueData *pkvd) +void CWorldItem::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "type")) + if( FStrEq( pkvd->szKeyName, "type" ) ) { - m_iType = atoi(pkvd->szValue); + m_iType = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -56,7 +56,7 @@ void CWorldItem::Spawn( void ) { CBaseEntity *pEntity = NULL; - switch (m_iType) + switch( m_iType ) { case 44: // ITEM_BATTERY: pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); @@ -72,7 +72,7 @@ void CWorldItem::Spawn( void ) break; } - if (!pEntity) + if( !pEntity ) { ALERT( at_console, "unable to create world_item %d\n", m_iType ); } @@ -83,7 +83,7 @@ void CWorldItem::Spawn( void ) pEntity->pev->spawnflags = pev->spawnflags; } - REMOVE_ENTITY(edict()); + REMOVE_ENTITY( edict() ); } void CItem::Spawn( void ) @@ -91,10 +91,10 @@ 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)); + UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 16 ) ); SetTouch( &CItem::ItemTouch ); - if (DROP_TO_FLOOR(ENT(pev)) == 0) + if( DROP_TO_FLOOR(ENT( pev ) ) == 0 ) { ALERT(at_error, "Item %s fell out of level at %f,%f,%f\n", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); UTIL_Remove( this ); @@ -107,7 +107,7 @@ extern int gEvilImpulse101; void CItem::ItemTouch( CBaseEntity *pOther ) { // if it's not a player, ignore - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { return; } @@ -115,20 +115,20 @@ void CItem::ItemTouch( CBaseEntity *pOther ) CBasePlayer *pPlayer = (CBasePlayer *)pOther; // ok, a player is touching this item, but can he have it? - if ( !g_pGameRules->CanHaveItem( pPlayer, this ) ) + if( !g_pGameRules->CanHaveItem( pPlayer, this ) ) { // no? Ignore the touch. return; } - if (MyTouch( pPlayer )) + 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 ) + if( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) { Respawn(); } @@ -137,7 +137,7 @@ void CItem::ItemTouch( CBaseEntity *pOther ) UTIL_Remove( this ); } } - else if (gEvilImpulse101) + else if( gEvilImpulse101 ) { UTIL_Remove( this ); } @@ -157,10 +157,10 @@ CBaseEntity* CItem::Respawn( void ) void CItem::Materialize( void ) { - if ( pev->effects & EF_NODRAW ) + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); pev->effects &= ~EF_NODRAW; pev->effects |= EF_MUZZLEFLASH; } @@ -174,78 +174,78 @@ class CItemSuit : public CItem { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_suit.mdl"); - CItem::Spawn( ); + Precache(); + SET_MODEL( ENT( pev ), "models/w_suit.mdl" ); + CItem::Spawn(); } void Precache( void ) { - PRECACHE_MODEL ("models/w_suit.mdl"); + PRECACHE_MODEL( "models/w_suit.mdl" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { - if ( pPlayer->pev->weapons & (1<pev->weapons & ( 1<spawnflags & SF_SUIT_SHORTLOGON ) - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon, + if( pev->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 + EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_AAx" ); // long version of suit logon - pPlayer->pev->weapons |= (1<pev->weapons |= ( 1 << WEAPON_SUIT ); return TRUE; } }; -LINK_ENTITY_TO_CLASS(item_suit, CItemSuit) +LINK_ENTITY_TO_CLASS( item_suit, CItemSuit ) class CItemBattery : public CItem { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_battery.mdl"); - CItem::Spawn( ); + Precache(); + SET_MODEL( ENT( pev ), "models/w_battery.mdl" ); + CItem::Spawn(); } void Precache( void ) { - PRECACHE_MODEL ("models/w_battery.mdl"); + PRECACHE_MODEL( "models/w_battery.mdl" ); PRECACHE_SOUND( "items/gunpickup2.wav" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { - if ( pPlayer->pev->deadflag != DEAD_NO ) + if( pPlayer->pev->deadflag != DEAD_NO ) { return FALSE; } - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue < MAX_NORMAL_BATTERY ) && + ( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) { int pct; char szcharge[64]; pPlayer->pev->armorvalue += gSkillData.batteryCapacity; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY); + 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) ); + 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 = (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; + //EMIT_SOUND_SUIT( ENT( pev ), szcharge ); + pPlayer->SetSuitUpdate( szcharge, FALSE, SUIT_NEXT_IN_30SEC); + return TRUE; } return FALSE; } @@ -257,18 +257,18 @@ class CItemAntidote : public CItem { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_antidote.mdl"); - CItem::Spawn( ); + Precache(); + SET_MODEL( ENT( pev ), "models/w_antidote.mdl" ); + CItem::Spawn(); } void Precache( void ) { - PRECACHE_MODEL ("models/w_antidote.mdl"); + PRECACHE_MODEL( "models/w_antidote.mdl" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { - pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN); - + pPlayer->SetSuitUpdate( "!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN ); + pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1; return TRUE; } @@ -280,13 +280,13 @@ class CItemSecurity : public CItem { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_security.mdl"); - CItem::Spawn( ); + Precache(); + SET_MODEL( ENT( pev ), "models/w_security.mdl" ); + CItem::Spawn(); } void Precache( void ) { - PRECACHE_MODEL ("models/w_security.mdl"); + PRECACHE_MODEL( "models/w_security.mdl" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { @@ -301,29 +301,29 @@ class CItemLongJump : public CItem { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_longjump.mdl"); - CItem::Spawn( ); + Precache(); + SET_MODEL( ENT( pev ), "models/w_longjump.mdl" ); + CItem::Spawn(); } void Precache( void ) { - PRECACHE_MODEL ("models/w_longjump.mdl"); + PRECACHE_MODEL( "models/w_longjump.mdl" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { - if ( pPlayer->m_fLongJump ) + if( pPlayer->m_fLongJump ) { return FALSE; } - if ( ( pPlayer->pev->weapons & (1<pev->weapons & ( 1 << WEAPON_SUIT ) ) ) { pPlayer->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) ); + WRITE_STRING( STRING( pev->classname ) ); MESSAGE_END(); EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? diff --git a/dlls/items.h b/dlls/items.h index 53395a55..2c31f801 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -18,11 +18,13 @@ 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; }; + 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/dlls/lights.cpp b/dlls/lights.cpp index 18602dc2..2a8b0683 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -27,23 +27,23 @@ 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 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; private: - int m_iStyle; - int m_iszPattern; + int m_iStyle; + int m_iszPattern; }; LINK_ENTITY_TO_CLASS( light, CLight ) -TYPEDESCRIPTION CLight::m_SaveData[] = +TYPEDESCRIPTION CLight::m_SaveData[] = { DEFINE_FIELD( CLight, m_iStyle, FIELD_INTEGER ), DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), @@ -54,19 +54,19 @@ IMPLEMENT_SAVERESTORE( CLight, CPointEntity ) // // Cache user-entity-field values until spawn is called. // -void CLight :: KeyValue( KeyValueData* pkvd) +void CLight::KeyValue( KeyValueData* pkvd ) { - if (FStrEq(pkvd->szKeyName, "style")) + if( FStrEq(pkvd->szKeyName, "style" ) ) { - m_iStyle = atoi(pkvd->szValue); + m_iStyle = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "pitch")) + else if( FStrEq(pkvd->szKeyName, "pitch" ) ) { - pev->angles.x = atof(pkvd->szValue); + pev->angles.x = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "pattern")) + else if( FStrEq(pkvd->szKeyName, "pattern" ) ) { m_iszPattern = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -84,45 +84,46 @@ Default style is 0 If targeted, it will toggle between on or off. */ -void CLight :: Spawn( void ) +void CLight::Spawn( void ) { - if (FStringNull(pev->targetname)) - { // inert light - REMOVE_ENTITY(ENT(pev)); + if( FStringNull( pev->targetname ) ) + { + // inert light + REMOVE_ENTITY(ENT( pev ) ); return; } - - if (m_iStyle >= 32) + + 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, (char *)STRING( m_iszPattern )); + if( FBitSet( pev->spawnflags, SF_LIGHT_START_OFF ) ) + LIGHT_STYLE( m_iStyle, "a" ); + else if( m_iszPattern ) + LIGHT_STYLE( m_iStyle, (char *)STRING( m_iszPattern ) ); else - LIGHT_STYLE(m_iStyle, "m"); + LIGHT_STYLE( m_iStyle, "m" ); } } -void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CLight::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if (m_iStyle >= 32) + if( m_iStyle >= 32 ) { - if ( !ShouldToggle( useType, !FBitSet(pev->spawnflags, SF_LIGHT_START_OFF) ) ) + if( !ShouldToggle( useType, !FBitSet( pev->spawnflags, SF_LIGHT_START_OFF ) ) ) return; - if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) + if( FBitSet( pev->spawnflags, SF_LIGHT_START_OFF ) ) { - if (m_iszPattern) - LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern )); + if( m_iszPattern ) + LIGHT_STYLE( m_iStyle, (char *)STRING( m_iszPattern ) ); else - LIGHT_STYLE(m_iStyle, "m"); - ClearBits(pev->spawnflags, SF_LIGHT_START_OFF); + 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); + LIGHT_STYLE( m_iStyle, "a" ); + SetBits( pev->spawnflags, SF_LIGHT_START_OFF ); } } } @@ -135,28 +136,28 @@ LINK_ENTITY_TO_CLASS( light_spot, CLight ) class CEnvLight : public CLight { public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); + void KeyValue( KeyValueData* pkvd ); + void Spawn( void ); }; LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ) void CEnvLight::KeyValue( KeyValueData* pkvd ) { - if (FStrEq(pkvd->szKeyName, "_light")) + 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) + if( j == 1 ) { g = b = r; } - else if (j == 4) + else if( j == 4 ) { - r = r * (v / 255.0); - g = g * (v / 255.0); - b = b * (v / 255.0); + r = r * ( v / 255.0 ); + g = g * ( v / 255.0 ); + b = b * ( v / 255.0 ); } // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling @@ -178,7 +179,7 @@ void CEnvLight::KeyValue( KeyValueData* pkvd ) } } -void CEnvLight :: Spawn( void ) +void CEnvLight::Spawn( void ) { char szVector[64]; UTIL_MakeAimVectors( pev->angles ); @@ -190,5 +191,5 @@ void CEnvLight :: Spawn( void ) sprintf( szVector, "%f", gpGlobals->v_forward.z ); CVAR_SET_STRING( "sv_skyvec_z", szVector ); - CLight::Spawn( ); + CLight::Spawn(); } diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index ca893969..38173d41 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -37,23 +37,23 @@ 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 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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_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. + 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 @@ -76,19 +76,19 @@ TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ) -void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) +void CMonsterMaker::KeyValue( KeyValueData *pkvd ) { - if ( FStrEq(pkvd->szKeyName, "monstercount") ) + if( FStrEq( pkvd->szKeyName, "monstercount" ) ) { - m_cNumMonsters = atoi(pkvd->szValue); + m_cNumMonsters = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") ) + else if( FStrEq( pkvd->szKeyName, "m_imaxlivechildren" ) ) { - m_iMaxLiveChildren = atoi(pkvd->szValue); + m_iMaxLiveChildren = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "monstertype") ) + else if( FStrEq( pkvd->szKeyName, "monstertype" ) ) { m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -97,15 +97,15 @@ void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) CBaseMonster::KeyValue( pkvd ); } -void CMonsterMaker :: Spawn( ) +void CMonsterMaker::Spawn() { pev->solid = SOLID_NOT; m_cLiveChildren = 0; Precache(); - if ( !FStringNull ( pev->targetname ) ) + if( !FStringNull( pev->targetname ) ) { - if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) + if( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) { SetUse( &CMonsterMaker::CyclicUse );// drop one monster each time we fire } @@ -114,7 +114,7 @@ void CMonsterMaker :: Spawn( ) SetUse( &CMonsterMaker::ToggleUse );// so can be turned on/off } - if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) + if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) { // start making monsters as soon as monstermaker spawns m_fActive = TRUE; @@ -135,7 +135,7 @@ void CMonsterMaker :: Spawn( ) SetThink( &CMonsterMaker::MakerThink ); } - if ( m_cNumMonsters == 1 ) + if( m_cNumMonsters == 1 ) { m_fFadeChildren = FALSE; } @@ -147,7 +147,7 @@ void CMonsterMaker :: Spawn( ) m_flGround = 0; } -void CMonsterMaker :: Precache( void ) +void CMonsterMaker::Precache( void ) { CBaseMonster::Precache(); @@ -160,20 +160,20 @@ void CMonsterMaker :: Precache( void ) void CMonsterMaker::MakeMonster( void ) { edict_t *pent; - entvars_t *pevCreate; + entvars_t *pevCreate; - if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) + 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 ) + 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 ); + UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 2048 ), ignore_monsters, ENT( pev ), &tr ); m_flGround = tr.vecEndPos.z; } @@ -183,8 +183,8 @@ void CMonsterMaker::MakeMonster( void ) mins.z = m_flGround; CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); - if ( count ) + int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT | FL_MONSTER ); + if( count ) { // don't build a stack of monsters! return; @@ -192,17 +192,17 @@ void CMonsterMaker::MakeMonster( void ) pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); - if ( FNullEnt( pent ) ) + if( FNullEnt( pent ) ) { ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); return; } - + // If I have a target, fire! - if ( !FStringNull ( pev->target ) ) + 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 ); + FireTargets( STRING( pev->target ), this, this, USE_TOGGLE, 0 ); } pevCreate = VARS( pent ); @@ -211,13 +211,13 @@ void CMonsterMaker::MakeMonster( void ) SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); // Children hit monsterclip brushes - if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) + if( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); DispatchSpawn( ENT( pevCreate ) ); pevCreate->owner = edict(); - if ( !FStringNull( pev->netname ) ) + if( !FStringNull( pev->netname ) ) { // if I have a netname (overloaded), give the child monster that name as a targetname pevCreate->targetname = pev->netname; @@ -226,7 +226,7 @@ void CMonsterMaker::MakeMonster( void ) m_cLiveChildren++;// count this monster m_cNumMonsters--; - if ( m_cNumMonsters == 0 ) + if( m_cNumMonsters == 0 ) { // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); @@ -238,7 +238,7 @@ void CMonsterMaker::MakeMonster( void ) // CyclicUse - drops one monster from the monstermaker // each time we call this. //========================================================= -void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CMonsterMaker::CyclicUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { MakeMonster(); } @@ -246,12 +246,12 @@ void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, U //========================================================= // ToggleUse - activates/deactivates the monster maker //========================================================= -void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CMonsterMaker::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_fActive ) ) + if( !ShouldToggle( useType, m_fActive ) ) return; - if ( m_fActive ) + if( m_fActive ) { m_fActive = FALSE; SetThink( NULL ); @@ -268,7 +268,7 @@ void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, //========================================================= // MakerThink - creates a new monster every so often //========================================================= -void CMonsterMaker :: MakerThink ( void ) +void CMonsterMaker::MakerThink( void ) { pev->nextthink = gpGlobals->time + m_flDelay; @@ -277,12 +277,12 @@ void CMonsterMaker :: MakerThink ( void ) //========================================================= //========================================================= -void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) +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 ) + if( !m_fFadeChildren ) { pevChild->owner = NULL; } diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index da565e6c..631eddd5 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -36,7 +36,7 @@ #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 ); +Vector VecBModelOrigin( entvars_t *pevBModel ); extern DLL_GLOBAL BOOL g_fDrawLines; extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam @@ -49,7 +49,7 @@ extern CGraph WorldGraph;// the world node graph // 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[] = +TYPEDESCRIPTION CBaseMonster::m_SaveData[] = { DEFINE_FIELD( CBaseMonster, m_hEnemy, FIELD_EHANDLE ), DEFINE_FIELD( CBaseMonster, m_hTargetEnt, FIELD_EHANDLE ), @@ -111,29 +111,29 @@ TYPEDESCRIPTION CBaseMonster::m_SaveData[] = int CBaseMonster::Save( CSave &save ) { - if ( !CBaseToggle::Save(save) ) + if( !CBaseToggle::Save( save ) ) return 0; - return save.WriteFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); + return save.WriteFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE( m_SaveData ) ); } int CBaseMonster::Restore( CRestore &restore ) { - if ( !CBaseToggle::Restore(restore) ) + if( !CBaseToggle::Restore( restore ) ) return 0; - int status = restore.ReadFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - + 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 == NULL ) + if( m_hEnemy == NULL ) m_afConditions = 0; return status; @@ -142,7 +142,7 @@ int CBaseMonster::Restore( CRestore &restore ) //========================================================= // Eat - makes a monster full for a little while. //========================================================= -void CBaseMonster :: Eat ( float flFullDuration ) +void CBaseMonster::Eat( float flFullDuration ) { m_flHungryTime = gpGlobals->time + flFullDuration; } @@ -150,9 +150,9 @@ void CBaseMonster :: Eat ( float flFullDuration ) //========================================================= // FShouldEat - returns true if a monster is hungry. //========================================================= -BOOL CBaseMonster :: FShouldEat ( void ) +BOOL CBaseMonster::FShouldEat( void ) { - if ( m_flHungryTime > gpGlobals->time ) + if( m_flHungryTime > gpGlobals->time ) { return FALSE; } @@ -165,13 +165,13 @@ BOOL CBaseMonster :: FShouldEat ( void ) // by Barnacle victims when the barnacle pulls their head // into its mouth //========================================================= -void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) +void CBaseMonster::BarnacleVictimBitten( entvars_t *pevBarnacle ) { Schedule_t *pNewSchedule; pNewSchedule = GetScheduleOfType( SCHED_BARNACLE_VICTIM_CHOMP ); - if ( pNewSchedule ) + if( pNewSchedule ) { ChangeSchedule( pNewSchedule ); } @@ -181,7 +181,7 @@ void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) // BarnacleVictimReleased - called by barnacle victims when // the host barnacle is killed. //========================================================= -void CBaseMonster :: BarnacleVictimReleased ( void ) +void CBaseMonster::BarnacleVictimReleased( void ) { m_IdealMonsterState = MONSTERSTATE_IDLE; @@ -193,20 +193,20 @@ void CBaseMonster :: BarnacleVictimReleased ( void ) // Listen - monsters dig through the active sound list for // any sounds that may interest them. (smells, too!) //========================================================= -void CBaseMonster :: Listen ( void ) +void CBaseMonster::Listen( void ) { - int iSound; - int iMySounds; + int iSound; + int iMySounds; float hearingSensitivity; CSound *pCurrentSound; m_iAudibleList = SOUNDLIST_EMPTY; - ClearConditions(bits_COND_HEAR_SOUND | bits_COND_SMELL | bits_COND_SMELL_FOOD); + ClearConditions( bits_COND_HEAR_SOUND | bits_COND_SMELL | bits_COND_SMELL_FOOD ); m_afSoundTypes = 0; iMySounds = ISoundMask(); - if ( m_pSchedule ) + if( m_pSchedule ) { //!!!WATCH THIS SPOT IF YOU ARE HAVING SOUND RELATED BUGS! // Make sure your schedule AND personal sound masks agree! @@ -217,23 +217,23 @@ void CBaseMonster :: Listen ( void ) // UNDONE: Clear these here? ClearConditions( bits_COND_HEAR_SOUND | bits_COND_SMELL_FOOD | bits_COND_SMELL ); - hearingSensitivity = HearingSensitivity( ); + hearingSensitivity = HearingSensitivity(); - while ( iSound != SOUNDLIST_EMPTY ) + while( iSound != SOUNDLIST_EMPTY ) { pCurrentSound = CSoundEnt::SoundPointerForIndex( iSound ); - if ( pCurrentSound && - ( pCurrentSound->m_iType & iMySounds ) && - ( pCurrentSound->m_vecOrigin - EarPosition() ).Length() <= pCurrentSound->m_iVolume * hearingSensitivity ) + 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 ) + //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; + //g_pSoundEnt->m_SoundPool[iSound].m_iNextAudible = m_iAudibleList; pCurrentSound->m_iNextAudible = m_iAudibleList; - - if ( pCurrentSound->FIsSound() ) + + if( pCurrentSound->FIsSound() ) { // this is an audible sound. SetConditions( bits_COND_HEAR_SOUND ); @@ -241,8 +241,8 @@ void CBaseMonster :: Listen ( void ) 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 ) ) + //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? @@ -255,13 +255,13 @@ void CBaseMonster :: Listen ( void ) SetConditions( bits_COND_SMELL ); } } - //m_afSoundTypes |= g_pSoundEnt->m_SoundPool[ iSound ].m_iType; + //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 = g_pSoundEnt->m_SoundPool[iSound].m_iNext; iSound = pCurrentSound->m_iNext; } } @@ -272,7 +272,7 @@ void CBaseMonster :: Listen ( void ) // and returns that value, which is considered to be the 'local' // volume of the sound. //========================================================= -float CBaseMonster :: FLSoundVolume ( CSound *pSound ) +float CBaseMonster::FLSoundVolume( CSound *pSound ) { return ( pSound->m_iVolume - ( ( pSound->m_vecOrigin - pev->origin ).Length() ) ); } @@ -281,7 +281,7 @@ float CBaseMonster :: FLSoundVolume ( CSound *pSound ) // FValidateHintType - tells use whether or not the monster cares // about the type of Hint Node given //========================================================= -BOOL CBaseMonster :: FValidateHintType ( short sHint ) +BOOL CBaseMonster::FValidateHintType( short sHint ) { return FALSE; } @@ -298,48 +298,48 @@ BOOL CBaseMonster :: FValidateHintType ( short sHint ) // (linked via each ent's m_pLink field) // //========================================================= -void CBaseMonster :: Look ( int iDistance ) +void CBaseMonster::Look( int iDistance ) { - int iSighted = 0; + 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); + 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 *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 ) ) + 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++ ) + 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 ) && + 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( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) { - if ( pSightEnt->IsPlayer() ) + if( pSightEnt->IsPlayer() ) { - if ( pev->spawnflags & SF_MONSTER_WAIT_TILL_SEEN ) + 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 ) ) + if( pSightEnt && !pClient->FInViewCone( this ) ) { // we're not in the player's view cone. continue; @@ -358,7 +358,7 @@ void CBaseMonster :: Look ( int iDistance ) pSightEnt->m_pLink = m_pLink; m_pLink = pSightEnt; - if ( pSightEnt == m_hEnemy ) + 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; @@ -366,24 +366,24 @@ void CBaseMonster :: Look ( int iDistance ) // 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 ) ) + switch( IRelationship( pSightEnt ) ) { - case R_NM: + case R_NM: iSighted |= bits_COND_SEE_NEMESIS; break; - case R_HT: + case R_HT: iSighted |= bits_COND_SEE_HATE; break; - case R_DL: + case R_DL: iSighted |= bits_COND_SEE_DISLIKE; break; - case R_FR: + case R_FR: iSighted |= bits_COND_SEE_FEAR; break; - case R_AL: + case R_AL: break; default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + ALERT( at_aiconsole, "%s can't assess %s\n", STRING( pev->classname ), STRING( pSightEnt->pev->classname ) ); break; } } @@ -399,45 +399,45 @@ void CBaseMonster :: Look ( int iDistance ) // of sounds this monster regards. In the base class implementation, // monsters care about all sounds, but no scents. //========================================================= -int CBaseMonster :: ISoundMask ( void ) +int CBaseMonster::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER; + 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 ) +CSound *CBaseMonster::PBestSound( void ) { int iThisSound; - int iBestSound = -1; + 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 ) + if( iThisSound == SOUNDLIST_EMPTY ) { - ALERT ( at_aiconsole, "ERROR! monster %s has no audible sounds!\n", STRING(pev->classname) ); + 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 ) + while( iThisSound != SOUNDLIST_EMPTY ) { pSound = CSoundEnt::SoundPointerForIndex( iThisSound ); - if ( pSound && pSound->FIsSound() ) + if( pSound && pSound->FIsSound() ) { - flDist = ( pSound->m_vecOrigin - EarPosition()).Length(); + flDist = ( pSound->m_vecOrigin - EarPosition() ).Length(); - if ( flDist < flBestDist ) + if( flDist < flBestDist ) { iBestSound = iThisSound; flBestDist = flDist; @@ -446,7 +446,7 @@ CSound* CBaseMonster :: PBestSound ( void ) iThisSound = pSound->m_iNextAudible; } - if ( iBestSound >= 0 ) + if( iBestSound >= 0 ) { pSound = CSoundEnt::SoundPointerForIndex( iBestSound ); return pSound; @@ -461,34 +461,34 @@ CSound* CBaseMonster :: PBestSound ( void ) // PBestScent - returns a pointer to the scent the monster // should react to. Right now responds only to nearest scent //========================================================= -CSound* CBaseMonster :: PBestScent ( void ) -{ +CSound *CBaseMonster::PBestScent( void ) +{ int iThisScent; - int iBestScent = -1; + 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 ) + if( iThisScent == SOUNDLIST_EMPTY ) { - ALERT ( at_aiconsole, "ERROR! PBestScent() has empty soundlist!\n" ); + 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 ) + while( iThisScent != SOUNDLIST_EMPTY ) { pSound = CSoundEnt::SoundPointerForIndex( iThisScent ); - if ( pSound->FIsScent() ) + if( pSound->FIsScent() ) { flDist = ( pSound->m_vecOrigin - pev->origin ).Length(); - if ( flDist < flBestDist ) + if( flDist < flBestDist ) { iBestScent = iThisScent; flBestDist = flDist; @@ -497,7 +497,7 @@ CSound* CBaseMonster :: PBestScent ( void ) iThisScent = pSound->m_iNextAudible; } - if ( iBestScent >= 0 ) + if( iBestScent >= 0 ) { pSound = CSoundEnt::SoundPointerForIndex( iBestScent ); @@ -513,7 +513,7 @@ CSound* CBaseMonster :: PBestScent ( void ) // Monster Think - calls out to core AI functions and handles this // monster's specific animation events //========================================================= -void CBaseMonster :: MonsterThink ( void ) +void CBaseMonster::MonsterThink( void ) { pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. @@ -524,39 +524,39 @@ void CBaseMonster :: MonsterThink ( void ) // 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 ) + if( m_MonsterState != MONSTERSTATE_SCRIPT && m_MonsterState != MONSTERSTATE_DEAD && m_Activity == ACT_IDLE && m_fSequenceFinished ) { int iSequence; - if ( m_fSequenceLoops ) + if( m_fSequenceLoops ) { // animation does loop, which means we're playing subtle idle. Might need to // fidget. - iSequence = LookupActivity ( m_Activity ); + 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 ); + iSequence = LookupActivityHeaviest( m_Activity ); } - if ( iSequence != ACTIVITY_NOT_AVAILABLE ) + if( iSequence != ACTIVITY_NOT_AVAILABLE ) { pev->sequence = iSequence; // Set to new anim (if it's there) - ResetSequenceInfo( ); + ResetSequenceInfo(); } } DispatchAnimEvents( flInterval ); - if ( !MovementIsComplete() ) + if( !MovementIsComplete() ) { Move( flInterval ); } #if _DEBUG else { - if ( !TaskIsRunning() && !TaskIsComplete() ) + if( !TaskIsRunning() && !TaskIsComplete() ) ALERT( at_error, "Schedule stalled!!\n" ); } #endif @@ -566,7 +566,7 @@ void CBaseMonster :: MonsterThink ( void ) // CBaseMonster - USE - will make a monster angry at whomever // activated it. //========================================================= -void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CBaseMonster::MonsterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { m_IdealMonsterState = MONSTERSTATE_ALERT; } @@ -578,17 +578,17 @@ void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, // schedule, but may not want to interrupt the schedule every // time. (Pain, for instance) //========================================================= -int CBaseMonster :: IgnoreConditions ( void ) +int CBaseMonster::IgnoreConditions( void ) { int iIgnoreConditions = 0; - if ( !FShouldEat() ) + if( !FShouldEat() ) { // not hungry? Ignore food smell. iIgnoreConditions |= bits_COND_SMELL_FOOD; } - if ( m_MonsterState == MONSTERSTATE_SCRIPT && m_pCine ) + if( m_MonsterState == MONSTERSTATE_SCRIPT && m_pCine ) iIgnoreConditions |= m_pCine->IgnoreConditions(); return iIgnoreConditions; @@ -597,7 +597,7 @@ int CBaseMonster :: IgnoreConditions ( void ) //========================================================= // RouteClear - zeroes out the monster's route array and goal //========================================================= -void CBaseMonster :: RouteClear ( void ) +void CBaseMonster::RouteClear( void ) { RouteNew(); m_movementGoal = MOVEGOAL_NONE; @@ -609,19 +609,19 @@ void CBaseMonster :: RouteClear ( void ) // Route New - clears out a route to be changed, but keeps // goal intact. //========================================================= -void CBaseMonster :: RouteNew ( void ) +void CBaseMonster::RouteNew( void ) { - m_Route[ 0 ].iType = 0; - m_iRouteIndex = 0; + m_Route[0].iType = 0; + m_iRouteIndex = 0; } //========================================================= // FRouteClear - returns TRUE is the Route is cleared out // ( invalid ) //========================================================= -BOOL CBaseMonster :: FRouteClear ( void ) +BOOL CBaseMonster::FRouteClear( void ) { - if ( m_Route[ m_iRouteIndex ].iType == 0 || m_movementGoal == MOVEGOAL_NONE ) + if( m_Route[m_iRouteIndex].iType == 0 || m_movementGoal == MOVEGOAL_NONE ) return TRUE; return FALSE; @@ -632,10 +632,10 @@ BOOL CBaseMonster :: FRouteClear ( void ) // target, this function copies as many waypoints as possible // from that path to the monster's Route array //========================================================= -BOOL CBaseMonster :: FRefreshRoute ( void ) +BOOL CBaseMonster::FRefreshRoute( void ) { CBaseEntity *pPathCorner; - int i; + int i; BOOL returnCode; RouteNew(); @@ -650,17 +650,16 @@ BOOL CBaseMonster :: FRefreshRoute ( void ) pPathCorner = m_pGoalEnt; i = 0; - while ( pPathCorner && i < ROUTE_SIZE ) + while( pPathCorner && i < ROUTE_SIZE ) { - m_Route[ i ].iType = bits_MF_TO_PATHCORNER; - m_Route[ i ].vecLocation = pPathCorner->pev->origin; + 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 ) + if( !pPathCorner ) m_Route[i].iType |= bits_MF_IS_GOAL; - i++; } } @@ -673,27 +672,26 @@ BOOL CBaseMonster :: FRefreshRoute ( void ) returnCode = BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, NULL ); break; case MOVEGOAL_TARGETENT: - if (m_hTargetEnt != NULL) + if( m_hTargetEnt != NULL ) { returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); } break; case MOVEGOAL_NODE: returnCode = FGetNodeRoute( m_vecMoveGoal ); -// if ( returnCode ) -// RouteSimplify( NULL ); + //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(); } @@ -730,24 +728,24 @@ BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vecto #ifdef _DEBUG void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ) { - int i; + int i; - if ( m_Route[m_iRouteIndex].iType == 0 ) + 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 ); + //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_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 @@ -762,19 +760,19 @@ void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, i WRITE_BYTE( 10 ); // speed MESSAGE_END(); - for ( i = m_iRouteIndex ; i < ROUTE_SIZE - 1; i++ ) + for( i = m_iRouteIndex; i < ROUTE_SIZE - 1; i++ ) { - if ( (m_Route[ i ].iType & bits_MF_IS_GOAL) || (m_Route[ i+1 ].iType == 0) ) + 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_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 @@ -788,7 +786,7 @@ void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, i WRITE_BYTE( 10 ); // speed MESSAGE_END(); -// UTIL_ParticleEffect ( m_Route[ i ].vecLocation, g_vecZero, 255, 25 ); + //UTIL_ParticleEffect( m_Route[i].vecLocation, g_vecZero, 255, 25 ); } } #endif @@ -797,7 +795,7 @@ int ShouldSimplify( int routeType ) { routeType &= ~bits_MF_IS_GOAL; - if ( (routeType == bits_MF_TO_PATHCORNER) || (routeType & bits_MF_DONT_SIMPLIFY) ) + if( ( routeType == bits_MF_TO_PATHCORNER ) || ( routeType & bits_MF_DONT_SIMPLIFY ) ) return FALSE; return TRUE; } @@ -809,26 +807,26 @@ int ShouldSimplify( int routeType ) // unnecessary nodes & cutting corners. // //========================================================= -void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) +void CBaseMonster::RouteSimplify( CBaseEntity *pTargetEnt ) { // BUGBUG: this doesn't work 100% yet - int i, count, outCount; + 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 + 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++ ) + for( i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) { - if ( !m_Route[i].iType ) + if( !m_Route[i].iType ) break; else count++; - if ( m_Route[i].iType & bits_MF_IS_GOAL ) + if( m_Route[i].iType & bits_MF_IS_GOAL ) break; } // Can't simplify a direct route! - if ( count < 2 ) + if( count < 2 ) { //DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); return; @@ -836,15 +834,15 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) outCount = 0; vecStart = pev->origin; - for ( i = 0; i < count-1; i++ ) + for( i = 0; i < count - 1; i++ ) { // Don't eliminate path_corners - if ( !ShouldSimplify( m_Route[m_iRouteIndex+i].iType ) ) + if( !ShouldSimplify( m_Route[m_iRouteIndex + i].iType ) ) { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + outRoute[outCount] = m_Route[m_iRouteIndex + i]; outCount++; } - else if ( CheckLocalMove ( vecStart, m_Route[m_iRouteIndex+i+1].vecLocation, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + else if( CheckLocalMove( vecStart, m_Route[m_iRouteIndex+i + 1].vecLocation, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { // Skip vert continue; @@ -854,18 +852,18 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) Vector vecTest, vecSplit; // Halfway between this and next - vecTest = (m_Route[m_iRouteIndex+i+1].vecLocation + m_Route[m_iRouteIndex+i].vecLocation) * 0.5; + 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; + 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 ) + 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 ) + else if( CheckLocalMove( vecSplit, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { outRoute[outCount].iType = iType; outRoute[outCount].vecLocation = vecSplit; @@ -875,35 +873,35 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) } else { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + outRoute[outCount] = m_Route[m_iRouteIndex + i]; } } // Get last point - vecStart = outRoute[ outCount ].vecLocation; + vecStart = outRoute[outCount].vecLocation; outCount++; } ASSERT( i < count ); - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; + outRoute[outCount] = m_Route[m_iRouteIndex + i]; outCount++; // Terminate outRoute[outCount].iType = 0; - ASSERT( outCount < (ROUTE_SIZE*2) ); + ASSERT( outCount < ( ROUTE_SIZE * 2 ) ); // Copy the simplified route, disable for testing m_iRouteIndex = 0; - for ( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) + for( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) { m_Route[i] = outRoute[i]; } // Terminate route - if ( i < ROUTE_SIZE ) + if( i < ROUTE_SIZE ) m_Route[i].iType = 0; // Debug, test movement code #if 0 -// if ( CVAR_GET_FLOAT( "simplify" ) != 0 ) +// if( CVAR_GET_FLOAT( "simplify" ) != 0 ) DrawRoute( pev, outRoute, 0, 255, 0, 0 ); // else DrawRoute( pev, m_Route, m_iRouteIndex, 0, 255, 0 ); @@ -915,9 +913,9 @@ void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) // right now only used when a barnacle snatches someone, so // may have some special case stuff for that. //========================================================= -BOOL CBaseMonster :: FBecomeProne ( void ) +BOOL CBaseMonster::FBecomeProne( void ) { - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) + if( FBitSet( pev->flags, FL_ONGROUND ) ) { pev->flags -= FL_ONGROUND; } @@ -929,9 +927,9 @@ BOOL CBaseMonster :: FBecomeProne ( void ) //========================================================= // CheckRangeAttack1 //========================================================= -BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) +BOOL CBaseMonster::CheckRangeAttack1( float flDot, float flDist ) { - if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 ) + if( flDist > 64 && flDist <= 784 && flDot >= 0.5 ) { return TRUE; } @@ -941,9 +939,9 @@ BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) //========================================================= // CheckRangeAttack2 //========================================================= -BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) +BOOL CBaseMonster::CheckRangeAttack2( float flDot, float flDist ) { - if ( flDist > 64 && flDist <= 512 && flDot >= 0.5 ) + if( flDist > 64 && flDist <= 512 && flDot >= 0.5 ) { return TRUE; } @@ -953,10 +951,10 @@ BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) //========================================================= // CheckMeleeAttack1 //========================================================= -BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) +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 != NULL && FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) + if( flDist <= 64 && flDot >= 0.7 && m_hEnemy != NULL && FBitSet( m_hEnemy->pev->flags, FL_ONGROUND ) ) { return TRUE; } @@ -966,9 +964,9 @@ BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) //========================================================= // CheckMeleeAttack2 //========================================================= -BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) +BOOL CBaseMonster::CheckMeleeAttack2( float flDot, float flDist ) { - if ( flDist <= 64 && flDot >= 0.7 ) + if( flDist <= 64 && flDot >= 0.7 ) { return TRUE; } @@ -979,17 +977,17 @@ BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) // 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 ) +void CBaseMonster::CheckAttacks( CBaseEntity *pTarget, float flDist ) { - Vector2D vec2LOS; - float flDot; + Vector2D vec2LOS; + float flDot; - UTIL_MakeVectors ( pev->angles ); + UTIL_MakeVectors( pev->angles ); vec2LOS = ( pTarget->pev->origin - pev->origin ).Make2D(); vec2LOS = vec2LOS.Normalize(); - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); + 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 @@ -998,24 +996,24 @@ void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) // 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( m_afCapability & bits_CAP_RANGE_ATTACK1 ) { - if ( CheckRangeAttack1 ( flDot, flDist ) ) + if( CheckRangeAttack1( flDot, flDist ) ) SetConditions( bits_COND_CAN_RANGE_ATTACK1 ); } - if ( m_afCapability & bits_CAP_RANGE_ATTACK2 ) + if( m_afCapability & bits_CAP_RANGE_ATTACK2 ) { - if ( CheckRangeAttack2 ( flDot, flDist ) ) + if( CheckRangeAttack2( flDot, flDist ) ) SetConditions( bits_COND_CAN_RANGE_ATTACK2 ); } - if ( m_afCapability & bits_CAP_MELEE_ATTACK1 ) + if( m_afCapability & bits_CAP_MELEE_ATTACK1 ) { - if ( CheckMeleeAttack1 ( flDot, flDist ) ) + if( CheckMeleeAttack1( flDot, flDist ) ) SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); } - if ( m_afCapability & bits_CAP_MELEE_ATTACK2 ) + if( m_afCapability & bits_CAP_MELEE_ATTACK2 ) { - if ( CheckMeleeAttack2 ( flDot, flDist ) ) + if( CheckMeleeAttack2( flDot, flDist ) ) SetConditions( bits_COND_CAN_MELEE_ATTACK2 ); } } @@ -1024,9 +1022,9 @@ void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) // CanCheckAttacks - prequalifies a monster to do more fine // checking of potential attacks. //========================================================= -BOOL CBaseMonster :: FCanCheckAttacks ( void ) +BOOL CBaseMonster::FCanCheckAttacks( void ) { - if ( HasConditions(bits_COND_SEE_ENEMY) && !HasConditions( bits_COND_ENEMY_TOOFAR ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions( bits_COND_ENEMY_TOOFAR ) ) { return TRUE; } @@ -1039,25 +1037,25 @@ BOOL CBaseMonster :: FCanCheckAttacks ( void ) // gets and stores data and conditions pertaining to a monster's // enemy. Returns TRUE if Enemy LKP was updated. //========================================================= -int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) +int CBaseMonster::CheckEnemy( CBaseEntity *pEnemy ) { float flDistToEnemy; - int iUpdatedLKP;// set this to TRUE if you update the EnemyLKP in this function. + int iUpdatedLKP;// set this to TRUE if you update the EnemyLKP in this function. iUpdatedLKP = FALSE; - ClearConditions ( bits_COND_ENEMY_FACING_ME ); + ClearConditions( bits_COND_ENEMY_FACING_ME ); - if ( !FVisible( pEnemy ) ) + if( !FVisible( pEnemy ) ) { - ASSERT(!HasConditions(bits_COND_SEE_ENEMY)); + ASSERT( !HasConditions( bits_COND_SEE_ENEMY ) ); SetConditions( bits_COND_ENEMY_OCCLUDED ); } else ClearConditions( bits_COND_ENEMY_OCCLUDED ); - if ( !pEnemy->IsAlive() ) + if( !pEnemy->IsAlive() ) { - SetConditions ( bits_COND_ENEMY_DEAD ); + SetConditions( bits_COND_ENEMY_DEAD ); ClearConditions( bits_COND_SEE_ENEMY | bits_COND_ENEMY_OCCLUDED ); return FALSE; } @@ -1069,19 +1067,19 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) vecEnemyPos.z += pEnemy->pev->size.z * 0.5; // distance to enemy's head - float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); - if (flDistToEnemy2 < flDistToEnemy) + 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) + float flDistToEnemy2 = ( vecEnemyPos - pev->origin ).Length(); + if( flDistToEnemy2 < flDistToEnemy ) flDistToEnemy = flDistToEnemy2; } - if ( HasConditions( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { CBaseMonster *pEnemyMonster; @@ -1090,17 +1088,17 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) pEnemyMonster = pEnemy->MyMonsterPointer(); - if ( pEnemyMonster ) + if( pEnemyMonster ) { - if ( pEnemyMonster->FInViewCone ( this ) ) + if( pEnemyMonster->FInViewCone( this ) ) { - SetConditions ( bits_COND_ENEMY_FACING_ME ); + SetConditions( bits_COND_ENEMY_FACING_ME ); } else ClearConditions( bits_COND_ENEMY_FACING_ME ); } - if (pEnemy->pev->velocity != Vector( 0, 0, 0)) + 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 ); @@ -1110,7 +1108,7 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) // UNDONE: use pev->oldorigin? } } - else if ( !HasConditions(bits_COND_ENEMY_OCCLUDED|bits_COND_SEE_ENEMY) && ( flDistToEnemy <= 256 ) ) + 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 @@ -1119,7 +1117,7 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) m_vecEnemyLKP = pEnemy->pev->origin; } - if ( flDistToEnemy >= m_flDistTooFar ) + if( flDistToEnemy >= m_flDistTooFar ) { // enemy is very far away from monster SetConditions( bits_COND_ENEMY_TOOFAR ); @@ -1127,19 +1125,19 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) else ClearConditions( bits_COND_ENEMY_TOOFAR ); - if ( FCanCheckAttacks() ) + if( FCanCheckAttacks() ) { - CheckAttacks ( m_hEnemy, flDistToEnemy ); + CheckAttacks( m_hEnemy, flDistToEnemy ); } - if ( m_movementGoal == MOVEGOAL_ENEMY ) + if( m_movementGoal == MOVEGOAL_ENEMY ) { - for ( int i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) + for( int i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) { - if ( m_Route[ i ].iType == (bits_MF_IS_GOAL|bits_MF_TO_ENEMY) ) + 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 ) + if( ( m_Route[i].vecLocation - m_vecEnemyLKP ).Length() > 80 ) { // Refresh FRefreshRoute(); @@ -1155,22 +1153,22 @@ int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) //========================================================= // PushEnemy - remember the last few enemies, always remember the player //========================================================= -void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) +void CBaseMonster::PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { int i; - if (pEnemy == NULL) + 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++) + for( i = 0; i < MAX_OLD_ENEMIES; i++ ) { - if (m_hOldEnemy[i] == pEnemy) + if( m_hOldEnemy[i] == pEnemy ) return; - if (m_hOldEnemy[i] == NULL) // someone died, reuse their slot + if( m_hOldEnemy[i] == NULL ) // someone died, reuse their slot break; } - if (i >= MAX_OLD_ENEMIES) + if( i >= MAX_OLD_ENEMIES ) return; m_hOldEnemy[i] = pEnemy; @@ -1180,18 +1178,18 @@ void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) //========================================================= // PopEnemy - try remembering the last few enemies //========================================================= -BOOL CBaseMonster :: PopEnemy( ) +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--) + for( int i = MAX_OLD_ENEMIES - 1; i >= 0; i-- ) { - if (m_hOldEnemy[i] != NULL) + if( m_hOldEnemy[i] != NULL ) { - if (m_hOldEnemy[i]->IsAlive( )) // cheat and know when they die + 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"); + // ALERT( at_console, "remembering\n" ); return TRUE; } else @@ -1206,31 +1204,31 @@ BOOL CBaseMonster :: PopEnemy( ) //========================================================= // SetActivity //========================================================= -void CBaseMonster :: SetActivity ( Activity NewActivity ) +void CBaseMonster::SetActivity( Activity NewActivity ) { - int iSequence; + int iSequence; - iSequence = LookupActivity ( NewActivity ); + iSequence = LookupActivity( NewActivity ); // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + if( iSequence > ACTIVITY_NOT_AVAILABLE ) { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) + 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)) + 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( ); + 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) + 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 @@ -1242,29 +1240,29 @@ void CBaseMonster :: SetActivity ( Activity NewActivity ) //========================================================= // SetSequenceByName //========================================================= -void CBaseMonster :: SetSequenceByName ( char *szSequence ) +void CBaseMonster::SetSequenceByName( char *szSequence ) { - int iSequence; + int iSequence; - iSequence = LookupSequence ( szSequence ); + iSequence = LookupSequence( szSequence ); // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) + if( iSequence > ACTIVITY_NOT_AVAILABLE ) { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) + if( pev->sequence != iSequence || !m_fSequenceLoops ) { pev->frame = 0; } - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); + 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) + 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) } } @@ -1282,24 +1280,24 @@ void CBaseMonster :: SetSequenceByName ( char *szSequence ) // DON"T USE SETORIGIN! //========================================================= #define LOCAL_STEP_SIZE 16 -int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) +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; + 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. + 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)) ) + if( !( pev->flags & ( FL_FLY | FL_SWIM ) ) ) { DROP_TO_FLOOR( ENT( pev ) );//make sure monster is on the floor! } @@ -1309,7 +1307,7 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn //pev->origin = vecStart; /* - if ( flDist > 1024 ) + 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 @@ -1321,23 +1319,23 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn } */ // this loop takes single steps to the goal. - for ( flStep = 0 ; flStep < flDist ; flStep += LOCAL_STEP_SIZE ) + for( flStep = 0; flStep < flDist; flStep += LOCAL_STEP_SIZE ) { stepSize = LOCAL_STEP_SIZE; - if ( (flStep + LOCAL_STEP_SIZE) >= (flDist-1) ) - stepSize = (flDist - flStep) - 1; + if( ( flStep + LOCAL_STEP_SIZE ) >= ( flDist - 1 ) ) + stepSize = ( flDist - flStep ) - 1; - //UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); + //UTIL_ParticleEffect( pev->origin, g_vecZero, 255, 25 ); - if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) + if( !WALK_MOVE( ENT( pev ), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) { // can't take the next step, fail! - if ( pflDist != NULL ) + if( pflDist != NULL ) { *pflDist = flStep; } - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) + if( pTarget && pTarget->edict() == gpGlobals->trace_ent ) { // if this step hits target ent, the move is legal. iReturn = LOCALMOVE_VALID; @@ -1346,7 +1344,7 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn 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 ) + //if( pTarget && fabs( flDist - iStep ) < LOCAL_STEP_SIZE ) // fReturn = TRUE; //else iReturn = LOCALMOVE_INVALID; @@ -1356,25 +1354,25 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn } } - if ( iReturn == LOCALMOVE_VALID && !(pev->flags & (FL_FLY|FL_SWIM) ) && (!pTarget || (pTarget->pev->flags & FL_ONGROUND)) ) + 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 ) + 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); + 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. @@ -1383,39 +1381,39 @@ int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEn return iReturn; } -float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) +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, "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)); + //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 ) + //ALERT( at_aiconsole, "Waiting %d ms\n", (int)( 1000 * flTravelTime ) ); + if( pcbeDoor->pev->targetname ) { edict_t *pentTarget = NULL; - for (;;) + for( ; ; ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pcbeDoor->pev->targetname)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pcbeDoor->pev->targetname ) ); - if ( VARS( pentTarget ) != pcbeDoor->pev ) + if( VARS( pentTarget ) != pcbeDoor->pev ) { - if (FNullEnt(pentTarget)) + if( FNullEnt( pentTarget ) ) break; - if ( FClassnameIs ( pentTarget, STRING(pcbeDoor->pev->classname) ) ) + if( FClassnameIs( pentTarget, STRING( pcbeDoor->pev->classname ) ) ) { - CBaseEntity *pDoor = Instance(pentTarget); - if ( pDoor ) - pDoor->Use(this, this, USE_ON, 0.0); + CBaseEntity *pDoor = Instance( pentTarget ); + if( pDoor ) + pDoor->Use( this, this, USE_ON, 0.0 ); } } } @@ -1430,59 +1428,58 @@ float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) // m_iRouteIndex. If it goes beyond ROUTE_SIZE, the route // is refreshed. //========================================================= -void CBaseMonster :: AdvanceRoute ( float distance ) +void CBaseMonster::AdvanceRoute( float distance ) { - - if ( m_iRouteIndex == ROUTE_SIZE - 1 ) + if( m_iRouteIndex == ROUTE_SIZE - 1 ) { // time to refresh the route. - if ( !FRefreshRoute() ) + if( !FRefreshRoute() ) { - ALERT ( at_aiconsole, "Can't Refresh Route!!\n" ); + ALERT( at_aiconsole, "Can't Refresh Route!!\n" ); } } else { - if ( ! (m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL) ) + 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 ) + 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) + 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. "); + //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 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); + WorldGraph.HashSearch( iSrcNode, iDestNode, iLink ); - if ( iLink >= 0 && WorldGraph.m_pLinkPool[iLink].m_pLinkEnt != NULL ) + 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, "A link. " ); + if( WorldGraph.HandleLinkEnt( iSrcNode, WorldGraph.m_pLinkPool[iLink].m_pLinkEnt, m_afCapability, CGraph::NODEGRAPH_DYNAMIC ) ) { - //ALERT(at_aiconsole, "usable."); + //ALERT( at_aiconsole, "usable." ); entvars_t *pevDoor = WorldGraph.m_pLinkPool[iLink].m_pLinkEnt; - if (pevDoor) + if( pevDoor ) { m_flMoveWaitFinished = OpenDoorAndWait( pevDoor ); //ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); } } } - //ALERT(at_aiconsole, "\n"); + //ALERT( at_aiconsole, "\n" ); } m_iRouteIndex++; } else // At goal!!! { - if ( distance < m_flGroundSpeed * 0.2 /* FIX */ ) + if( distance < m_flGroundSpeed * 0.2 /* FIX */ ) { MovementComplete(); } @@ -1490,21 +1487,21 @@ void CBaseMonster :: AdvanceRoute ( float distance ) } } -int CBaseMonster :: RouteClassify( int iMoveFlag ) +int CBaseMonster::RouteClassify( int iMoveFlag ) { int movementGoal; movementGoal = MOVEGOAL_NONE; - if ( iMoveFlag & bits_MF_TO_TARGETENT ) + if( iMoveFlag & bits_MF_TO_TARGETENT ) movementGoal = MOVEGOAL_TARGETENT; - else if ( iMoveFlag & bits_MF_TO_ENEMY ) + else if( iMoveFlag & bits_MF_TO_ENEMY ) movementGoal = MOVEGOAL_ENEMY; - else if ( iMoveFlag & bits_MF_TO_PATHCORNER ) + else if( iMoveFlag & bits_MF_TO_PATHCORNER ) movementGoal = MOVEGOAL_PATHCORNER; - else if ( iMoveFlag & bits_MF_TO_NODE ) + else if( iMoveFlag & bits_MF_TO_NODE ) movementGoal = MOVEGOAL_NODE; - else if ( iMoveFlag & bits_MF_TO_LOCATION ) + else if( iMoveFlag & bits_MF_TO_LOCATION ) movementGoal = MOVEGOAL_LOCATION; return movementGoal; @@ -1513,55 +1510,55 @@ int CBaseMonster :: RouteClassify( int iMoveFlag ) //========================================================= // BuildRoute //========================================================= -BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) +BOOL CBaseMonster::BuildRoute( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { - float flDist; - Vector vecApex; - int iLocalMove; + 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; + 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 ) + 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 ) ) + 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[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; + 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 ); + 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 ) ) + if( FGetNodeRoute( vecGoal ) ) { - //ALERT ( at_console, "Can get there on nodes\n" ); + //ALERT( at_console, "Can get there on nodes\n" ); m_vecMoveGoal = vecGoal; RouteSimplify( pTarget ); return TRUE; @@ -1571,28 +1568,27 @@ BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEnt 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 ) +void CBaseMonster::InsertWaypoint( Vector vecLocation, int afMoveFlags ) { - int i, type; + 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); + 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]; + 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; + m_Route[m_iRouteIndex].vecLocation = vecLocation; + m_Route[m_iRouteIndex].iType = type; } //========================================================= @@ -1602,7 +1598,7 @@ void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) // 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 ) +BOOL CBaseMonster::FTriangulate( const Vector &vecStart, const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { Vector vecDir; Vector vecForward; @@ -1611,24 +1607,24 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn 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; + 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) + if( sizeX < 24.0 ) sizeX = 24.0; - else if (sizeX > 48.0) + else if( sizeX > 48.0 ) sizeX = 48.0; sizeZ = pev->size.z; - //if (sizeZ < 24.0) + //if( sizeZ < 24.0 ) // sizeZ = 24.0; vecForward = ( vecEnd - vecStart ).Normalize(); - Vector vecDirUp(0,0,1); - vecDir = CrossProduct ( vecForward, vecDirUp); + 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, @@ -1638,19 +1634,19 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn vecLeft = pev->origin + ( vecForward * ( flDist + sizeX ) ) - vecDir * ( sizeX * 3 ); vecRight = pev->origin + ( vecForward * ( flDist + sizeX ) ) + vecDir * ( sizeX * 3 ); - if (pev->movetype == MOVETYPE_FLY) + if( pev->movetype == MOVETYPE_FLY ) { - vecTop = pev->origin + (vecForward * flDist) + (vecDirUp * sizeZ * 3); - vecBottom = pev->origin + (vecForward * flDist) - (vecDirUp * sizeZ * 3); + vecTop = pev->origin + ( vecForward * flDist ) + ( vecDirUp * sizeZ * 3 ); + vecBottom = pev->origin + ( vecForward * flDist ) - ( vecDirUp * sizeZ * 3 ); } - vecFarSide = m_Route[ m_iRouteIndex ].vecLocation; + vecFarSide = m_Route[m_iRouteIndex].vecLocation; vecDir = vecDir * sizeX * 2; - if (pev->movetype == MOVETYPE_FLY) + if( pev->movetype == MOVETYPE_FLY ) vecDirUp = vecDirUp * sizeZ * 2; - for ( i = 0 ; i < 8; i++ ) + for( i = 0; i < 8; i++ ) { // Debug, Draw the triangulation #if 0 @@ -1675,7 +1671,7 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn MESSAGE_END(); #endif #if 0 - if (pev->movetype == MOVETYPE_FLY) + if( pev->movetype == MOVETYPE_FLY ) { MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_SHOWLINE ); @@ -1698,11 +1694,11 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn MESSAGE_END(); } #endif - if ( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( CheckLocalMove ( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( pApex ) + if( pApex ) { *pApex = vecRight; } @@ -1710,11 +1706,11 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn return TRUE; } } - if ( CheckLocalMove( pev->origin, vecLeft, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( pev->origin, vecLeft, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( CheckLocalMove ( vecLeft, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( vecLeft, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( pApex ) + if( pApex ) { *pApex = vecLeft; } @@ -1723,13 +1719,13 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn } } - if (pev->movetype == MOVETYPE_FLY) + if( pev->movetype == MOVETYPE_FLY ) { - if ( CheckLocalMove( pev->origin, vecTop, pTargetEnt, NULL ) == LOCALMOVE_VALID) + if( CheckLocalMove( pev->origin, vecTop, pTargetEnt, NULL ) == LOCALMOVE_VALID) { - if ( CheckLocalMove ( vecTop, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove ( vecTop, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( pApex ) + if( pApex ) { *pApex = vecTop; //ALERT(at_aiconsole, "triangulate over\n"); @@ -1739,11 +1735,11 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn } } #if 1 - if ( CheckLocalMove( pev->origin, vecBottom, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( pev->origin, vecBottom, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( CheckLocalMove ( vecBottom, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) + if( CheckLocalMove( vecBottom, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) { - if ( pApex ) + if( pApex ) { *pApex = vecBottom; //ALERT(at_aiconsole, "triangulate under\n"); @@ -1757,7 +1753,7 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn vecRight = vecRight + vecDir; vecLeft = vecLeft - vecDir; - if (pev->movetype == MOVETYPE_FLY) + if( pev->movetype == MOVETYPE_FLY ) { vecTop = vecTop + vecDirUp; vecBottom = vecBottom - vecDirUp; @@ -1772,7 +1768,7 @@ BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEn //========================================================= #define DIST_TO_CHECK 200 -void CBaseMonster :: Move ( float flInterval ) +void CBaseMonster::Move( float flInterval ) { float flWaypointDist; float flCheckDist; @@ -1782,11 +1778,11 @@ void CBaseMonster :: Move ( float flInterval ) CBaseEntity *pTargetEnt; // Don't move if no valid route - if ( FRouteClear() ) + 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() ) + if( m_movementGoal == MOVEGOAL_NONE || !FRefreshRoute() ) { ALERT( at_aiconsole, "Tried to move with no route!\n" ); TaskFail(); @@ -1794,14 +1790,14 @@ void CBaseMonster :: Move ( float flInterval ) } } - if ( m_flMoveWaitFinished > gpGlobals->time ) + if( m_flMoveWaitFinished > gpGlobals->time ) return; // Debug, test movement code #if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) +// if( CVAR_GET_FLOAT("stopmove" ) != 0 ) { - if ( m_movementGoal == MOVEGOAL_ENEMY ) + if( m_movementGoal == MOVEGOAL_ENEMY ) RouteSimplify( m_hEnemy ); else RouteSimplify( m_hTargetEnt ); @@ -1817,14 +1813,14 @@ void CBaseMonster :: Move ( float flInterval ) pTargetEnt = NULL; // local move to waypoint. - vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); + 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 ); + 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 ) + if( flWaypointDist < DIST_TO_CHECK ) { flCheckDist = flWaypointDist; } @@ -1833,12 +1829,12 @@ void CBaseMonster :: Move ( float flInterval ) flCheckDist = DIST_TO_CHECK; } - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) + 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 ) + else if( ( m_Route[m_iRouteIndex].iType & ~bits_MF_NOT_TO_MASK ) == bits_MF_TO_TARGETENT ) { pTargetEnt = m_hTargetEnt; } @@ -1847,7 +1843,7 @@ void CBaseMonster :: Move ( float flInterval ) // 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 ) + if( CheckLocalMove( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) { CBaseEntity *pBlocker; @@ -1856,15 +1852,15 @@ void CBaseMonster :: Move ( float flInterval ) // Blocking entity is in global trace_ent pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) + if( pBlocker ) { DispatchBlocked( edict(), pBlocker->edict() ); } - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) + 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 ) + if( flDist < m_flGroundSpeed ) { // No, Wait for a second m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; @@ -1875,28 +1871,28 @@ void CBaseMonster :: Move ( float flInterval ) else { // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) + 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" ); + //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) ) + if( m_moveWaitTime > 0 && !( m_afMemory & bits_MEMORY_MOVE_FAILED ) ) { FRefreshRoute(); - if ( FRouteClear() ) + if( FRouteClear() ) { TaskFail(); } else { // Don't get stuck - if ( (gpGlobals->time - m_flMoveWaitFinished) < 0.2 ) + if( ( gpGlobals->time - m_flMoveWaitFinished ) < 0.2 ) Remember( bits_MEMORY_MOVE_FAILED ); m_flMoveWaitFinished = gpGlobals->time + 0.1; @@ -1905,8 +1901,8 @@ void CBaseMonster :: Move ( float flInterval ) 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 ); + 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; } @@ -1915,36 +1911,36 @@ void CBaseMonster :: Move ( float flInterval ) // 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 + if( ShouldAdvanceRoute( flWaypointDist ) )///!!!BUGBUG- magic number { AdvanceRoute( flWaypointDist ); } // Might be waiting for a door - if ( m_flMoveWaitFinished > gpGlobals->time ) + 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) + if( flCheckDist < m_flGroundSpeed * flInterval ) { flInterval = flCheckDist / m_flGroundSpeed; // ALERT( at_console, "%.02f\n", flInterval ); } MoveExecute( pTargetEnt, vecDir, flInterval ); - if ( MovementIsComplete() ) + if( MovementIsComplete() ) { Stop(); RouteClear(); } } -BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) +BOOL CBaseMonster::ShouldAdvanceRoute( float flWaypointDist ) { - if ( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) + if( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) { // ALERT( at_console, "cut %f\n", flWaypointDist ); return TRUE; @@ -1955,18 +1951,18 @@ BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) 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 ) + //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) + 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 ); + 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 ); @@ -1980,12 +1976,12 @@ void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f // initialization that should take place for all monsters // goes here. //========================================================= -void CBaseMonster :: MonsterInit ( void ) +void CBaseMonster::MonsterInit( void ) { - if (!g_pGameRules->FAllowMonsters()) + 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)); + //REMOVE_ENTITY( ENT( pev ) ); return; } @@ -1999,22 +1995,22 @@ void CBaseMonster :: MonsterInit ( void ) m_IdealActivity = ACT_IDLE; - SetBits (pev->flags, FL_MONSTER); - if ( pev->spawnflags & SF_MONSTER_HITMONSTERCLIP ) + 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_iHintNode = NO_NODE; - m_afMemory = MEMORY_CLEAR; + m_afMemory = MEMORY_CLEAR; - m_hEnemy = NULL; + m_hEnemy = NULL; - m_flDistTooFar = 1024.0; - m_flDistLook = 2048.0; + m_flDistTooFar = 1024.0; + m_flDistLook = 2048.0; // set eye position SetEyePosition(); @@ -2028,7 +2024,7 @@ void CBaseMonster :: MonsterInit ( void ) // MonsterInitThink - Calls StartMonster. Startmonster is // virtual, but this function cannot be //========================================================= -void CBaseMonster :: MonsterInitThink ( void ) +void CBaseMonster::MonsterInitThink( void ) { StartMonster(); } @@ -2037,36 +2033,36 @@ void CBaseMonster :: MonsterInitThink ( void ) // StartMonster - final bit of initization before a monster // is turned over to the AI. //========================================================= -void CBaseMonster :: StartMonster ( void ) +void CBaseMonster::StartMonster( void ) { // update capabilities - if ( LookupActivity ( ACT_RANGE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( ACT_RANGE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) { m_afCapability |= bits_CAP_RANGE_ATTACK1; } - if ( LookupActivity ( ACT_RANGE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( ACT_RANGE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) { m_afCapability |= bits_CAP_RANGE_ATTACK2; } - if ( LookupActivity ( ACT_MELEE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( ACT_MELEE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) { m_afCapability |= bits_CAP_MELEE_ATTACK1; } - if ( LookupActivity ( ACT_MELEE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) + 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 ) ) + if( pev->movetype != MOVETYPE_FLY && !FBitSet( pev->spawnflags, SF_MONSTER_FALL_TO_GROUND ) ) { pev->origin.z += 1; - DROP_TO_FLOOR ( ENT(pev) ); + 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 ) ) + if( !WALK_MOVE( ENT( pev ), 0, 0, WALKMOVE_NORMAL ) ) { - ALERT(at_error, "Monster %s stuck in wall--level design error\n", STRING(pev->classname)); + ALERT( at_error, "Monster %s stuck in wall--level design error\n", STRING( pev->classname ) ); pev->effects = EF_BRIGHTFIELD; } } @@ -2075,26 +2071,26 @@ void CBaseMonster :: StartMonster ( void ) pev->flags &= ~FL_ONGROUND; } - if ( !FStringNull(pev->target) )// this monster has a target + 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 ) ) ); + m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ) ); - if ( !m_pGoalEnt ) + if( !m_pGoalEnt ) { - ALERT(at_error, "ReadyMonster()--%s couldn't find target %s", STRING(pev->classname), STRING(pev->target)); + 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 ); + 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")) + if( !FClassnameIs( m_pGoalEnt->pev, "path_corner" ) ) { - ALERT(at_warning, "ReadyMonster--monster's initial goal '%s' is not a path_corner", STRING(pev->target)); + 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. @@ -2102,29 +2098,29 @@ void CBaseMonster :: StartMonster ( void ) // JAYJAY m_movementGoal = MOVEGOAL_PATHCORNER; - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) m_movementActivity = ACT_FLY; else m_movementActivity = ACT_WALK; - if ( !FRefreshRoute() ) + if( !FRefreshRoute() ) { - ALERT ( at_aiconsole, "Can't Create Route!\n" ); + ALERT( at_aiconsole, "Can't Create Route!\n" ); } SetState( MONSTERSTATE_IDLE ); ChangeSchedule( GetScheduleOfType( SCHED_IDLE_WALK ) ); } } - //SetState ( m_IdealMonsterState ); - //SetActivity ( m_IdealActivity ); + //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. + pev->nextthink += RANDOM_FLOAT( 0.1, 0.4 ); // spread think times. - if ( !FStringNull(pev->targetname) )// wait until triggered + if( !FStringNull( pev->targetname ) )// wait until triggered { SetState( MONSTERSTATE_IDLE ); // UNDONE: Some scripted sequence monsters don't have an idle? @@ -2133,7 +2129,7 @@ void CBaseMonster :: StartMonster ( void ) } } -void CBaseMonster :: MovementComplete( void ) +void CBaseMonster::MovementComplete( void ) { switch( m_iTaskStatus ) { @@ -2155,7 +2151,7 @@ void CBaseMonster :: MovementComplete( void ) int CBaseMonster::TaskIsRunning( void ) { - if ( m_iTaskStatus != TASKSTATUS_COMPLETE && + if( m_iTaskStatus != TASKSTATUS_COMPLETE && m_iTaskStatus != TASKSTATUS_RUNNING_MOVEMENT ) return 1; @@ -2166,7 +2162,7 @@ int CBaseMonster::TaskIsRunning( void ) // IRelationship - returns an integer that describes the // relationship between two types of monster. //========================================================= -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) +int CBaseMonster::IRelationship( CBaseEntity *pTarget ) { static int iEnemy[14][14] = { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN @@ -2186,7 +2182,7 @@ int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) /*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() ]; + return iEnemy[Classify()][pTarget->Classify()]; } //========================================================= @@ -2202,33 +2198,33 @@ int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) //float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) -BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) +BOOL CBaseMonster::FindCover( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { int i; int iMyHullIndex; int iMyNode; int iThreatNode; float flDist; - Vector vecLookersOffset; + Vector vecLookersOffset; TraceResult tr; - if ( !flMaxDist ) + if( !flMaxDist ) { // user didn't supply a MaxDist, so work up a crazy one. flMaxDist = 784; } - if ( flMinDist > 0.5 * flMaxDist) + if( flMinDist > 0.5 * flMaxDist ) { #if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); + 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 ) + if( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) { - ALERT ( at_aiconsole, "Graph not ready for findcover!\n" ); + ALERT( at_aiconsole, "Graph not ready for findcover!\n" ); return FALSE; } @@ -2236,14 +2232,14 @@ BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float f iThreatNode = WorldGraph.FindNearestNode ( vecThreat, this ); iMyHullIndex = WorldGraph.HullIndex( this ); - if ( iMyNode == NO_NODE ) + if( iMyNode == NO_NODE ) { - ALERT ( at_aiconsole, "FindCover() - %s has no nearest node!\n", STRING(pev->classname)); + ALERT( at_aiconsole, "FindCover() - %s has no nearest node!\n", STRING( pev->classname ) ); return FALSE; } - if ( iThreatNode == NO_NODE ) + if( iThreatNode == NO_NODE ) { - // ALERT ( at_aiconsole, "FindCover() - Threat has no nearest node!\n" ); + // ALERT( at_aiconsole, "FindCover() - Threat has no nearest node!\n" ); iThreatNode = iMyNode; // return FALSE; } @@ -2251,9 +2247,9 @@ BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float f 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++ ) + for( i = 0; i < WorldGraph.m_cNodes; i++ ) { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; + 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. @@ -2263,22 +2259,22 @@ BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float f // 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 ) + if( flDist >= flMinDist && flDist < flMaxDist ) { - UTIL_TraceLine ( node.m_vecOrigin + vecViewOffset, vecLookersOffset, ignore_monsters, ignore_glass, ENT(pev), &tr ); + 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 ) + 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( ( 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 ) ) + if( FValidateCover( node.m_vecOrigin ) && MoveToLocation( ACT_RUN, 0, node.m_vecOrigin ) ) { /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - + WRITE_BYTE( TE_SHOWLINE ); + WRITE_COORD( node.m_vecOrigin.x ); WRITE_COORD( node.m_vecOrigin.y ); WRITE_COORD( node.m_vecOrigin.z ); @@ -2307,69 +2303,69 @@ BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float f // if MaxDist isn't supplied, it defaults to a reasonable // value //========================================================= -BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) +BOOL CBaseMonster::BuildNearestRoute( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { int i; int iMyHullIndex; int iMyNode; float flDist; - Vector vecLookersOffset; + Vector vecLookersOffset; TraceResult tr; - if ( !flMaxDist ) + if( !flMaxDist ) { // user didn't supply a MaxDist, so work up a crazy one. flMaxDist = 784; } - if ( flMinDist > 0.5 * flMaxDist) + if( flMinDist > 0.5 * flMaxDist ) { #if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); + 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 ) + if( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) { - ALERT ( at_aiconsole, "Graph not ready for BuildNearestRoute!\n" ); + 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 ) + if( iMyNode == NO_NODE ) { - ALERT ( at_aiconsole, "BuildNearestRoute() - %s has no nearest node!\n", STRING(pev->classname)); + 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++ ) + for( i = 0; i < WorldGraph.m_cNodes; i++ ) { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; + 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) + if( WorldGraph.NextNodeInRoute( iMyNode, nodeNumber, iMyHullIndex, 0 ) != iMyNode ) { flDist = ( vecThreat - node.m_vecOrigin ).Length(); // is it close? - if ( flDist > flMinDist && flDist < flMaxDist) + 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) + if( tr.flFraction == 1.0 ) { // try to actually get there - if ( BuildRoute ( node.m_vecOrigin, bits_MF_TO_LOCATION, NULL ) ) + if( BuildRoute( node.m_vecOrigin, bits_MF_TO_LOCATION, NULL ) ) { flMaxDist = flDist; m_vecMoveGoal = node.m_vecOrigin; @@ -2392,24 +2388,24 @@ BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, // !!!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 *CBaseMonster::BestVisibleEnemy( void ) { CBaseEntity *pReturn; CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; + 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 ) + while( pNextEnt != NULL ) { - if ( pNextEnt->IsAlive() ) + if( pNextEnt->IsAlive() ) { - if ( IRelationship( pNextEnt) > iBestRelationship ) + 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 @@ -2418,17 +2414,17 @@ CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); pReturn = pNextEnt; } - else if ( IRelationship( pNextEnt) == iBestRelationship ) + 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 ) + if( iDist <= iNearest ) { iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); + iBestRelationship = IRelationship( pNextEnt ); pReturn = pNextEnt; } } @@ -2445,19 +2441,19 @@ CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) // face the supplied vector. Value is stuffed into the monster's // ideal_yaw //========================================================= -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) +void CBaseMonster::MakeIdealYaw( Vector vecTarget ) { - Vector vecProjection; + Vector vecProjection; // strafing monster needs to face 90 degrees away from its goal - if ( m_movementActivity == ACT_STRAFE_LEFT ) + 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 ) + else if( m_movementActivity == ACT_STRAFE_RIGHT ) { vecProjection.x = vecTarget.y; vecProjection.y = vecTarget.x; @@ -2466,7 +2462,7 @@ void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) } else { - pev->ideal_yaw = UTIL_VecToYaw ( vecTarget - pev->origin ); + pev->ideal_yaw = UTIL_VecToYaw( vecTarget - pev->origin ); } } @@ -2476,13 +2472,13 @@ void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) // // Positive result is left turn, negative is right turn //========================================================= -float CBaseMonster::FlYawDiff ( void ) +float CBaseMonster::FlYawDiff( void ) { - float flCurrentYaw; + float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - if ( flCurrentYaw == pev->ideal_yaw ) + if( flCurrentYaw == pev->ideal_yaw ) { return 0; } @@ -2493,49 +2489,51 @@ float CBaseMonster::FlYawDiff ( void ) //========================================================= // Changeyaw - turns a monster towards its ideal_yaw //========================================================= -float CBaseMonster::ChangeYaw ( int yawSpeed ) +float CBaseMonster::ChangeYaw( int yawSpeed ) { float ideal, current, move, speed; current = UTIL_AngleMod( pev->angles.y ); ideal = pev->ideal_yaw; - if (current != ideal) + if( current != ideal ) { speed = (float)yawSpeed * gpGlobals->frametime * 10; move = ideal - current; - if (ideal > current) + if( ideal > current ) { - if (move >= 180) + if( move >= 180 ) move = move - 360; } else { - if (move <= -180) + if( move <= -180 ) move = move + 360; } - if (move > 0) + if( move > 0 ) { // turning to the monster's left - if (move > speed) + if( move > speed ) move = speed; } else { // turning to the monster's right - if (move < -speed) + if( move < -speed ) move = -speed; } - pev->angles.y = UTIL_AngleMod (current + move); + 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) + 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; + if( yaw > 180 ) + yaw -= 360; + if( yaw < -180 ) + yaw += 360; // yaw *= 0.8; SetBoneController( 0, yaw ); } @@ -2550,9 +2548,9 @@ float CBaseMonster::ChangeYaw ( int yawSpeed ) // VecToYaw - turns a directional vector into a yaw value // that points down that vector. //========================================================= -float CBaseMonster::VecToYaw ( Vector vecDir ) +float CBaseMonster::VecToYaw( Vector vecDir ) { - if (vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0) + if( vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0 ) return pev->angles.y; return UTIL_VecToYaw( vecDir ); @@ -2565,7 +2563,7 @@ float CBaseMonster::VecToYaw ( Vector vecDir ) // that vector to the monster's view_ofs // //========================================================= -void CBaseMonster :: SetEyePosition ( void ) +void CBaseMonster::SetEyePosition( void ) { Vector vecEyePosition; void *pmodel = GET_MODEL_PTR( ENT(pev) ); @@ -2574,33 +2572,33 @@ void CBaseMonster :: SetEyePosition ( void ) pev->view_ofs = vecEyePosition; - if ( pev->view_ofs == g_vecZero ) + if( pev->view_ofs == g_vecZero ) { - ALERT ( at_aiconsole, "%s has no view_ofs!\n", STRING ( pev->classname ) ); + ALERT( at_aiconsole, "%s has no view_ofs!\n", STRING( pev->classname ) ); } } -void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CBaseMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case SCRIPT_EVENT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + 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) ); + 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) ); + ALERT( at_aiconsole, "INVALID death event:%s\n", STRING( pev->classname ) ); #endif break; case SCRIPT_EVENT_NOT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + if( m_MonsterState == MONSTERSTATE_SCRIPT ) { pev->deadflag = DEAD_NO; @@ -2615,7 +2613,7 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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) + if( RANDOM_LONG( 0, 2 ) == 0 ) break; // fall through... case SCRIPT_EVENT_SENTENCE: // Play a named sentence group @@ -2625,11 +2623,11 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) FireTargets( pEvent->options, this, this, USE_TOGGLE, 0 ); break; case SCRIPT_EVENT_NOINTERRUPT: // Can't be interrupted from now on - if ( m_pCine ) + if( m_pCine ) m_pCine->AllowInterrupt( FALSE ); break; case SCRIPT_EVENT_CANINTERRUPT: // OK to interrupt now - if ( m_pCine ) + if( m_pCine ) m_pCine->AllowInterrupt( TRUE ); break; #if 0 @@ -2638,47 +2636,47 @@ void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; #endif case MONSTER_EVENT_BODYDROP_HEAVY: - if ( pev->flags & FL_ONGROUND ) + if( pev->flags & FL_ONGROUND ) { - if ( RANDOM_LONG( 0, 1 ) == 0 ) + if( RANDOM_LONG( 0, 1 ) == 0 ) { - EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM, 0, 90 ); + 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 ); + 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( pev->flags & FL_ONGROUND ) { - if ( RANDOM_LONG( 0, 1 ) == 0 ) + if( RANDOM_LONG( 0, 1 ) == 0 ) { - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM ); + 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 ); + 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 ); + 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) ); + ALERT( at_aiconsole, "Unhandled animation event %d for %s\n", pEvent->event, STRING( pev->classname ) ); break; } } // Combat -Vector CBaseMonster :: GetGunPosition( ) +Vector CBaseMonster::GetGunPosition() { - UTIL_MakeVectors(pev->angles); + UTIL_MakeVectors( pev->angles ); // Vector vecSrc = pev->origin + gpGlobals->v_forward * 10; //vecSrc.z = pevShooter->absmin.z + pevShooter->size.z * 0.7; @@ -2703,7 +2701,7 @@ Vector CBaseMonster :: GetGunPosition( ) // succeeds (path is valid) or FALSE if failed (no path // exists ) //========================================================= -BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) +BOOL CBaseMonster::FGetNodeRoute( Vector vecDest ) { int iPath[ MAX_PATH_SIZE ]; int iSrcNode, iDestNode; @@ -2711,45 +2709,45 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) int i; int iNumToCopy; - iSrcNode = WorldGraph.FindNearestNode ( pev->origin, this ); - iDestNode = WorldGraph.FindNearestNode ( vecDest, this ); + iSrcNode = WorldGraph.FindNearestNode( pev->origin, this ); + iDestNode = WorldGraph.FindNearestNode( vecDest, this ); - if ( iSrcNode == -1 ) + if( iSrcNode == -1 ) { // no node nearest self - //ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); + //ALERT( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); return FALSE; } - else if ( iDestNode == -1 ) + else if( iDestNode == -1 ) { // no node nearest target - //ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near target!\n" ); + //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 ); + iResult = WorldGraph.FindShortestPath( iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability ); - if ( !iResult ) + if( !iResult ) { #if 1 - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); + 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); + iResult = WorldGraph.FindShortestPath( iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability ); WorldGraph.m_fRoutingComplete = bRoutingSave; - if ( !iResult ) + if( !iResult ) { - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); + ALERT( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); return FALSE; } else { - ALERT ( at_aiconsole, "Routing is inconsistent!" ); + ALERT( at_aiconsole, "Routing is inconsistent!" ); } #endif } @@ -2759,7 +2757,7 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) // don't copy ROUTE_SIZE entries if the path returned is shorter // than ROUTE_SIZE!!! - if ( iResult < ROUTE_SIZE ) + if( iResult < ROUTE_SIZE ) { iNumToCopy = iResult; } @@ -2768,16 +2766,16 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) iNumToCopy = ROUTE_SIZE; } - for ( i = 0 ; i < iNumToCopy; i++ ) + 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; + m_Route[i].vecLocation = WorldGraph.m_pNodes[iPath[i]].m_vecOrigin; + m_Route[i].iType = bits_MF_TO_NODE; } - if ( iNumToCopy < ROUTE_SIZE ) + if( iNumToCopy < ROUTE_SIZE ) { - m_Route[ iNumToCopy ].vecLocation = vecDest; - m_Route[ iNumToCopy ].iType |= bits_MF_IS_GOAL; + m_Route[iNumToCopy].vecLocation = vecDest; + m_Route[iNumToCopy].iType |= bits_MF_IS_GOAL; } return TRUE; @@ -2786,37 +2784,37 @@ BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) //========================================================= // FindHintNode //========================================================= -int CBaseMonster :: FindHintNode ( void ) +int CBaseMonster::FindHintNode( void ) { int i; TraceResult tr; - if ( !WorldGraph.m_fGraphPresent ) + if( !WorldGraph.m_fGraphPresent ) { - ALERT ( at_aiconsole, "find_hintnode: graph not ready!\n" ); + ALERT( at_aiconsole, "find_hintnode: graph not ready!\n" ); return NO_NODE; } - if ( WorldGraph.m_iLastActiveIdleSearch >= WorldGraph.m_cNodes ) + if( WorldGraph.m_iLastActiveIdleSearch >= WorldGraph.m_cNodes ) { WorldGraph.m_iLastActiveIdleSearch = 0; } - for ( i = 0; i < WorldGraph.m_cNodes ; i++ ) + for( i = 0; i < WorldGraph.m_cNodes; i++ ) { - int nodeNumber = (i + WorldGraph.m_iLastActiveIdleSearch) % WorldGraph.m_cNodes; + int nodeNumber = ( i + WorldGraph.m_iLastActiveIdleSearch) % WorldGraph.m_cNodes; CNode &node = WorldGraph.Node( nodeNumber ); - if ( node.m_sHintType ) + 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( FValidateHintType( node.m_sHintType ) ) { - if ( !node.m_sHintActivity || LookupActivity ( node.m_sHintActivity ) != ACTIVITY_NOT_AVAILABLE ) + 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 ); + UTIL_TraceLine( pev->origin + pev->view_ofs, node.m_vecOrigin + pev->view_ofs, ignore_monsters, ENT( pev ), &tr ); - if ( tr.flFraction == 1.0 ) + 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! @@ -2838,12 +2836,12 @@ void CBaseMonster::ReportAIState( void ) static const char *pStateNames[] = { "None", "Idle", "Combat", "Alert", "Hunt", "Prone", "Scripted", "Dead" }; ALERT( level, "%s: ", STRING(pev->classname) ); - if ( (int)m_MonsterState < ARRAYSIZE(pStateNames) ) + if( (int)m_MonsterState < ARRAYSIZE( pStateNames ) ) ALERT( level, "State: %s, ", pStateNames[m_MonsterState] ); int i = 0; - while ( activity_map[i].type != 0 ) + while( activity_map[i].type != 0 ) { - if ( activity_map[i].type == (int)m_Activity ) + if( activity_map[i].type == (int)m_Activity ) { ALERT( level, "Activity %s, ", activity_map[i].name ); break; @@ -2851,58 +2849,58 @@ void CBaseMonster::ReportAIState( void ) i++; } - if ( m_pSchedule ) + if( m_pSchedule ) { const char *pName = NULL; pName = m_pSchedule->pName; - if ( !pName ) + if( !pName ) pName = "Unknown"; ALERT( level, "Schedule %s, ", pName ); Task_t *pTask = GetTask(); - if ( pTask ) + if( pTask ) ALERT( level, "Task %d (#%d), ", pTask->iTask, m_iScheduleIndex ); } else ALERT( level, "No Schedule, " ); - if ( m_hEnemy != NULL ) - ALERT( level, "\nEnemy is %s", STRING(m_hEnemy->pev->classname) ); + if( m_hEnemy != NULL ) + ALERT( level, "\nEnemy is %s", STRING( m_hEnemy->pev->classname ) ); else ALERT( level, "No enemy" ); - if ( IsMoving() ) + if( IsMoving() ) { ALERT( level, " Moving " ); - if ( m_flMoveWaitFinished > gpGlobals->time ) + if( m_flMoveWaitFinished > gpGlobals->time ) ALERT( level, ": Stopped for %.2f. ", m_flMoveWaitFinished - gpGlobals->time ); - else if ( m_IdealActivity == GetStoppedActivity() ) + else if( m_IdealActivity == GetStoppedActivity() ) ALERT( level, ": In stopped anim. " ); } CSquadMonster *pSquadMonster = MySquadMonsterPointer(); - if ( pSquadMonster ) + if( pSquadMonster ) { - if ( !pSquadMonster->InSquad() ) + if( !pSquadMonster->InSquad() ) { - ALERT ( level, "not " ); + ALERT( level, "not " ); } - ALERT ( level, "In Squad, " ); + ALERT( level, "In Squad, " ); - if ( !pSquadMonster->IsLeader() ) + if( !pSquadMonster->IsLeader() ) { - ALERT ( level, "not " ); + ALERT( level, "not " ); } - ALERT ( level, "Leader." ); + 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 ) + if( pev->spawnflags & SF_MONSTER_PRISONER ) ALERT( level, " PRISONER! " ); - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) + if( pev->spawnflags & SF_MONSTER_PREDISASTER ) ALERT( level, " Pre-Disaster! " ); ALERT( level, "\n" ); } @@ -2912,14 +2910,14 @@ void CBaseMonster::ReportAIState( void ) // // !!! netname entvar field is used in squadmonster for groupname!!! //========================================================= -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) +void CBaseMonster::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "TriggerTarget")) + if( FStrEq( pkvd->szKeyName, "TriggerTarget" ) ) { m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "TriggerCondition") ) + else if( FStrEq( pkvd->szKeyName, "TriggerCondition" ) ) { m_iTriggerCondition = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -2937,11 +2935,11 @@ void CBaseMonster :: KeyValue( KeyValueData *pkvd ) // // Returns TRUE if the target is fired. //========================================================= -BOOL CBaseMonster :: FCheckAITrigger ( void ) +BOOL CBaseMonster::FCheckAITrigger( void ) { BOOL fFireTarget; - if ( m_iTriggerCondition == AITRIGGER_NONE ) + if( m_iTriggerCondition == AITRIGGER_NONE ) { // no conditions, so this trigger is never fired. return FALSE; @@ -2949,22 +2947,22 @@ BOOL CBaseMonster :: FCheckAITrigger ( void ) fFireTarget = FALSE; - switch ( m_iTriggerCondition ) + switch( m_iTriggerCondition ) { case AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER: - if ( m_hEnemy != NULL && m_hEnemy->IsPlayer() && HasConditions ( bits_COND_SEE_ENEMY ) ) + if( m_hEnemy != NULL && m_hEnemy->IsPlayer() && HasConditions( bits_COND_SEE_ENEMY ) ) { fFireTarget = TRUE; } break; case AITRIGGER_SEEPLAYER_UNCONDITIONAL: - if ( HasConditions ( bits_COND_SEE_CLIENT ) ) + if( HasConditions( bits_COND_SEE_CLIENT ) ) { fFireTarget = TRUE; } break; case AITRIGGER_SEEPLAYER_NOT_IN_COMBAT: - if ( HasConditions ( bits_COND_SEE_CLIENT ) && + if( HasConditions( bits_COND_SEE_CLIENT ) && m_MonsterState != MONSTERSTATE_COMBAT && m_MonsterState != MONSTERSTATE_PRONE && m_MonsterState != MONSTERSTATE_SCRIPT) @@ -2973,19 +2971,19 @@ BOOL CBaseMonster :: FCheckAITrigger ( void ) } break; case AITRIGGER_TAKEDAMAGE: - if ( m_afConditions & ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + if( m_afConditions & ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { fFireTarget = TRUE; } break; case AITRIGGER_DEATH: - if ( pev->deadflag != DEAD_NO ) + if( pev->deadflag != DEAD_NO ) { fFireTarget = TRUE; } break; case AITRIGGER_HALFHEALTH: - if ( IsAlive() && pev->health <= ( pev->max_health / 2 ) ) + if( IsAlive() && pev->health <= ( pev->max_health / 2 ) ) { fFireTarget = TRUE; } @@ -3000,29 +2998,29 @@ BOOL CBaseMonster :: FCheckAITrigger ( void ) break; */ case AITRIGGER_HEARWORLD: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_WORLD ) + 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 ) + 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 ) + if( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_COMBAT ) { fFireTarget = TRUE; } break; } - if ( fFireTarget ) + 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" ); + ALERT( at_aiconsole, "AI Trigger Fire Target\n" ); FireTargets( STRING( m_iszTriggerTarget ), this, this, USE_TOGGLE, 0 ); m_iTriggerCondition = AITRIGGER_NONE; return TRUE; @@ -3038,27 +3036,27 @@ BOOL CBaseMonster :: FCheckAITrigger ( void ) // 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 ) +int CBaseMonster::CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { - if ( m_pCine || !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) + if( m_pCine || !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) { // monster is already running a scripted sequence or dead! return FALSE; } - if ( fDisregardMonsterState ) + 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 ) + 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 ) + if( m_MonsterState == MONSTERSTATE_ALERT && interruptLevel >= SS_INTERRUPT_BY_NAME ) return TRUE; // unknown situation @@ -3073,35 +3071,35 @@ int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptL #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 ) +BOOL CBaseMonster::FindLateralCover( const Vector &vecThreat, const Vector &vecViewOffset ) { - TraceResult tr; + TraceResult tr; Vector vecBestOnLeft; Vector vecBestOnRight; Vector vecLeftTest; Vector vecRightTest; Vector vecStepRight; - int i; + int i; - UTIL_MakeVectors ( pev->angles ); + UTIL_MakeVectors( pev->angles ); vecStepRight = gpGlobals->v_right * COVER_DELTA; vecStepRight.z = 0; vecLeftTest = vecRightTest = pev->origin; - for ( i = 0 ; i < COVER_CHECKS ; i++ ) + 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) + 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( FValidateCover( vecLeftTest ) && CheckLocalMove( pev->origin, vecLeftTest, NULL, NULL ) == LOCALMOVE_VALID ) { - if ( MoveToLocation( ACT_RUN, 0, vecLeftTest ) ) + if( MoveToLocation( ACT_RUN, 0, vecLeftTest ) ) { return TRUE; } @@ -3109,13 +3107,13 @@ BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &v } // 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 ) + 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( FValidateCover( vecRightTest ) && CheckLocalMove( pev->origin, vecRightTest, NULL, NULL ) == LOCALMOVE_VALID ) { - if ( MoveToLocation( ACT_RUN, 0, vecRightTest ) ) + if( MoveToLocation( ACT_RUN, 0, vecRightTest ) ) { return TRUE; } @@ -3126,13 +3124,13 @@ BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &v return FALSE; } -Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) +Vector CBaseMonster::ShootAtEnemy( const Vector &shootOrigin ) { CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy ) + if( pEnemy ) { - return ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP - shootOrigin ).Normalize(); + return( ( pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin ) + m_vecEnemyLKP - shootOrigin ).Normalize(); } else return gpGlobals->v_forward; @@ -3145,9 +3143,9 @@ Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) // number. Nicer to have it in one place if we're gonna // be stuck with it. //========================================================= -BOOL CBaseMonster :: FacingIdeal( void ) +BOOL CBaseMonster::FacingIdeal( void ) { - if ( fabs( FlYawDiff() ) <= 0.006 )//!!!BUGBUG - no magic numbers!!! + if( fabs( FlYawDiff() ) <= 0.006 )//!!!BUGBUG - no magic numbers!!! { return TRUE; } @@ -3158,10 +3156,10 @@ BOOL CBaseMonster :: FacingIdeal( void ) //========================================================= // FCanActiveIdle //========================================================= -BOOL CBaseMonster :: FCanActiveIdle ( void ) +BOOL CBaseMonster::FCanActiveIdle( void ) { /* - if ( m_MonsterState == MONSTERSTATE_IDLE && m_IdealMonsterState == MONSTERSTATE_IDLE && !IsMoving() ) + if( m_MonsterState == MONSTERSTATE_IDLE && m_IdealMonsterState == MONSTERSTATE_IDLE && !IsMoving() ) { return TRUE; } @@ -3171,9 +3169,9 @@ BOOL CBaseMonster :: FCanActiveIdle ( void ) void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { - if ( pszSentence && IsAlive() ) + if( pszSentence && IsAlive() ) { - if ( pszSentence[0] == '!' ) + 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 ); @@ -3192,7 +3190,7 @@ void CBaseMonster::SentenceStop( void ) void CBaseMonster::CorpseFallThink( void ) { - if ( pev->flags & FL_ONGROUND ) + if( pev->flags & FL_ONGROUND ) { SetThink( NULL ); @@ -3204,22 +3202,22 @@ void CBaseMonster::CorpseFallThink( void ) } // Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) +void CBaseMonster::MonsterInitDead( void ) { InitBoneControllers(); - pev->solid = SOLID_BBOX; + pev->solid = SOLID_BBOX; pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->framerate = 0; // Copy health pev->max_health = pev->health; pev->deadflag = DEAD_DEAD; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); + UTIL_SetSize( pev, g_vecZero, g_vecZero ); UTIL_SetOrigin( pev, pev->origin ); // Setup health counters, etc. @@ -3233,7 +3231,7 @@ void CBaseMonster :: MonsterInitDead( void ) // is lying flat on a surface (traces from all four corners // are same length.) //========================================================= -BOOL CBaseMonster :: BBoxFlat ( void ) +BOOL CBaseMonster::BBoxFlat( void ) { TraceResult tr; Vector vecPoint; @@ -3248,15 +3246,15 @@ BOOL CBaseMonster :: BBoxFlat ( void ) 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(); + 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 ) + UTIL_TraceLine( vecPoint, vecPoint - Vector( 0, 0, 100 ), ignore_monsters, ENT( pev ), &tr ); + flLength2 = ( vecPoint - tr.vecEndPos ).Length(); + if( flLength2 > flLength ) { return FALSE; } @@ -3264,9 +3262,9 @@ BOOL CBaseMonster :: BBoxFlat ( void ) 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 ) + UTIL_TraceLine ( vecPoint, vecPoint - Vector( 0, 0, 100 ), ignore_monsters, ENT( pev ), &tr ); + flLength2 = ( vecPoint - tr.vecEndPos ).Length(); + if( flLength2 > flLength ) { return FALSE; } @@ -3274,9 +3272,9 @@ BOOL CBaseMonster :: BBoxFlat ( void ) 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 ) + UTIL_TraceLine( vecPoint, vecPoint - Vector( 0, 0, 100 ), ignore_monsters, ENT( pev ), &tr ); + flLength2 = ( vecPoint - tr.vecEndPos ).Length(); + if( flLength2 > flLength ) { return FALSE; } @@ -3288,34 +3286,34 @@ BOOL CBaseMonster :: BBoxFlat ( void ) //========================================================= // Get Enemy - tries to find the best suitable enemy for the monster. //========================================================= -BOOL CBaseMonster :: GetEnemy ( void ) +BOOL CBaseMonster::GetEnemy( void ) { CBaseEntity *pNewEnemy; - if ( HasConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_NEMESIS) ) + if( HasConditions( bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_NEMESIS ) ) { pNewEnemy = BestVisibleEnemy(); - if ( pNewEnemy != m_hEnemy && pNewEnemy != NULL) + 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 ) { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + if( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) { PushEnemy( m_hEnemy, m_vecEnemyLKP ); - SetConditions(bits_COND_NEW_ENEMY); + 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) + if( pNewEnemy->pev->owner != NULL ) { CBaseEntity *pOwner = GetMonsterPointer( pNewEnemy->pev->owner ); - if ( pOwner && (pOwner->pev->flags & FL_MONSTER) && IRelationship( pOwner ) != R_NO ) + if( pOwner && ( pOwner->pev->flags & FL_MONSTER ) && IRelationship( pOwner ) != R_NO ) PushEnemy( pOwner, m_vecEnemyLKP ); } } @@ -3323,18 +3321,18 @@ BOOL CBaseMonster :: GetEnemy ( void ) } // remember old enemies - if (m_hEnemy == NULL && PopEnemy( )) + if( m_hEnemy == NULL && PopEnemy() ) { - if ( m_pSchedule ) + if( m_pSchedule ) { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) + if( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) { - SetConditions(bits_COND_NEW_ENEMY); + SetConditions( bits_COND_NEW_ENEMY ); } } } - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { // monster has an enemy. return TRUE; @@ -3346,35 +3344,34 @@ BOOL CBaseMonster :: GetEnemy ( void ) //========================================================= // DropItem - dead monster drops named item //========================================================= -CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) +CBaseEntity *CBaseMonster::DropItem( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { - if ( !pszItemName ) + if( !pszItemName ) { - ALERT ( at_console, "DropItem() - No item name!\n" ); + ALERT( at_console, "DropItem() - No item name!\n" ); return NULL; } CBaseEntity *pItem = CBaseEntity::Create( pszItemName, vecPos, vecAng, edict() ); - if ( pItem ) + 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 ); + pItem->pev->avelocity = Vector( 0, RANDOM_FLOAT( 0, 100 ), 0 ); return pItem; } else { - ALERT ( at_console, "DropItem() - Didn't create!\n" ); + ALERT( at_console, "DropItem() - Didn't create!\n" ); return FALSE; } - } -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) +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 ) ) + if( ( pev->spawnflags & SF_MONSTER_FADECORPSE ) || !FNullEnt( pev->owner ) ) return TRUE; return FALSE; diff --git a/dlls/monsterstate.cpp b/dlls/monsterstate.cpp index b40af733..f29664dc 100644 --- a/dlls/monsterstate.cpp +++ b/dlls/monsterstate.cpp @@ -29,12 +29,12 @@ //========================================================= // SetState //========================================================= -void CBaseMonster :: SetState ( MONSTERSTATE State ) +void CBaseMonster::SetState( MONSTERSTATE State ) { /* - if ( State != m_MonsterState ) + if( State != m_MonsterState ) { - ALERT ( at_aiconsole, "State Changed to %d\n", State ); + ALERT( at_aiconsole, "State Changed to %d\n", State ); } */ switch( State ) @@ -42,10 +42,10 @@ void CBaseMonster :: SetState ( MONSTERSTATE State ) // Drop enemy pointers when going to idle case MONSTERSTATE_IDLE: - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { m_hEnemy = NULL;// not allowed to have an enemy anymore. - ALERT ( at_aiconsole, "Stripped\n" ); + ALERT( at_aiconsole, "Stripped\n" ); } break; default: @@ -59,20 +59,20 @@ void CBaseMonster :: SetState ( MONSTERSTATE State ) //========================================================= // RunAI //========================================================= -void CBaseMonster :: RunAI ( void ) +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) ) + 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 && + 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. @@ -80,7 +80,7 @@ void CBaseMonster :: RunAI ( void ) // 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 ) ) + if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) { Look( m_flDistLook ); Listen();// check for audible sounds. @@ -92,7 +92,7 @@ void CBaseMonster :: RunAI ( void ) } // do these calculations if monster has an enemy. - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) { CheckEnemy( m_hEnemy ); } @@ -116,14 +116,14 @@ void CBaseMonster :: RunAI ( void ) // GetIdealState - surveys the Conditions information available // and finds the best new state for a monster. //========================================================= -MONSTERSTATE CBaseMonster :: GetIdealState ( void ) +MONSTERSTATE CBaseMonster::GetIdealState( void ) { - int iConditions; + int iConditions; iConditions = IScheduleFlags(); - + // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_IDLE: /* @@ -134,36 +134,36 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) IDLE goes to HUNT upon smelling food */ { - if ( iConditions & bits_COND_NEW_ENEMY ) + 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 ) + else if( iConditions & bits_COND_LIGHT_DAMAGE ) { - MakeIdealYaw ( m_vecEnemyLKP ); + MakeIdealYaw( m_vecEnemyLKP ); m_IdealMonsterState = MONSTERSTATE_ALERT; } - else if ( iConditions & bits_COND_HEAVY_DAMAGE ) + else if( iConditions & bits_COND_HEAVY_DAMAGE ) { - MakeIdealYaw ( m_vecEnemyLKP ); + MakeIdealYaw( m_vecEnemyLKP ); m_IdealMonsterState = MONSTERSTATE_ALERT; } - else if ( iConditions & bits_COND_HEAR_SOUND ) + else if( iConditions & bits_COND_HEAR_SOUND ) { CSound *pSound; - + pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound ) + if( pSound ) { - MakeIdealYaw ( pSound->m_vecOrigin ); - if ( pSound->m_iType & (bits_SOUND_COMBAT|bits_SOUND_DANGER) ) + 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) ) + else if( iConditions & ( bits_COND_SMELL | bits_COND_SMELL_FOOD ) ) { m_IdealMonsterState = MONSTERSTATE_ALERT; } @@ -177,18 +177,18 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) ALERT goes to HUNT upon hearing a noise */ { - if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) ) + 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 ) + else if( iConditions & bits_COND_HEAR_SOUND ) { m_IdealMonsterState = MONSTERSTATE_ALERT; CSound *pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound ) - MakeIdealYaw ( pSound->m_vecOrigin ); + if( pSound ) + MakeIdealYaw( pSound->m_vecOrigin ); } break; } @@ -198,11 +198,11 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) COMBAT goes to ALERT upon death of enemy */ { - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { m_IdealMonsterState = MONSTERSTATE_ALERT; // pev->effects = EF_BRIGHTFIELD; - ALERT ( at_aiconsole, "***Combat state with no enemy!\n" ); + ALERT( at_aiconsole, "***Combat state with no enemy!\n" ); } break; } @@ -217,7 +217,7 @@ MONSTERSTATE CBaseMonster :: GetIdealState ( void ) break; } case MONSTERSTATE_SCRIPT: - if ( iConditions & (bits_COND_TASK_FAILED|bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) ) + if( iConditions & ( bits_COND_TASK_FAILED | bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { ExitScriptedSequence(); // This will set the ideal state } diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index 54c05f25..33a7d2da 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -16,7 +16,7 @@ ===== mortar.cpp ======================================================== - the "LaBuznik" mortar device + the "LaBuznik" mortar device */ @@ -36,12 +36,12 @@ public: void KeyValue( KeyValueData *pkvd ); // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); @@ -67,55 +67,55 @@ TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ) -void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) +void CFuncMortarField::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "m_iszXController")) + if( FStrEq( pkvd->szKeyName, "m_iszXController" ) ) { - m_iszXController = ALLOC_STRING(pkvd->szValue); + m_iszXController = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_iszYController")) + else if( FStrEq( pkvd->szKeyName, "m_iszYController" ) ) { - m_iszYController = ALLOC_STRING(pkvd->szValue); + m_iszYController = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flSpread")) + else if( FStrEq( pkvd->szKeyName, "m_flSpread" ) ) { - m_flSpread = atof(pkvd->szValue); + m_flSpread = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_fControl")) + else if( FStrEq( pkvd->szKeyName, "m_fControl" ) ) { - m_fControl = atoi(pkvd->szValue); + m_fControl = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_iCount")) + else if( FStrEq( pkvd->szKeyName, "m_iCount" ) ) { - m_iCount = atoi(pkvd->szValue); + m_iCount = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } } // Drop bombs from above -void CFuncMortarField :: Spawn( void ) +void CFuncMortarField::Spawn( void ) { pev->solid = SOLID_NOT; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + 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 ) +void CFuncMortarField::Precache( void ) { - PRECACHE_SOUND ("weapons/mortar.wav"); - PRECACHE_SOUND ("weapons/mortarhit.wav"); + 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 ) +void CFuncMortarField::FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { Vector vecStart; @@ -125,62 +125,66 @@ void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller switch( m_fControl ) { - case 0: // random + case 0: + // random break; - case 1: // Trigger Activator - if (pActivator != NULL) + case 1: + // Trigger Activator + if( pActivator != NULL ) { vecStart.x = pActivator->pev->origin.x; vecStart.y = pActivator->pev->origin.y; } break; - case 2: // table + case 2: + // table { CBaseEntity *pController; - if (!FStringNull(m_iszXController)) + if( !FStringNull( m_iszXController ) ) { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszXController)); - if (pController != NULL) + pController = UTIL_FindEntityByTargetname( NULL, STRING( m_iszXController ) ); + if( pController != NULL ) { - vecStart.x = pev->mins.x + pController->pev->ideal_yaw * (pev->size.x); + vecStart.x = pev->mins.x + pController->pev->ideal_yaw * ( pev->size.x ); } } - if (!FStringNull(m_iszYController)) + if( !FStringNull( m_iszYController ) ) { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszYController)); - if (pController != NULL) + pController = UTIL_FindEntityByTargetname( NULL, STRING( m_iszYController ) ); + if( pController != NULL ) { - vecStart.y = pev->mins.y + pController->pev->ideal_yaw * (pev->size.y); + vecStart.y = pev->mins.y + pController->pev->ideal_yaw * ( pev->size.y ); } } } break; } - int pitch = RANDOM_LONG(95,124); + int pitch = RANDOM_LONG( 95,124 ); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortar.wav", 1.0, ATTN_NONE, 0, pitch); + 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++) + 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 ); + UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT( pev ), &tr ); edict_t *pentOwner = NULL; - if (pActivator) pentOwner = pActivator->edict(); + if( pActivator ) + pentOwner = pActivator->edict(); - CBaseEntity *pMortar = Create("monster_mortar", tr.vecEndPos, Vector( 0, 0, 0 ), pentOwner ); + 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 ); + if( i == 0 ) + CSoundEnt::InsertSound( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); } } @@ -197,20 +201,20 @@ public: LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ) -void CMortar::Spawn( ) +void CMortar::Spawn() { - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; - pev->dmg = 200; + pev->dmg = 200; SetThink( &CMortar::MortarExplode ); pev->nextthink = 0; - Precache( ); + Precache(); } -void CMortar::Precache( ) +void CMortar::Precache() { m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" ); } @@ -221,13 +225,13 @@ void CMortar::MortarExplode( void ) // 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_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 @@ -244,14 +248,14 @@ void CMortar::MortarExplode( void ) #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( 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 @@ -266,22 +270,22 @@ void CMortar::MortarExplode( void ) #endif TraceResult tr; - UTIL_TraceLine( pev->origin + Vector( 0, 0, 1024 ), pev->origin - Vector( 0, 0, 1024 ), dont_ignore_monsters, ENT(pev), &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); + 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 ); + RadiusDamage( pev, VARS( pev->owner ), pev->dmg, CLASS_NONE, DMG_BLAST ); /* - if ( RANDOM_FLOAT ( 0 , 1 ) < 0.5 ) + if( RANDOM_FLOAT( 0, 1 ) < 0.5 ) { UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); } @@ -303,7 +307,7 @@ void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) pMortar->Spawn(); TraceResult tr; - UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pMortar->pev), &tr ); + UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT( pMortar->pev ), &tr ); pMortar->pev->nextthink = gpGlobals->time + time; diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index edfaee5d..3cc2e5c2 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -25,28 +25,28 @@ float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: u /*********************************************************/ -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; } +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::ReportAIState( void ) { } +float CBaseMonster::ChangeYaw( int speed ) { return 0; } +void CBaseMonster::MakeIdealYaw( Vector vecTarget ) { } void CBaseMonster::CorpseFallThink( void ) { - if ( pev->flags & FL_ONGROUND ) + if( pev->flags & FL_ONGROUND ) { SetThink( NULL ); - SetSequenceBox( ); + SetSequenceBox(); UTIL_SetOrigin( pev, pev->origin );// link into world. } else @@ -54,22 +54,22 @@ void CBaseMonster::CorpseFallThink( void ) } // Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) +void CBaseMonster::MonsterInitDead( void ) { InitBoneControllers(); - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->framerate = 0; - + // Copy health - pev->max_health = pev->health; - pev->deadflag = DEAD_DEAD; - - UTIL_SetSize(pev, g_vecZero, g_vecZero ); + 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. @@ -78,22 +78,22 @@ void CBaseMonster :: MonsterInitDead( void ) pev->nextthink = gpGlobals->time + 0.5; } -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) -{ - return FALSE; +BOOL CBaseMonster::ShouldFadeOnDeath( void ) +{ + return FALSE; } -BOOL CBaseMonster :: FCheckAITrigger ( void ) -{ - return FALSE; +BOOL CBaseMonster::FCheckAITrigger( void ) +{ + return FALSE; } -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) +void CBaseMonster::KeyValue( KeyValueData *pkvd ) { CBaseToggle::KeyValue( pkvd ); } -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) +int CBaseMonster::IRelationship( CBaseEntity *pTarget ) { static int iEnemy[14][14] = { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN @@ -113,7 +113,7 @@ int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) /*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() ]; + return iEnemy[Classify()][pTarget->Classify()]; } //========================================================= @@ -128,33 +128,33 @@ int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) // (linked via each ent's m_pLink field) // //========================================================= -void CBaseMonster :: Look ( int iDistance ) +void CBaseMonster::Look( int iDistance ) { - int iSighted = 0; + 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); + 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 *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++ ) + 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 ) + 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( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) { - if ( pSightEnt->IsPlayer() ) + if( pSightEnt->IsPlayer() ) { // if we see a client, remember that (mostly for scripted AI) iSighted |= bits_COND_SEE_CLIENT; @@ -163,7 +163,7 @@ void CBaseMonster :: Look ( int iDistance ) pSightEnt->m_pLink = m_pLink; m_pLink = pSightEnt; - if ( pSightEnt == m_hEnemy ) + 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; @@ -171,30 +171,30 @@ void CBaseMonster :: Look ( int iDistance ) // 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 ) ) + switch( IRelationship( pSightEnt ) ) { - case R_NM: + case R_NM: iSighted |= bits_COND_SEE_NEMESIS; break; - case R_HT: + case R_HT: iSighted |= bits_COND_SEE_HATE; break; - case R_DL: + case R_DL: iSighted |= bits_COND_SEE_DISLIKE; break; - case R_FR: + case R_FR: iSighted |= bits_COND_SEE_FEAR; break; - case R_AL: + case R_AL: break; default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + ALERT( at_aiconsole, "%s can't assess %s\n", STRING( pev->classname ), STRING(pSightEnt->pev->classname ) ); break; } } } } - + SetConditions( iSighted ); } @@ -207,43 +207,43 @@ void CBaseMonster :: Look ( int iDistance ) // !!!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 *CBaseMonster::BestVisibleEnemy( void ) { CBaseEntity *pReturn; CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; + 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 ) + while( pNextEnt != NULL ) { - if ( pNextEnt->IsAlive() ) + if( pNextEnt->IsAlive() ) { - if ( IRelationship( pNextEnt) > iBestRelationship ) + 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 ); + iBestRelationship = IRelationship( pNextEnt ); iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); pReturn = pNextEnt; } - else if ( IRelationship( pNextEnt) == iBestRelationship ) + 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 ) + + if( iDist <= iNearest ) { iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); + iBestRelationship = IRelationship( pNextEnt ); pReturn = pNextEnt; } } diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index fead70cf..cd5ffaf2 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -29,7 +29,7 @@ #include "voice_gamemgr.h" #include "hltv.h" -extern DLL_GLOBAL CGameRules *g_pGameRules; +extern DLL_GLOBAL CGameRules *g_pGameRules; extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages extern int gmsgScoreInfo; @@ -51,11 +51,11 @@ CVoiceGameMgr g_VoiceGameMgr; class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper { public: - virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) { - if ( g_teamplay ) + if( g_teamplay ) { - if ( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) + if( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) { return false; } @@ -70,13 +70,11 @@ static CMultiplayGameMgrHelper g_GameMgrHelper; //********************************************************* // Rules for the half-life multiplayer game. //********************************************************* - -CHalfLifeMultiplay :: CHalfLifeMultiplay() +CHalfLifeMultiplay::CHalfLifeMultiplay() { #ifndef NO_VOICEGAMEMGR - g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); + g_VoiceGameMgr.Init( &g_GameMgrHelper, gpGlobals->maxClients ); #endif - RefreshSkillData(); m_flIntermissionEndTime = 0; g_flIntermissionStartTime = 0; @@ -90,12 +88,12 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() // 3/31/99 // Added lservercfg file cvar, since listen and dedicated servers should not // share a single config file. (sjb) - if ( IS_DEDICATED_SERVER() ) + if( IS_DEDICATED_SERVER() ) { // dedicated server char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); - if ( servercfgfile && servercfgfile[0] ) + if( servercfgfile && servercfgfile[0] ) { char szCommand[256]; @@ -109,7 +107,7 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() // listen server char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); - if ( lservercfgfile && lservercfgfile[0] ) + if( lservercfgfile && lservercfgfile[0] ) { char szCommand[256]; @@ -123,10 +121,10 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { #ifndef NO_VOICEGAMEMGR - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + if( g_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) ) return TRUE; #endif - return CGameRules::ClientCommand(pPlayer, pcmd); + return CGameRules::ClientCommand( pPlayer, pcmd ); } //========================================================= @@ -191,10 +189,10 @@ extern cvar_t mp_chattime; //========================================================= //========================================================= -void CHalfLifeMultiplay :: Think ( void ) +void CHalfLifeMultiplay::Think( void ) { #ifndef NO_VOICEGAMEMGR - g_VoiceGameMgr.Update(gpGlobals->frametime); + g_VoiceGameMgr.Update( gpGlobals->frametime ); #endif ///// Check game rules ///// @@ -204,22 +202,22 @@ void CHalfLifeMultiplay :: Think ( void ) int frags_remaining = 0; int time_remaining = 0; - if ( g_fGameOver ) // someone else quit the game already + if( g_fGameOver ) // someone else quit the game already { // bounds check int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) + if( time < 1 ) CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) + 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_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) ) + 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 } @@ -229,58 +227,56 @@ void CHalfLifeMultiplay :: Think ( void ) float flTimeLimit = timelimit.value * 60; float flFragLimit = fraglimit.value; - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) + time_remaining = (int)( flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + + if( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) { GoToIntermission(); return; } - if ( flFragLimit ) + if( flFragLimit ) { int bestfrags = 9999; int remain; // check if any player is over the frag limit - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) + if( pPlayer && pPlayer->pev->frags >= flFragLimit ) { GoToIntermission(); return; } - - if ( pPlayer ) + if( pPlayer ) { remain = flFragLimit - pPlayer->pev->frags; - if ( remain < bestfrags ) + if( remain < bestfrags ) { bestfrags = remain; } } - } frags_remaining = bestfrags; } // Updates when frags change - if ( frags_remaining != last_frags ) + if( frags_remaining != last_frags ) { g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); } // Updates once per second - if ( timeleft.value != last_time ) + if( timeleft.value != last_time ) { g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); } last_frags = frags_remaining; - last_time = time_remaining; + last_time = time_remaining; } //========================================================= @@ -308,25 +304,25 @@ BOOL CHalfLifeMultiplay::IsCoOp( void ) //========================================================= BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { - if ( !pWeapon->CanDeploy() ) + if( !pWeapon->CanDeploy() ) { // that weapon can't deploy anyway. return FALSE; } - if ( !pPlayer->m_pActiveItem ) + if( !pPlayer->m_pActiveItem ) { // player doesn't have an active item! return TRUE; } - if ( !pPlayer->m_pActiveItem->CanHolster() ) + if( !pPlayer->m_pActiveItem->CanHolster() ) { // can't put away the active item. return FALSE; } - if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) + if( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) { return TRUE; } @@ -334,9 +330,8 @@ BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerI return FALSE; } -BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +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; @@ -345,19 +340,19 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI iBestWeight = -1;// no weapon lower than -1 can be autoswitched to pBest = NULL; - if ( !pCurrentWeapon->CanHolster() ) + 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++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - pCheck = pPlayer->m_rgpPlayerItems[ i ]; + pCheck = pPlayer->m_rgpPlayerItems[i]; - while ( pCheck ) + while( pCheck ) { - if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) + if( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) { // this weapon is from the same category. if ( pCheck->CanDeploy() ) @@ -368,13 +363,13 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI } } } - else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of + 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( pCheck->CanDeploy() ) { // if this weapon is useable, flag it as the best iBestWeight = pCheck->iWeight(); @@ -391,7 +386,7 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI // 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 ) + if( !pBest ) { return FALSE; } @@ -403,10 +398,10 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI //========================================================= //========================================================= -BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +BOOL CHalfLifeMultiplay::ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) { #ifndef NO_VOICEGAMEMGR - g_VoiceGameMgr.ClientConnected(pEntity); + g_VoiceGameMgr.ClientConnected( pEntity ); #endif return TRUE; } @@ -414,21 +409,21 @@ BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszNam extern int gmsgSayText; extern int gmsgGameMode; -void CHalfLifeMultiplay :: UpdateGameMode( CBasePlayer *pPlayer ) +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 ) +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" ) ); + ( pl->pev->netname && STRING( pl->pev->netname )[0] != 0 ) ? STRING( pl->pev->netname ) : "unconnected" ) ); // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n", STRING( pl->pev->netname ), @@ -460,12 +455,12 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) 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++ ) + 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 ) + if( plr ) { MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); WRITE_BYTE( i ); // client number @@ -477,7 +472,7 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) } } - if ( g_fGameOver ) + if( g_fGameOver ) { MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() ); MESSAGE_END(); @@ -486,18 +481,18 @@ void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) //========================================================= //========================================================= -void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) +void CHalfLifeMultiplay::ClientDisconnected( edict_t *pClient ) { - if ( pClient ) + if( pClient ) { CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - if ( pPlayer ) + if( pPlayer ) { FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", STRING( pPlayer->pev->netname ), @@ -521,18 +516,20 @@ void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) //========================================================= //========================================================= -float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) +float CHalfLifeMultiplay::FlPlayerFallDamage( CBasePlayer *pPlayer ) { int iFallDamage = (int)falldamage.value; - switch ( iFallDamage ) + switch( iFallDamage ) { - case 1://progressive + case 1: + //progressive pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; break; default: - case 0:// fixed + case 0: + // fixed return 10; break; } @@ -547,12 +544,12 @@ BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity //========================================================= //========================================================= -void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) +void CHalfLifeMultiplay::PlayerThink( CBasePlayer *pPlayer ) { - if ( g_fGameOver ) + if( g_fGameOver ) { // check for button presses - if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) + if( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) m_iEndIntermissionButtonHit = TRUE; // clear attack/use commands from player @@ -564,22 +561,22 @@ void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) //========================================================= //========================================================= -void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) +void CHalfLifeMultiplay::PlayerSpawn( CBasePlayer *pPlayer ) { BOOL addDefault; CBaseEntity *pWeaponEntity = NULL; - pPlayer->pev->weapons |= (1<pev->weapons |= ( 1 << WEAPON_SUIT ); + addDefault = TRUE; - while ( ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" ) ) ) + while( ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" ) ) ) { pWeaponEntity->Touch( pPlayer ); addDefault = FALSE; } - if ( addDefault ) + if( addDefault ) { pPlayer->GiveNamedItem( "weapon_crowbar" ); pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); @@ -589,19 +586,19 @@ void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) //========================================================= //========================================================= -BOOL CHalfLifeMultiplay :: FPlayerCanRespawn( CBasePlayer *pPlayer ) +BOOL CHalfLifeMultiplay::FPlayerCanRespawn( CBasePlayer *pPlayer ) { return TRUE; } //========================================================= //========================================================= -float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) +float CHalfLifeMultiplay::FlPlayerSpawnTime( CBasePlayer *pPlayer ) { return gpGlobals->time;//now! } -BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) +BOOL CHalfLifeMultiplay::AllowAutoTargetCrosshair( void ) { return ( aimcrosshair.value != 0 ); } @@ -610,7 +607,7 @@ BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) // IPointsForKill - how many points awarded to anyone // that kills this player? //========================================================= -int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +int CHalfLifeMultiplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) { return 1; } @@ -618,7 +615,7 @@ int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *p //========================================================= // PlayerKilled - someone/something killed this player //========================================================= -void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) { DeathNotice( pVictim, pKiller, pInflictor ); @@ -627,19 +624,19 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); CBasePlayer *peKiller = NULL; CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); - if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) + if( ktmp && (ktmp->Classify() == CLASS_PLAYER ) ) peKiller = (CBasePlayer*)ktmp; - if ( pVictim->pev == pKiller ) + if( pVictim->pev == pKiller ) { // killed self pKiller->frags -= 1; } - else if ( ktmp && ktmp->IsPlayer() ) + 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 @@ -660,23 +657,23 @@ void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKille // killers score, if it's a player CBaseEntity *ep = CBaseEntity::Instance( pKiller ); - if ( ep && ep->Classify() == CLASS_PLAYER ) + if( ep && ep->Classify() == CLASS_PLAYER ) { CBasePlayer *PK = (CBasePlayer*)ep; MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(PK->edict()) ); + WRITE_BYTE( ENTINDEX( PK->edict() ) ); WRITE_SHORT( PK->pev->frags ); WRITE_SHORT( PK->m_iDeaths ); WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( PK->m_szTeamName) + 1 ); + 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") ) + if( pVictim->HasNamedPlayerItem( "weapon_satchel" ) ) { DeactivateSatchels( pVictim ); } @@ -693,23 +690,23 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *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 char *tau = "tau_cannon"; char *gluon = "gluon gun"; - if ( pKiller->flags & FL_CLIENT ) + if( pKiller->flags & FL_CLIENT ) { - killer_index = ENTINDEX(ENT(pKiller)); - - if ( pevInflictor ) + killer_index = ENTINDEX( ENT( pKiller ) ); + + if( pevInflictor ) { - if ( pevInflictor == pKiller ) + 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 ) + + if( pPlayer->m_pActiveItem ) { killer_weapon_name = pPlayer->m_pActiveItem->pszName(); } @@ -726,31 +723,31 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, } // strip the monster_* or weapon_* from the inflictor's classname - if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) + if( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) killer_weapon_name += 7; - else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) + else if( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) killer_weapon_name += 8; - else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) + 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_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" ) ) + if( !strcmp( killer_weapon_name, "egon" ) ) killer_weapon_name = gluon; - else if ( !strcmp( killer_weapon_name, "gauss" ) ) + else if( !strcmp( killer_weapon_name, "gauss" ) ) killer_weapon_name = tau; - if ( pVictim->pev == pKiller ) + if( pVictim->pev == pKiller ) { // killed self // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING( pVictim->pev->netname ), @@ -769,10 +766,10 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, killer_weapon_name ); } } - else if ( pKiller->flags & FL_CLIENT ) + else if( pKiller->flags & FL_CLIENT ) { // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING( pKiller->netname ), @@ -804,7 +801,7 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, // killed by the world // team match? - if ( g_teamplay ) + if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING( pVictim->pev->netname ), @@ -825,60 +822,60 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, } 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 + 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) + 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 ]; + char szText[128]; - if ( pKiller->flags & FL_MONSTER ) + if( pKiller->flags & FL_MONSTER ) { // killed by a monster - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was killed by a monster.\n" ); + strcpy( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, " was killed by a monster.\n" ); return; } - if ( pKiller == pVictim->pev ) + if( pKiller == pVictim->pev ) { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " commited suicide.\n" ); + strcpy( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, " commited suicide.\n" ); } - else if ( pKiller->flags & FL_CLIENT ) + else if( pKiller->flags & FL_CLIENT ) { - strcpy ( szText, STRING( pKiller->netname ) ); + strcpy( szText, STRING( pKiller->netname ) ); strcat( szText, " : " ); strcat( szText, killer_weapon_name ); strcat( szText, " : " ); - strcat ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, "\n" ); + strcat( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, "\n" ); } - else if ( FClassnameIs ( pKiller, "worldspawn" ) ) + else if( FClassnameIs( pKiller, "worldspawn" ) ) { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " fell or drowned or something.\n" ); + strcpy( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, " fell or drowned or something.\n" ); } - else if ( pKiller->solid == SOLID_BSP ) + else if( pKiller->solid == SOLID_BSP ) { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was mooshed.\n" ); + strcpy( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, " was mooshed.\n" ); } else { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " died mysteriously.\n" ); + strcpy( szText, STRING( pVictim->pev->netname ) ); + strcat( szText, " died mysteriously.\n" ); } UTIL_ClientPrintAll( szText ); @@ -889,7 +886,7 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, // PlayerGotWeapon - player has grabbed a weapon that was // sitting in the world //========================================================= -void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +void CHalfLifeMultiplay::PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { } @@ -897,12 +894,12 @@ void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerIte // FlWeaponRespawnTime - what is the time in the future // at which this weapon may spawn? //========================================================= -float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) +float CHalfLifeMultiplay::FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) { - if ( weaponstay.value > 0 ) + if( weaponstay.value > 0 ) { // make sure it's only certain weapons - if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) + if( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD ) ) { return gpGlobals->time + 0; // weapon respawns almost instantly } @@ -920,11 +917,11 @@ float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) // now, otherwise it returns the time at which it can try // to spawn again. //========================================================= -float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) +float CHalfLifeMultiplay::FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) { - if ( pWeapon && pWeapon->m_iId && (pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) + if( pWeapon && pWeapon->m_iId && ( pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD ) ) { - if ( NUMBER_OF_ENTITIES() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) ) + if( NUMBER_OF_ENTITIES() < ( gpGlobals->maxEntities - ENTITY_INTOLERANCE ) ) return 0; // we're past the entity tolerance level, so delay the respawn @@ -938,7 +935,7 @@ float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) // VecWeaponRespawnSpot - where should this weapon spawn? // Some game variations may choose to randomize spawn locations //========================================================= -Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) +Vector CHalfLifeMultiplay::VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) { return pWeapon->pev->origin; } @@ -947,9 +944,9 @@ Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) // WeaponShouldRespawn - any conditions inhibiting the // respawning of this weapon? //========================================================= -int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) +int CHalfLifeMultiplay::WeaponShouldRespawn( CBasePlayerItem *pWeapon ) { - if ( pWeapon->pev->spawnflags & SF_NORESPAWN ) + if( pWeapon->pev->spawnflags & SF_NORESPAWN ) { return GR_WEAPON_RESPAWN_NO; } @@ -963,19 +960,19 @@ int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) //========================================================= BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) { - if ( weaponstay.value > 0 ) + if( weaponstay.value > 0 ) { - if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) + 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++ ) + for( int i = 0; i < MAX_ITEM_TYPES; i++ ) { CBasePlayerItem *it = pPlayer->m_rgpPlayerItems[i]; - while ( it != NULL ) + while( it != NULL ) { - if ( it->m_iId == pItem->m_iId ) + if( it->m_iId == pItem->m_iId ) { return FALSE; } @@ -1005,7 +1002,7 @@ void CHalfLifeMultiplay::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) //========================================================= int CHalfLifeMultiplay::ItemShouldRespawn( CItem *pItem ) { - if ( pItem->pev->spawnflags & SF_NORESPAWN ) + if( pItem->pev->spawnflags & SF_NORESPAWN ) { return GR_ITEM_RESPAWN_NO; } @@ -1040,7 +1037,7 @@ void CHalfLifeMultiplay::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int //========================================================= BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) { -// if ( pEntity->pev->flags & FL_MONSTER ) +// if( pEntity->pev->flags & FL_MONSTER ) // return FALSE; return TRUE; @@ -1050,7 +1047,7 @@ BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) //========================================================= int CHalfLifeMultiplay::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) { - if ( pAmmo->pev->spawnflags & SF_NORESPAWN ) + if( pAmmo->pev->spawnflags & SF_NORESPAWN ) { return GR_AMMO_RESPAWN_NO; } @@ -1101,9 +1098,9 @@ int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) { edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); - if ( IsMultiplayer() && pentSpawnSpot->v.target ) + if( IsMultiplayer() && pentSpawnSpot->v.target ) { - FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); + FireTargets( STRING( pentSpawnSpot->v.target ), pPlayer, pPlayer, USE_TOGGLE, 0 ); } return pentSpawnSpot; @@ -1117,25 +1114,25 @@ int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *p return GR_NOTTEAMMATE; } -BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) +BOOL CHalfLifeMultiplay::PlayFootstepSounds( CBasePlayer *pl, float fvol ) { - if ( g_footsteps && g_footsteps->value == 0 ) + if( g_footsteps && g_footsteps->value == 0 ) return FALSE; - if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > 220 ) + 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 ) -{ +BOOL CHalfLifeMultiplay::FAllowFlashlight( void ) +{ return flashlight.value != 0; } //========================================================= //========================================================= -BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) +BOOL CHalfLifeMultiplay::FAllowMonsters( void ) { return ( allowmonsters.value != 0 ); } @@ -1144,19 +1141,19 @@ BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) //======== CHalfLifeMultiplay private functions =========== #define INTERMISSION_TIME 6 -void CHalfLifeMultiplay :: GoToIntermission( void ) +void CHalfLifeMultiplay::GoToIntermission( void ) { - if ( g_fGameOver ) + if( g_fGameOver ) return; // intermission has already been triggered, so ignore. - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); + MESSAGE_BEGIN( MSG_ALL, SVC_INTERMISSION ); MESSAGE_END(); // bounds check int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) + if( time < 1 ) CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) + else if( time > MAX_INTERMISSION_TIME ) CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); m_flIntermissionEndTime = gpGlobals->time + ( (int)mp_chattime.value ); @@ -1172,9 +1169,9 @@ typedef struct mapcycle_item_s { struct mapcycle_item_s *next; - char mapname[ 32 ]; - int minplayers, maxplayers; - char rulebuffer[ MAX_RULE_BUFFER ]; + char mapname[32]; + int minplayers, maxplayers; + char rulebuffer[MAX_RULE_BUFFER]; } mapcycle_item_t; typedef struct mapcycle_s @@ -1194,11 +1191,11 @@ void DestroyMapCycle( mapcycle_t *cycle ) { mapcycle_item_t *p, *n, *start; p = cycle->items; - if ( p ) + if( p ) { start = p; p = p->next; - while ( p != start ) + while( p != start ) { n = p->next; delete p; @@ -1211,7 +1208,7 @@ void DestroyMapCycle( mapcycle_t *cycle ) cycle->next_item = NULL; } -static char com_token[ 1500 ]; +static char com_token[1500]; /* ============== @@ -1220,42 +1217,42 @@ COM_Parse Parse a token out of a string ============== */ -char *COM_Parse (char *data) +char *COM_Parse( char *data ) { - int c; - int len; + int c; + int len; len = 0; com_token[0] = 0; - if (!data) + if( !data ) return NULL; // skip whitespace skipwhite: - while ( (c = *data) <= ' ') + while( ( c = *data ) <= ' ') { - if (c == 0) + if( c == 0 ) return NULL; // end of file; data++; } // skip // comments - if (c=='/' && data[1] == '/') + if( c=='/' && data[1] == '/' ) { - while (*data && *data != '\n') + while( *data && *data != '\n' ) data++; goto skipwhite; } // handle quoted strings specially - if (c == '\"') + if( c == '\"' ) { data++; - while (1) + while( 1 ) { c = *data++; - if (c=='\"' || !c) + if( c=='\"' || !c ) { com_token[len] = 0; return data; @@ -1266,12 +1263,12 @@ skipwhite: } // parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + if( c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) { com_token[len] = c; len++; com_token[len] = 0; - return data+1; + return data + 1; } // parse a regular word @@ -1281,9 +1278,9 @@ skipwhite: data++; len++; c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + if( c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) break; - } while (c>32); + } while ( c > 32 ); com_token[len] = 0; return data; @@ -1301,9 +1298,9 @@ int COM_TokenWaiting( char *buffer ) char *p; p = buffer; - while ( *p && *p!='\n') + while( *p && *p!='\n') { - if ( !isspace( *p ) || isalnum( *p ) ) + if( !isspace( *p ) || isalnum( *p ) ) return 1; p++; @@ -1316,39 +1313,38 @@ int COM_TokenWaiting( char *buffer ) ============== ReloadMapCycleFile - Parses mapcycle.txt file into mapcycle_t structure ============== */ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) { - char szBuffer[ MAX_RULE_BUFFER ]; - char szMap[ 32 ]; + 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 ) + if( pFileList && length ) { // the first map name in the file becomes the default - while ( 1 ) + while( 1 ) { hasbuffer = 0; memset( szBuffer, 0, MAX_RULE_BUFFER ); pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) <= 0 ) + if( strlen( com_token ) <= 0 ) break; strcpy( szMap, com_token ); // Any more tokens on this line? - if ( COM_TokenWaiting( pFileList ) ) + if( COM_TokenWaiting( pFileList ) ) { pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) > 0 ) + if( strlen( com_token ) > 0 ) { hasbuffer = 1; strcpy( szBuffer, com_token ); @@ -1356,7 +1352,7 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) } // Check map - if ( IS_MAP_VALID( szMap ) ) + if( IS_MAP_VALID( szMap ) ) { // Create entry char *s; @@ -1370,17 +1366,17 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); - if ( hasbuffer ) + if( hasbuffer ) { s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); - if ( s && s[0] ) + 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] ) + if( s && s[0] ) { item->maxplayers = atoi( s ); item->maxplayers = max( item->maxplayers, 0 ); @@ -1402,7 +1398,6 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) { ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); } - } FREE_FILE( aFileList ); @@ -1412,7 +1407,7 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) item = cycle->items; // Reverse it to get original order - while ( item ) + while( item ) { next = item->next; item->next = newlist; @@ -1423,12 +1418,12 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) item = cycle->items; // Didn't parse anything - if ( !item ) + if( !item ) { return 0; } - while ( item->next ) + while( item->next ) { item = item->next; } @@ -1448,13 +1443,13 @@ Determine the current # of active players on the server for map cycling logic */ int CountPlayers( void ) { - int num = 0; + int num = 0; - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); - if ( pEnt ) + if( pEnt ) { num = num + 1; } @@ -1474,18 +1469,18 @@ Parse commands/key value pairs to issue right after map xxx command is issued on void ExtractCommandString( char *s, char *szCommand ) { // Now make rules happen - char pkey[512]; - char value[512]; // use two buffers so compares + char pkey[512]; + char value[512]; // use two buffers so compares // work without stomping on each other - char *o; + char *o; - if ( *s == '\\' ) + if( *s == '\\' ) s++; - while (1) + while( 1 ) { o = pkey; - while ( *s != '\\' ) + while( *s != '\\' ) { if ( !*s ) return; @@ -1496,23 +1491,23 @@ void ExtractCommandString( char *s, char *szCommand ) o = value; - while (*s != '\\' && *s) + while( *s != '\\' && *s ) { - if (!*s) + if( !*s ) return; *o++ = *s++; } *o = 0; strcat( szCommand, pkey ); - if ( strlen( value ) > 0 ) + if( strlen( value ) > 0 ) { strcat( szCommand, " " ); strcat( szCommand, value ); } strcat( szCommand, "\n" ); - if (!*s) + if( !*s ) return; s++; } @@ -1525,64 +1520,64 @@ ChangeLevel Server is changing to a new level, check mapcycle.txt for map name and setup info ============== */ -void CHalfLifeMultiplay :: ChangeLevel( void ) +void CHalfLifeMultiplay::ChangeLevel( void ) { - static char szPreviousMapCycleFile[ 256 ]; + static char szPreviousMapCycleFile[256]; static mapcycle_t mapcycle; char szNextMap[32]; char szFirstMapInList[32]; - char szCommands[ 1500 ]; - char szRules[ 1500 ]; + char szCommands[1500]; + char szRules[1500]; int minplayers = 0, maxplayers = 0; strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 - int curplayers; + 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'; + szCommands[0] = '\0'; + szRules[0] = '\0'; curplayers = CountPlayers(); // Has the map cycle filename changed? - if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) + if( stricmp( mapcfile, szPreviousMapCycleFile ) ) { strcpy( szPreviousMapCycleFile, mapcfile ); DestroyMapCycle( &mapcycle ); - if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) + 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 ) + 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) ); + 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 ) + for( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) { keeplooking = FALSE; ASSERT( item != NULL ); - if ( item->minplayers != 0 ) + if( item->minplayers != 0 ) { - if ( curplayers >= item->minplayers ) + if( curplayers >= item->minplayers ) { found = TRUE; minplayers = item->minplayers; @@ -1593,9 +1588,9 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) } } - if ( item->maxplayers != 0 ) + if( item->maxplayers != 0 ) { - if ( curplayers <= item->maxplayers ) + if( curplayers <= item->maxplayers ) { found = TRUE; maxplayers = item->maxplayers; @@ -1606,18 +1601,18 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) } } - if ( keeplooking ) + if( keeplooking ) continue; found = TRUE; break; } - if ( !found ) + if( !found ) { item = mapcycle.next_item; - } - + } + // Increment next item pointer mapcycle.next_item = item->next; @@ -1628,7 +1623,7 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) strcpy( szRules, item->rulebuffer ); } - if ( !IS_MAP_VALID(szNextMap) ) + if( !IS_MAP_VALID( szNextMap ) ) { strcpy( szNextMap, szFirstMapInList ); } @@ -1636,17 +1631,17 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) g_fGameOver = TRUE; ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); - if ( minplayers || maxplayers ) + if( minplayers || maxplayers ) { ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); } - if ( strlen( szRules ) > 0 ) + if( strlen( szRules ) > 0 ) { ALERT( at_console, "RULES: %s\n", szRules ); } - + CHANGE_LEVEL( szNextMap, NULL ); - if ( strlen( szCommands ) > 0 ) + if( strlen( szCommands ) > 0 ) { SERVER_COMMAND( szCommands ); } @@ -1655,7 +1650,7 @@ void CHalfLifeMultiplay :: ChangeLevel( void ) #define MAX_MOTD_CHUNK 60 #define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) -void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) +void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client ) { // read from the MOTD.txt file int length, char_count = 0; @@ -1664,17 +1659,17 @@ void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) // send the server name MESSAGE_BEGIN( MSG_ONE, gmsgServerName, NULL, client ); - WRITE_STRING( CVAR_GET_STRING("hostname") ); + 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 ) + while( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) { - char chunk[MAX_MOTD_CHUNK+1]; + char chunk[MAX_MOTD_CHUNK + 1]; - if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) + if( strlen( pFileList ) < MAX_MOTD_CHUNK ) { strcpy( chunk, pFileList ); } @@ -1685,7 +1680,7 @@ void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) } char_count += strlen( chunk ); - if ( char_count < MAX_MOTD_LENGTH ) + if( char_count < MAX_MOTD_LENGTH ) pFileList = aFileList + char_count; else *pFileList = 0; diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 7b6e6331..58317b3c 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -28,14 +28,14 @@ class CNihilanth : public CBaseMonster { public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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; } + int Classify( void ) { return CLASS_ALIEN_MILITARY; }; + int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } void Killed( entvars_t *pevAttacker, int iGib ); void GibMonster( void ); @@ -66,9 +66,9 @@ public: 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); + + 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 ); @@ -112,7 +112,7 @@ public: EHANDLE m_hRecharger; EHANDLE m_hSphere[N_SPHERES]; - int m_iActiveSpheres; + int m_iActiveSpheres; float m_flAdj; @@ -172,9 +172,9 @@ IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ) class CNihilanthHVR : public CBaseMonster { public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; void Spawn( void ); void Precache( void ); @@ -192,7 +192,7 @@ public: 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 ); @@ -231,68 +231,68 @@ IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ) // Nihilanth, final Boss monster //========================================================= -const char *CNihilanth::pAttackSounds[] = +const char *CNihilanth::pAttackSounds[] = { "X/x_attack1.wav", "X/x_attack2.wav", "X/x_attack3.wav", }; -const char *CNihilanth::pBallSounds[] = +const char *CNihilanth::pBallSounds[] = { "X/x_ballattack1.wav", }; -const char *CNihilanth::pShootSounds[] = +const char *CNihilanth::pShootSounds[] = { "X/x_shoot1.wav", }; -const char *CNihilanth::pRechargeSounds[] = +const char *CNihilanth::pRechargeSounds[] = { "X/x_recharge1.wav", "X/x_recharge2.wav", "X/x_recharge3.wav", }; -const char *CNihilanth::pLaughSounds[] = +const char *CNihilanth::pLaughSounds[] = { "X/x_laugh1.wav", "X/x_laugh2.wav", }; -const char *CNihilanth::pPainSounds[] = +const char *CNihilanth::pPainSounds[] = { "X/x_pain1.wav", "X/x_pain2.wav", }; -const char *CNihilanth::pDeathSounds[] = +const char *CNihilanth::pDeathSounds[] = { "X/x_die1.wav", }; -void CNihilanth :: Spawn( void ) +void CNihilanth::Spawn( void ) { - Precache( ); + Precache(); // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; - SET_MODEL(edict(), "models/nihilanth.mdl"); + 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_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); UTIL_SetOrigin( pev, pev->origin ); - pev->flags |= FL_MONSTER; + pev->flags |= FL_MONSTER; pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.nihilanthHealth; + pev->health = gSkillData.nihilanthHealth; pev->view_ofs = Vector( 0, 0, 300 ); m_flFieldOfView = -1; // 360 degrees pev->sequence = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); InitBoneControllers(); @@ -305,12 +305,18 @@ void CNihilanth :: Spawn( void ) 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" ); + 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 /* @@ -323,8 +329,8 @@ void CNihilanth :: Spawn( void ) void CNihilanth::Precache( void ) { - PRECACHE_MODEL("models/nihilanth.mdl"); - PRECACHE_MODEL("sprites/lgtning.spr"); + 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" ); @@ -336,34 +342,34 @@ void CNihilanth::Precache( void ) PRECACHE_SOUND_ARRAY( pLaughSounds ); PRECACHE_SOUND_ARRAY( pPainSounds ); PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND("debris/beamstart7.wav"); + PRECACHE_SOUND( "debris/beamstart7.wav" ); } -void CNihilanth :: PainSound( void ) +void CNihilanth::PainSound( void ) { - if (m_flNextPainSound > gpGlobals->time) + if( m_flNextPainSound > gpGlobals->time ) return; - + m_flNextPainSound = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - if (pev->health > gSkillData.nihilanthHealth / 2) + if( pev->health > gSkillData.nihilanthHealth / 2 ) { EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1.0, 0.2 ); } - else if (m_irritation >= 2) + else if( m_irritation >= 2 ) { EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0, 0.2 ); } -} +} -void CNihilanth :: DeathSound( void ) +void CNihilanth::DeathSound( void ) { EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1.0, 0.1 ); } void CNihilanth::NullThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.5; } @@ -381,54 +387,54 @@ void CNihilanth::StartupThink( void ) CBaseEntity *pEntity; - pEntity = UTIL_FindEntityByTargetname( NULL, "n_min"); - if (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) + 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++) + for( int i = 0; i < N_SPHERES; i++ ) { - EmitSphere( ); + EmitSphere(); } m_hRecharger = NULL; - SetThink( &CNihilanth::HuntThink); + SetThink( &CNihilanth::HuntThink ); SetUse( &CNihilanth::CommandUse ); pev->nextthink = gpGlobals->time + 0.1; } -void CNihilanth :: Killed( entvars_t *pevAttacker, int iGib ) +void CNihilanth::Killed( entvars_t *pevAttacker, int iGib ) { CBaseMonster::Killed( pevAttacker, iGib ); } -void CNihilanth :: DyingThink( void ) +void CNihilanth::DyingThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); + DispatchAnimEvents(); + StudioFrameAdvance(); - if (pev->deadflag == DEAD_NO) + if( pev->deadflag == DEAD_NO ) { - DeathSound( ); + DeathSound(); pev->deadflag = DEAD_DYING; m_posDesired.z = m_flMaxZ; } - if (pev->deadflag == DEAD_DYING) + if( pev->deadflag == DEAD_DYING ) { - Flight( ); + Flight(); - if (fabs( pev->origin.z - m_flMaxZ ) < 16) + if( fabs( pev->origin.z - m_flMaxZ ) < 16 ) { pev->velocity = Vector( 0, 0, 0 ); FireTargets( m_szDeadUse, this, this, USE_ON, 1.0 ); @@ -436,22 +442,22 @@ void CNihilanth :: DyingThink( void ) } } - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { pev->avelocity.y += RANDOM_FLOAT( -100, 100 ); - if (pev->avelocity.y < -100) + if( pev->avelocity.y < -100 ) pev->avelocity.y = -100; - if (pev->avelocity.y > 100) + if( pev->avelocity.y > 100 ) pev->avelocity.y = 100; pev->sequence = LookupSequence( "die1" ); } - if (m_pBall) + if( m_pBall ) { - if (m_pBall->pev->renderamt > 0) + if( m_pBall->pev->renderamt > 0 ) { - m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2); + m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2 ); } else { @@ -466,28 +472,32 @@ void CNihilanth :: DyingThink( void ) 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); + 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 )) + switch( RANDOM_LONG( 1, 4 ) ) { - case 1: // head + 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) + 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) + 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) + case 4: + // right hand + if( DotProduct( vecDir, gpGlobals->v_right ) < 0 ) vecDir = vecDir * -1; vecDir = vecDir + 2 * gpGlobals->v_right; break; @@ -497,8 +507,8 @@ void CNihilanth :: DyingThink( void ) TraceResult tr; - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 4096, ignore_monsters, ENT(pev), &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 ); @@ -520,8 +530,8 @@ void CNihilanth :: DyingThink( void ) 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( ); + pEntity->pev->velocity = Vector( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; + pEntity->GreenBallInit(); return; } @@ -529,37 +539,37 @@ void CNihilanth :: DyingThink( void ) void CNihilanth::CrashTouch( CBaseEntity *pOther ) { // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) + if( pOther->pev->solid == SOLID_BSP ) { SetTouch( NULL ); pev->nextthink = gpGlobals->time; } } -void CNihilanth :: GibMonster( void ) +void CNihilanth::GibMonster( void ) { - // EMIT_SOUND_DYN(edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); + // EMIT_SOUND_DYN( edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200 ); } -void CNihilanth :: FloatSequence( void ) +void CNihilanth::FloatSequence( void ) { - if (m_irritation >= 2) + if( m_irritation >= 2 ) { pev->sequence = LookupSequence( "float_open" ); } - else if (m_avelocity.y > 30) + else if( m_avelocity.y > 30 ) { pev->sequence = LookupSequence( "walk_r" ); } - else if (m_avelocity.y < -30) + else if( m_avelocity.y < -30 ) { pev->sequence = LookupSequence( "walk_l" ); } - else if (m_velocity.z > 30) + else if( m_velocity.z > 30 ) { pev->sequence = LookupSequence( "walk_u" ); } - else if (m_velocity.z < -30) + else if( m_velocity.z < -30 ) { pev->sequence = LookupSequence( "walk_d" ); } @@ -569,33 +579,33 @@ void CNihilanth :: FloatSequence( void ) } } -void CNihilanth :: ShootBalls( void ) +void CNihilanth::ShootBalls( void ) { - if (m_flShootEnd > gpGlobals->time) + if( m_flShootEnd > gpGlobals->time ) { Vector vecHand, vecAngle; - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) + while( m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time ) { - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { 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); + 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); + 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 ); @@ -605,46 +615,46 @@ void CNihilanth :: ShootBalls( void ) } } -void CNihilanth :: MakeFriend( Vector vecStart ) +void CNihilanth::MakeFriend( Vector vecStart ) { int i; - for (i = 0; i < 3; i++) + for( i = 0; i < 3; i++ ) { - if (m_hFriend[i] != NULL && !m_hFriend[i]->IsAlive()) + if( m_hFriend[i] != NULL && !m_hFriend[i]->IsAlive() ) { - if (pev->rendermode == kRenderNormal) // don't do it if they are already fading - m_hFriend[i]->MyMonsterPointer()->FadeMonster( ); + 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] == NULL) + if( m_hFriend[i] == NULL ) { - if (RANDOM_LONG(0, 1) == 0) + if( RANDOM_LONG( 0, 1 ) == 0 ) { - int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_AIR ); - if (iNode != NO_NODE) + 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 ); + 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) + 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( tr.fStartSolid == 0 ) + m_hFriend[i] = Create( "monster_alien_slave", node.m_vecOrigin, pev->angles ); } } - if (m_hFriend[i] != NULL) + if( m_hFriend[i] != NULL ) { EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); } @@ -654,30 +664,30 @@ void CNihilanth :: MakeFriend( Vector vecStart ) } } -void CNihilanth :: NextActivity( ) +void CNihilanth::NextActivity() { UTIL_MakeAimVectors( pev->angles ); - if (m_irritation >= 2) + if( m_irritation >= 2 ) { - if (m_pBall == NULL) + if( m_pBall == NULL ) { m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); - if (m_pBall) + 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( ); + m_pBall->TurnOn(); } } - if (m_pBall) + if( m_pBall ) { MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment + WRITE_SHORT( entindex() + 0x1000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -691,7 +701,7 @@ void CNihilanth :: NextActivity( ) } } - if ((pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2) && m_hRecharger == NULL && m_iLevel <= 9) + if( ( pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2 ) && m_hRecharger == NULL && m_iLevel <= 9 ) { char szName[64]; @@ -699,23 +709,23 @@ void CNihilanth :: NextActivity( ) CBaseEntity *pRecharger = NULL; float flDist = 8192; - sprintf(szName, "%s%d", m_szRechargerTarget, m_iLevel ); + sprintf( szName, "%s%d", m_szRechargerTarget, m_iLevel ); - while ((pEnt = UTIL_FindEntityByTargetname( pEnt, szName )) != NULL) + while( ( pEnt = UTIL_FindEntityByTargetname( pEnt, szName ) ) != NULL ) { - float flLocal = (pEnt->pev->origin - pev->origin).Length(); - if (flLocal < flDist) + float flLocal = (pEnt->pev->origin - pev->origin ).Length(); + if( flLocal < flDist ) { flDist = flLocal; pRecharger = pEnt; - } + } } - if (pRecharger) + 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 = ( pRecharger->pev->origin - m_posDesired ).Normalize(); m_vecDesired.z = 0; m_vecDesired = m_vecDesired.Normalize(); } @@ -724,22 +734,22 @@ void CNihilanth :: NextActivity( ) m_hRecharger = NULL; ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); m_iLevel++; - if (m_iLevel > 9) + if( m_iLevel > 9 ) m_irritation = 2; } } - float flDist = (m_posDesired - pev->origin).Length(); + float flDist = ( m_posDesired - pev->origin ).Length(); float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); - if (m_hRecharger != NULL) + if( m_hRecharger != NULL ) { // at we at power up yet? - if (flDist < 128.0) + if( flDist < 128.0 ) { int iseq = LookupSequence( "recharge" ); - if (iseq != pev->sequence) + if( iseq != pev->sequence ) { char szText[64]; @@ -752,38 +762,38 @@ void CNihilanth :: NextActivity( ) } else { - FloatSequence( ); + FloatSequence(); } return; } - if (m_hEnemy != NULL && !m_hEnemy->IsAlive()) + if( m_hEnemy != NULL && !m_hEnemy->IsAlive() ) { m_hEnemy = NULL; } - if (m_flLastSeen + 15 < gpGlobals->time) + if( m_flLastSeen + 15 < gpGlobals->time ) { m_hEnemy = NULL; } - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { Look( 4096 ); - m_hEnemy = BestVisibleEnemy( ); + m_hEnemy = BestVisibleEnemy(); } - if (m_hEnemy != NULL && m_irritation != 0) + if( m_hEnemy != NULL && m_irritation != 0 ) { - if (m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0) + if( m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0 ) { - if (m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0) + if( m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0 ) { pev->sequence = LookupSequence( "attack1_open" ); } else { - if (RANDOM_LONG(0, 1 ) == 0) + if( RANDOM_LONG( 0, 1 ) == 0 ) { pev->sequence = LookupSequence( "attack1" ); // zap } @@ -797,7 +807,7 @@ void CNihilanth :: NextActivity( ) sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - if (pTrigger != NULL || pTouch != NULL) + if( pTrigger != NULL || pTouch != NULL ) { pev->sequence = LookupSequence( "attack2" ); // teleport } @@ -812,19 +822,19 @@ void CNihilanth :: NextActivity( ) } } - FloatSequence( ); + FloatSequence(); } -void CNihilanth :: HuntThink( void ) +void CNihilanth::HuntThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); + DispatchAnimEvents(); + StudioFrameAdvance(); - ShootBalls( ); + ShootBalls(); // if dead, force cancelation of current animation - if (pev->health <= 0) + if( pev->health <= 0 ) { SetThink( &CNihilanth::DyingThink ); m_fSequenceFinished = TRUE; @@ -834,31 +844,31 @@ void CNihilanth :: HuntThink( void ) // ALERT( at_console, "health %.0f\n", pev->health ); // if damaged, try to abosorb some spheres - if (pev->health < gSkillData.nihilanthHealth && AbsorbSphere( )) + if( pev->health < gSkillData.nihilanthHealth && AbsorbSphere() ) { pev->health += gSkillData.nihilanthHealth / N_SPHERES; } // get new sequence - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { - // if (!m_fSequenceLoops) + // if ( !m_fSequenceLoops ) pev->frame = 0; - NextActivity( ); - ResetSequenceInfo( ); - pev->framerate = 2.0 - 1.0 * (pev->health / gSkillData.nihilanthHealth); + NextActivity(); + ResetSequenceInfo(); + pev->framerate = 2.0 - 1.0 * ( pev->health / gSkillData.nihilanthHealth ); } // look for current enemy - if (m_hEnemy != NULL && m_hRecharger == NULL) + if( m_hEnemy != NULL && m_hRecharger == NULL ) { - if (FVisible( m_hEnemy )) + if( FVisible( m_hEnemy ) ) { - if (m_flLastSeen < gpGlobals->time - 5) + 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_vecTarget = ( m_posTarget - pev->origin ).Normalize(); m_vecDesired = m_vecTarget; m_posDesired = Vector( pev->origin.x, pev->origin.y, m_posTarget.z + m_flAdj ); } @@ -869,17 +879,17 @@ void CNihilanth :: HuntThink( void ) } // don't go too high - if (m_posDesired.z > m_flMaxZ) + if( m_posDesired.z > m_flMaxZ ) m_posDesired.z = m_flMaxZ; // don't go too low - if (m_posDesired.z < m_flMinZ) + if( m_posDesired.z < m_flMinZ ) m_posDesired.z = m_flMinZ; - Flight( ); + Flight(); } -void CNihilanth :: Flight( void ) +void CNihilanth::Flight( void ) { // estimate where I'll be facing in one seconds UTIL_MakeAimVectors( pev->angles + m_avelocity ); @@ -888,18 +898,18 @@ void CNihilanth :: Flight( void ) float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - if (flSide < 0) + if( flSide < 0 ) { - if (m_avelocity.y < 180) + if( m_avelocity.y < 180 ) { - m_avelocity.y += 6; // 9 * (3.0/2.0); + m_avelocity.y += 6; // 9 * ( 3.0 / 2.0 ); } } else { - if (m_avelocity.y > -180) + if( m_avelocity.y > -180 ) { - m_avelocity.y -= 6; // 9 * (3.0/2.0); + m_avelocity.y -= 6; // 9 * ( 3.0 / 2.0 ); } } m_avelocity.y *= 0.98; @@ -915,27 +925,27 @@ void CNihilanth :: Flight( void ) 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) + if( flDir < 0 ) flSpeed = -flSpeed; float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); // 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); + 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) + if( m_flForce < 100 && vecEst.z < m_posDesired.z ) { m_flForce += 10; } - else if (m_flForce > -100 && vecEst.z > m_posDesired.z) + else if( m_flForce > -100 && vecEst.z > m_posDesired.z ) { - if (vecEst.z > m_posDesired.z) + if( vecEst.z > m_posDesired.z ) m_flForce -= 10; } @@ -945,14 +955,14 @@ void CNihilanth :: Flight( void ) // 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 ) +BOOL CNihilanth::AbsorbSphere( void ) { - for (int i = 0; i < N_SPHERES; i++) + for( int i = 0; i < N_SPHERES; i++ ) { - if (m_hSphere[i] != NULL) + if( m_hSphere[i] != NULL ) { - CNihilanthHVR *pSphere = (CNihilanthHVR *)((CBaseEntity *)m_hSphere[i]); - pSphere->AbsorbInit( ); + CNihilanthHVR *pSphere = (CNihilanthHVR *)( (CBaseEntity *)m_hSphere[i] ); + pSphere->AbsorbInit(); m_hSphere[i] = NULL; m_iActiveSpheres--; return TRUE; @@ -961,14 +971,14 @@ BOOL CNihilanth :: AbsorbSphere( void ) return FALSE; } -BOOL CNihilanth :: EmitSphere( void ) +BOOL CNihilanth::EmitSphere( void ) { m_iActiveSpheres = 0; int empty = 0; - for (int i = 0; i < N_SPHERES; i++) + for( int i = 0; i < N_SPHERES; i++ ) { - if (m_hSphere[i] != NULL) + if( m_hSphere[i] != NULL ) { m_iActiveSpheres++; } @@ -978,7 +988,7 @@ BOOL CNihilanth :: EmitSphere( void ) } } - if (m_iActiveSpheres >= N_SPHERES) + if( m_iActiveSpheres >= N_SPHERES ) return FALSE; Vector vecSrc = m_hRecharger->pev->origin; @@ -990,20 +1000,22 @@ BOOL CNihilanth :: EmitSphere( void ) return TRUE; } -void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) +void CNihilanth::TargetSphere( USE_TYPE useType, float value ) { int i; CBaseMonster *pSphere; - for (i = 0; i < N_SPHERES; i++) + + for( i = 0; i < N_SPHERES; i++ ) { - if (m_hSphere[i] != NULL) + if( m_hSphere[i] != NULL ) { pSphere = m_hSphere[i]->MyMonsterPointer(); - if (pSphere->m_hEnemy == NULL) + if( pSphere->m_hEnemy == NULL ) break; } } - if (i == N_SPHERES) + + if( i == N_SPHERES ) { return; } @@ -1015,23 +1027,25 @@ void CNihilanth :: TargetSphere( USE_TYPE useType, float 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 ) +void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { - case 1: // shoot + case 1: + // shoot break; - case 2: // zen - if (m_hEnemy != NULL) + case 2: + // zen + if( m_hEnemy != NULL ) { - if (RANDOM_LONG(0,4) == 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_SHORT( entindex() + 0x3000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1045,7 +1059,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment + WRITE_SHORT( entindex() + 0x4000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1061,7 +1075,8 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) m_flShootEnd = gpGlobals->time + 1.0; } break; - case 3: // prayer + case 3: + // prayer if (m_hEnemy != NULL) { char szText[32]; @@ -1072,7 +1087,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - if (pTrigger != NULL || pTouch != NULL) + if( pTrigger != NULL || pTouch != NULL ) { EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); @@ -1092,7 +1107,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment + WRITE_SHORT( entindex() + 0x3000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1106,7 +1121,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment + WRITE_SHORT( entindex() + 0x4000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1123,24 +1138,26 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } break; - case 4: // get a sphere + case 4: + // get a sphere { - if (m_hRecharger != NULL) + if( m_hRecharger != NULL ) { - if (!EmitSphere( )) + if( !EmitSphere() ) { m_hRecharger = NULL; } } } break; - case 5: // start up sphere machine + case 5: + // start up sphere machine { - EMIT_SOUND( edict(), CHAN_VOICE , RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); + EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); } break; case 6: - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { Vector vecSrc, vecAngles; GetAttachment( 2, vecSrc, vecAngles ); @@ -1154,8 +1171,8 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) 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( ); + pEntity->pev->velocity = Vector( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; + pEntity->GreenBallInit(); */ break; } @@ -1163,17 +1180,17 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - switch (useType) + switch( useType ) { case USE_OFF: { - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - if ( pTouch && m_hEnemy != NULL ) - pTouch->Touch( m_hEnemy ); + CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); + if( pTouch && m_hEnemy != NULL ) + pTouch->Touch( m_hEnemy ); } break; case USE_ON: - if (m_irritation == 0) + if( m_irritation == 0 ) { m_irritation = 1; } @@ -1185,40 +1202,40 @@ void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ } } -int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +int CNihilanth::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { - if (pevInflictor->owner == edict()) + if( pevInflictor->owner == edict() ) return 0; - if (flDamage >= pev->health) + if( flDamage >= pev->health ) { pev->health = 1; - if (m_irritation != 3) + if( m_irritation != 3 ) return 0; } - PainSound( ); + PainSound(); pev->health -= flDamage; return 0; } -void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if (m_irritation == 3) + if( m_irritation == 3 ) m_irritation = 2; - if (m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2) + if( m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2 ) m_irritation = 3; - if (m_irritation != 3) + if( m_irritation != 3 ) { - Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( ); + Vector vecBlood = ( ptr->vecEndPos - pev->origin ).Normalize(); - UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + (100 - 100 * (pev->health / gSkillData.nihilanthHealth))); + UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + ( 100 - 100 * ( pev->health / gSkillData.nihilanthHealth ) ) ); } - // SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage * 5.0);// a little surface blood. + // SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage * 5.0 );// a little surface blood. AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } @@ -1228,10 +1245,10 @@ CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) CBaseEntity *pEntity = NULL; CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) + while( ( pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName ) ) != NULL ) { total++; - if (RANDOM_LONG(0,total-1) < 1) + if( RANDOM_LONG( 0, total - 1 ) < 1 ) pEntity = pNewEntity; } return pEntity; @@ -1241,38 +1258,38 @@ CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) // Controller bouncy ball attack //========================================================= -void CNihilanthHVR :: Spawn( void ) +void CNihilanthHVR::Spawn( void ) { - Precache( ); + Precache(); pev->rendermode = kRenderTransAdd; pev->renderamt = 255; pev->scale = 3.0; } -void CNihilanthHVR :: Precache( void ) +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"); + 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 ) +void CNihilanthHVR::CircleInit( CBaseEntity *pTarget ) { pev->movetype = MOVETYPE_NOCLIP; pev->solid = SOLID_NOT; - // SET_MODEL(edict(), "sprites/flare6.spr"); + // SET_MODEL( edict(), "sprites/flare6.spr" ); // pev->scale = 3.0; - // SET_MODEL(edict(), "sprites/xspark4.spr"); - SET_MODEL(edict(), "sprites/muzzleflash3.spr"); + // SET_MODEL( edict(), "sprites/xspark4.spr" ); + SET_MODEL( edict(), "sprites/muzzleflash3.spr" ); pev->rendercolor.x = 255; pev->rendercolor.y = 224; pev->rendercolor.z = 192; @@ -1280,7 +1297,7 @@ void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) m_nFrames = 1; pev->renderamt = 255; - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); UTIL_SetOrigin( pev, pev->origin ); SetThink( &CNihilanthHVR::HoverThink ); @@ -1296,20 +1313,20 @@ CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) CBaseEntity *pEntity = NULL; CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName )) != NULL) + while( ( pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName ) ) != NULL ) { total++; - if (RANDOM_LONG(0,total-1) < 1) + if( RANDOM_LONG( 0, total - 1 ) < 1 ) pEntity = pNewEntity; } return pEntity; } -void CNihilanthHVR :: HoverThink( void ) +void CNihilanthHVR::HoverThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - if (m_hTargetEnt != NULL) + if( m_hTargetEnt != NULL ) { CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); } @@ -1318,13 +1335,12 @@ void CNihilanthHVR :: HoverThink( void ) UTIL_Remove( this ); } - - if (RANDOM_LONG( 0, 99 ) < 5) + if( RANDOM_LONG( 0, 99 ) < 5 ) { /* - CBaseEntity *pOther = RandomClassname( STRING(pev->classname) ); + CBaseEntity *pOther = RandomClassname( STRING( pev->classname ) ); - if (pOther && pOther != this) + if( pOther && pOther != this ) { MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_BEAMENTS ); @@ -1364,22 +1380,22 @@ void CNihilanthHVR :: HoverThink( void ) */ } - pev->frame = ((int)pev->frame + 1) % m_nFrames; + pev->frame = ( (int)pev->frame + 1 ) % m_nFrames; } -void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) +void CNihilanthHVR::ZapInit( CBaseEntity *pEnemy ) { pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; - SET_MODEL(edict(), "sprites/nhth1.spr"); + 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; + pev->velocity = ( pEnemy->pev->origin - pev->origin ).Normalize() * 200; m_hEnemy = pEnemy; SetThink( &CNihilanthHVR::ZapThink ); @@ -1389,35 +1405,35 @@ void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); } -void CNihilanthHVR :: ZapThink( void ) +void CNihilanthHVR::ZapThink( void ) { pev->nextthink = gpGlobals->time + 0.05; // check world boundaries - if (m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) + if( m_hEnemy == NULL || 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) + if( pev->velocity.Length() < 2000 ) { pev->velocity = pev->velocity * 1.2; } - // MovetoTarget( m_hEnemy->Center( ) ); + // MovetoTarget( m_hEnemy->Center() ); - if ((m_hEnemy->Center() - pev->origin).Length() < 256) + 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) + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + if( pEntity != NULL && pEntity->pev->takedamage ) { - ClearMultiDamage( ); + ClearMultiDamage(); pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); ApplyMultiDamage( pev, pev ); } @@ -1449,7 +1465,7 @@ void CNihilanthHVR :: ZapThink( void ) return; } - pev->frame = (int)(pev->frame + 1) % 11; + pev->frame = (int)( pev->frame + 1 ) % 11; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); @@ -1465,7 +1481,7 @@ void CNihilanthHVR :: ZapThink( void ) WRITE_COORD( 128 ); // decay MESSAGE_END(); - // Crawl( ); + // Crawl(); } void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) @@ -1476,9 +1492,9 @@ void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) pev->velocity = pev->velocity * 0; /* - for (int i = 0; i < 10; i++) + for( int i = 0; i < 10; i++ ) { - Crawl( ); + Crawl(); } */ @@ -1487,7 +1503,7 @@ void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) pev->nextthink = gpGlobals->time + 0.2; } -void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) +void CNihilanthHVR::TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) { pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; @@ -1497,7 +1513,7 @@ void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBa pev->rendercolor.z = 255; pev->velocity.z *= 0.2; - SET_MODEL(edict(), "sprites/exit1.spr"); + SET_MODEL( edict(), "sprites/exit1.spr" ); m_pNihilanth = pOwner; m_hEnemy = pEnemy; @@ -1511,7 +1527,7 @@ void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBa EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); } -void CNihilanthHVR :: GreenBallInit( ) +void CNihilanthHVR::GreenBallInit() { pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; @@ -1521,42 +1537,42 @@ void CNihilanthHVR :: GreenBallInit( ) pev->rendercolor.z = 255; pev->scale = 1.0; - SET_MODEL(edict(), "sprites/exit1.spr"); + SET_MODEL( edict(), "sprites/exit1.spr" ); SetTouch( &CNihilanthHVR::RemoveTouch ); } -void CNihilanthHVR :: TeleportThink( void ) +void CNihilanthHVR::TeleportThink( void ) { pev->nextthink = gpGlobals->time + 0.1; // check world boundaries - if (m_hEnemy == NULL || !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) + if( m_hEnemy == NULL || !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" ); + STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); UTIL_Remove( this ); return; } - if ((m_hEnemy->Center() - pev->origin).Length() < 128) + if( ( m_hEnemy->Center() - pev->origin).Length() < 128 ) { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); UTIL_Remove( this ); - if (m_hTargetEnt != NULL) + if( m_hTargetEnt != NULL ) m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - if ( m_hTouch != NULL && m_hEnemy != NULL ) + if( m_hTouch != NULL && m_hEnemy != NULL ) m_hTouch->Touch( m_hEnemy ); } else { - MovetoTarget( m_hEnemy->Center( ) ); + MovetoTarget( m_hEnemy->Center() ); } MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_SHORT( entindex() ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1568,10 +1584,10 @@ void CNihilanthHVR :: TeleportThink( void ) WRITE_COORD( 256 ); // decay MESSAGE_END(); - pev->frame = (int)(pev->frame + 1) % 20; + pev->frame = (int)( pev->frame + 1 ) % 20; } -void CNihilanthHVR :: AbsorbInit( void ) +void CNihilanthHVR::AbsorbInit( void ) { SetThink( &CNihilanthHVR::DissipateThink ); pev->renderamt = 255; @@ -1598,12 +1614,12 @@ void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) { CBaseEntity *pEnemy = m_hEnemy; - if (pOther == pEnemy) + if( pOther == pEnemy ) { - if (m_hTargetEnt != NULL) + if( m_hTargetEnt != NULL ) m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - if (m_hTouch != NULL && pEnemy != NULL ) + if( m_hTouch != NULL && pEnemy != NULL ) m_hTouch->Touch( pEnemy ); } else @@ -1616,17 +1632,17 @@ void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) UTIL_Remove( this ); } -void CNihilanthHVR :: DissipateThink( void ) +void CNihilanthHVR::DissipateThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - if (pev->scale > 5.0) + if( pev->scale > 5.0 ) UTIL_Remove( this ); pev->renderamt -= 2; pev->scale += 0.1; - if (m_hTargetEnt != NULL) + if( m_hTargetEnt != NULL ) { CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); } @@ -1637,7 +1653,7 @@ void CNihilanthHVR :: DissipateThink( void ) MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment + WRITE_SHORT( entindex() ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); @@ -1650,7 +1666,7 @@ void CNihilanthHVR :: DissipateThink( void ) MESSAGE_END(); } -BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) +BOOL CNihilanthHVR::CircleTarget( Vector vecTarget ) { BOOL fClose = FALSE; @@ -1660,42 +1676,42 @@ BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) 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; + float d1 = ( vecDest - vecSrc ).Length() - 24 * N_SCALE; + float d2 = ( vecDest - vecEst ).Length() - 24 * N_SCALE; - if (m_vecIdeal == Vector( 0, 0, 0 )) + if( m_vecIdeal == Vector( 0, 0, 0 ) ) { m_vecIdeal = pev->velocity; } - if (d1 < 0 && d2 <= d1) + if( d1 < 0 && d2 <= d1 ) { - // ALERT( at_console, "too close\n"); - m_vecIdeal = m_vecIdeal - (vecDest - vecSrc).Normalize() * 50; + // ALERT( at_console, "too close\n" ); + m_vecIdeal = m_vecIdeal - ( vecDest - vecSrc ).Normalize() * 50; } - else if (d1 > 0 && d2 >= d1) + else if( d1 > 0 && d2 >= d1 ) { - // ALERT( at_console, "too far\n"); - m_vecIdeal = m_vecIdeal + (vecDest - vecSrc).Normalize() * 50; + // ALERT( at_console, "too far\n" ); + m_vecIdeal = m_vecIdeal + ( vecDest - vecSrc ).Normalize() * 50; } pev->avelocity.z = d1 * 20; - if (d1 < 32) + 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 */ + 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; + // 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) + if( d1 > 0 && m_vecIdeal.z < 200 ) m_vecIdeal.z += 20; - else if (d1 < 0 && m_vecIdeal.z > -200) + else if( d1 < 0 && m_vecIdeal.z > -200 ) m_vecIdeal.z -= 20; pev->velocity = m_vecIdeal; @@ -1704,34 +1720,34 @@ BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) return fClose; } -void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) +void CNihilanthHVR::MovetoTarget( Vector vecTarget ) { - if (m_vecIdeal == Vector( 0, 0, 0 )) + if( m_vecIdeal == Vector( 0, 0, 0 ) ) { m_vecIdeal = pev->velocity; } // accelerate float flSpeed = m_vecIdeal.Length(); - if (flSpeed > 300) + if( flSpeed > 300 ) { - m_vecIdeal = m_vecIdeal.Normalize( ) * 300; + m_vecIdeal = m_vecIdeal.Normalize() * 300; } m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 300; pev->velocity = m_vecIdeal; } -void CNihilanthHVR :: Crawl( void ) +void CNihilanthHVR::Crawl( void ) { - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); + 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_COORD( vecPnt.x ); + WRITE_COORD( vecPnt.y ); + WRITE_COORD( vecPnt.z ); WRITE_SHORT( g_sModelIndexLaser ); WRITE_BYTE( 0 ); // frame start WRITE_BYTE( 10 ); // framerate @@ -1748,17 +1764,17 @@ void CNihilanthHVR :: Crawl( void ) void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); + STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); UTIL_Remove( this ); } void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) { - Vector vecDir = m_vecIdeal.Normalize( ); + Vector vecDir = m_vecIdeal.Normalize(); - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); - float n = -DotProduct(tr.vecPlaneNormal, vecDir); + float n = -DotProduct( tr.vecPlaneNormal, vecDir ); vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 368ba7b3..55626fc0 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -32,25 +32,27 @@ #define MAX_NODE_INITIAL_LINKS 128 #define MAX_NODES 1024 -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; +extern DLL_GLOBAL edict_t *g_pBodyQueueHead; -Vector VecBModelOrigin( entvars_t* pevBModel ); +Vector VecBModelOrigin( entvars_t *pevBModel ); -CGraph WorldGraph; +CGraph WorldGraph; LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ) LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ) + #if defined _LINUX && !defined _WIN32 #include #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) +void CGraph::InitGraph( void ) { // Make the graph unavailable // @@ -60,37 +62,37 @@ void CGraph :: InitGraph( void) // Free the link pool // - if ( m_pLinkPool ) + if( m_pLinkPool ) { - free ( m_pLinkPool ); + free( m_pLinkPool ); m_pLinkPool = NULL; } - + // Free the node info // - if ( m_pNodes ) + if( m_pNodes ) { - free ( m_pNodes ); + free( m_pNodes ); m_pNodes = NULL; } - if ( m_di ) + if( m_di ) { - free ( m_di ); + free( m_di ); m_di = NULL; } // Free the routing info. // - if ( m_pRouteInfo ) + if( m_pRouteInfo ) { - free ( m_pRouteInfo ); + free( m_pRouteInfo ); m_pRouteInfo = NULL; } - if (m_pHashLinks) + if( m_pHashLinks ) { - free(m_pHashLinks); + free( m_pHashLinks ); m_pHashLinks = NULL; } @@ -109,15 +111,15 @@ void CGraph :: InitGraph( void) // reasonable number of nodes so we can build the path which // will be saved to disk. //========================================================= -int CGraph :: AllocNodes ( void ) +int CGraph::AllocNodes( void ) { // malloc all of the nodes - WorldGraph.m_pNodes = (CNode *)calloc ( sizeof ( CNode ), MAX_NODES ); + WorldGraph.m_pNodes = (CNode *)calloc( sizeof(CNode), MAX_NODES ); // could not malloc space for all the nodes! - if ( !WorldGraph.m_pNodes ) + if( !WorldGraph.m_pNodes ) { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", WorldGraph.m_cNodes ); + ALERT( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", WorldGraph.m_cNodes ); return FALSE; } @@ -137,36 +139,36 @@ int CGraph :: AllocNodes ( void ) // 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 ) +entvars_t *CGraph::LinkEntForLink( CLink *pLink, CNode *pNode ) { edict_t *pentSearch; edict_t *pentTrigger; - entvars_t *pevTrigger; - entvars_t *pevLinkEnt; - TraceResult tr; + entvars_t *pevTrigger; + entvars_t *pevLinkEnt; + TraceResult tr; pevLinkEnt = pLink->m_pLinkEnt; - if ( !pevLinkEnt ) + 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" ) ) + 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 ) ) + 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 ) + while( 1 ) { - pentTrigger = FIND_ENTITY_BY_TARGET ( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger + pentTrigger = FIND_ENTITY_BY_TARGET( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger - if ( FNullEnt( pentTrigger ) ) + if( FNullEnt( pentTrigger ) ) { // no trigger found @@ -175,20 +177,19 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) // 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" ) ) + + if( FClassnameIs( pevTrigger, "func_button" ) || FClassnameIs( pevTrigger, "func_rot_button" ) ) { - // only buttons are handled right now. + // 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 ); + UTIL_TraceLine( pNode->m_vecOrigin, VecBModelOrigin( pevTrigger ), ignore_monsters, g_pBodyQueueHead, &tr ); - - if ( VARS(tr.pHit) == pevTrigger ) + if( VARS(tr.pHit) == pevTrigger ) { // good to go! return VARS( tr.pHit ); @@ -198,7 +199,7 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) } else { - ALERT ( at_aiconsole, "Unsupported PathEnt:\n'%s'\n", STRING ( pevLinkEnt->classname ) ); + ALERT( at_aiconsole, "Unsupported PathEnt:\n'%s'\n", STRING( pevLinkEnt->classname ) ); return NULL; } } @@ -209,36 +210,36 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) // 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 ) +int CGraph::HandleLinkEnt( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ) { - edict_t *pentWorld; - CBaseEntity *pDoor; - TraceResult tr; + edict_t *pentWorld; + CBaseEntity *pDoor; + TraceResult tr; - if ( !m_fGraphPresent || !m_fGraphPointersSet ) + if( !m_fGraphPresent || !m_fGraphPointersSet ) { // protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); + ALERT( at_aiconsole, "Graph not ready!\n" ); return FALSE; } - if ( FNullEnt ( pevLinkEnt ) ) + if( FNullEnt( pevLinkEnt ) ) { - ALERT ( at_aiconsole, "dead path ent!\n" ); + ALERT( at_aiconsole, "dead path ent!\n" ); return TRUE; } pentWorld = NULL; // func_door - if ( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) + 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 ) ) + if( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) { // door is use only. - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) + if( ( afCapMask & bits_CAP_OPEN_DOORS ) ) { // let monster right through if he can open doors return TRUE; @@ -246,7 +247,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N 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 ) ) + if( pDoor->GetToggleState()== TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) { return TRUE; } @@ -257,29 +258,29 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N 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 ) ) + if( pDoor->GetToggleState() == TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) { return TRUE; } - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) + if( ( afCapMask & bits_CAP_OPEN_DOORS ) ) { - if ( !( pevLinkEnt->spawnflags & SF_DOOR_NOMONSTERS ) || queryType == NODEGRAPH_STATIC ) + if( !( pevLinkEnt->spawnflags & SF_DOOR_NOMONSTERS ) || queryType == NODEGRAPH_STATIC ) return TRUE; } return FALSE; } } - // func_breakable - else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) + // 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 ) ); + ALERT( at_aiconsole, "Unhandled Ent in Path %s\n", STRING( pevLinkEnt->classname ) ); return FALSE; } @@ -294,24 +295,24 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N // 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 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 + int i, j;// loops - BOOL fCurrentAlongLine; - BOOL fSuccess; + 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 - //float flConstant;// line constant - Vector vecSpot1, vecSpot2; - Vector2D vec2Spot1, vec2Spot2, vec2TestPoint; - Vector2D vec2Normal;// line normal - Vector2D vec2Line; + BOOL fCurrentAlongLine; + BOOL fSuccess; - TraceResult tr; + //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; @@ -322,22 +323,22 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, 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++ ) + for( i = 0; i < m_cNodes; i++ ) { - vecSpot1 = m_pNodes[ i ].m_vecOrigin; + vecSpot1 = m_pNodes[i].m_vecOrigin; - if ( m_pNodes[ i ].m_cNumLinks <= 0 ) + if( m_pNodes[i].m_cNumLinks <= 0 ) { // this shouldn't happen! - ALERT ( at_aiconsole, "**Node %d has no links\n", i ); + ALERT( at_aiconsole, "**Node %d has no links\n", i ); continue; } - for ( j = 0 ; j < m_pNodes[ i ].m_cNumLinks ; j++ ) + 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 ) + 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 @@ -348,10 +349,10 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, } */ - vecSpot2 = PNodeLink ( i, j )->m_vecOrigin; + 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( 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. @@ -361,9 +362,9 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, 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. + // 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++; @@ -376,13 +377,13 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, vec2Normal.x = -vec2Line.y; vec2Normal.y = vec2Line.x; - if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot1 ) ) > 0 ) + if( DotProduct( vec2Line, ( vec2TestPoint - vec2Spot1 ) ) > 0 ) { // point outside of line flDistToLine = ( vec2TestPoint - vec2Spot1 ).Length(); fCurrentAlongLine = FALSE; } - else if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) + else if( DotProduct( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) { // point outside of line flDistToLine = ( vec2TestPoint - vec2Spot2 ).Length(); @@ -391,75 +392,75 @@ int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, else { // point inside line - flDistToLine = fabs( DotProduct ( vec2TestPoint - vec2Spot2, vec2Normal ) ); + flDistToLine = fabs( DotProduct( vec2TestPoint - vec2Spot2, vec2Normal ) ); fCurrentAlongLine = TRUE; } - if ( flDistToLine < flMinDist ) + 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 ); + UTIL_TraceLine( vecTestPoint, SourceNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); - if ( tr.flFraction != 1.0 ) + 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 ) + 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; + iNearestLink = m_pNodes[i].m_iFirstLink + j; + *piNearestLink = m_pNodes[i].m_iFirstLink + j; *pfAlongLine = fCurrentAlongLine; } } } /* - if ( fSuccess ) + 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_BYTE( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( MSG_BROADCAST, TE_SHOWLINE ); - 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); + 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 ); + ALERT( at_aiconsole, "%d Checked\n", cChecked ); return fSuccess; } #endif -int CGraph::HullIndex( const CBaseEntity *pEntity ) +int CGraph::HullIndex( const CBaseEntity *pEntity ) { - if ( pEntity->pev->movetype == MOVETYPE_FLY) + if( pEntity->pev->movetype == MOVETYPE_FLY ) return NODE_FLY_HULL; - if ( pEntity->pev->mins == Vector( -12, -12, 0 ) ) + if( pEntity->pev->mins == Vector( -12, -12, 0 ) ) return NODE_SMALL_HULL; - else if ( pEntity->pev->mins == VEC_HUMAN_HULL_MIN ) + else if( pEntity->pev->mins == VEC_HUMAN_HULL_MIN ) return NODE_HUMAN_HULL; - else if ( pEntity->pev->mins == Vector ( -32, -32, 0 ) ) + else if( pEntity->pev->mins == Vector( -32, -32, 0 ) ) return NODE_LARGE_HULL; - //ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); + //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->movetype == MOVETYPE_FLY ) { - if (pEntity->pev->waterlevel != 0) + if( pEntity->pev->waterlevel != 0 ) { return bits_NODE_WATER; } @@ -474,37 +475,37 @@ int CGraph::NodeType( const CBaseEntity *pEntity ) // 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; + float distance = 0; + int iNext; - int iMaxLoop = m_cNodes; + int iMaxLoop = m_cNodes; int iCurrentNode = iStart; int iCap = CapIndex( afCapMask ); - while (iCurrentNode != iDest) + while( iCurrentNode != iDest ) { - if (iMaxLoop-- <= 0) + if( iMaxLoop-- <= 0 ) { ALERT( at_console, "Route Failure\n" ); return 0; } iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) + if( iCurrentNode == iNext ) { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); + //ALERT( at_aiconsole, "SVD: Can't get there from here..\n" ); return 0; } int iLink; - HashSearch(iCurrentNode, iNext, iLink); - if (iLink < 0) + HashSearch( iCurrentNode, iNext, iLink ); + if( iLink < 0 ) { - ALERT(at_console, "HashLinks is broken from %d to %d.\n", iCurrentNode, iDest); + ALERT( at_console, "HashLinks is broken from %d to %d.\n", iCurrentNode, iDest ); return 0; } - CLink &link = Link(iLink); + CLink &link = Link( iLink ); distance += link.m_flWeight; iCurrentNode = iNext; @@ -517,49 +518,51 @@ float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) { int iNext = iCurrentNode; - int nCount = iDest+1; - signed char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; + int nCount = iDest + 1; + signed char *pRoute = m_pRouteInfo + m_pNodes[iCurrentNode].m_pNextBestNode[iHull][iCap]; // Until we decode the next best node // - while (nCount > 0) + while( nCount > 0 ) { signed char ch = *pRoute++; - //ALERT(at_aiconsole, "C(%d)", ch); - if (ch < 0) + //ALERT( at_aiconsole, "C(%d)", ch ); + if( ch < 0 ) { // Sequence phrase // ch = -ch; - if (nCount <= ch) + if( nCount <= ch ) { iNext = iDest; nCount = 0; - //ALERT(at_aiconsole, "SEQ: iNext/iDest=%d\n", iNext); + //ALERT( at_aiconsole, "SEQ: iNext/iDest=%d\n", iNext ); } else { - //ALERT(at_aiconsole, "SEQ: nCount + ch (%d + %d)\n", nCount, ch); + //ALERT( at_aiconsole, "SEQ: nCount + ch (%d + %d)\n", nCount, ch ); nCount = nCount - ch; } } else { - //ALERT(at_aiconsole, "C(%d)", *pRoute); + //ALERT( at_aiconsole, "C(%d)", *pRoute ); // Repeat phrase // - if (nCount <= ch+1) + if( nCount <= ch + 1 ) { iNext = iCurrentNode + *pRoute; - if (iNext >= m_cNodes) iNext -= m_cNodes; - else if (iNext < 0) iNext += m_cNodes; + if( iNext >= m_cNodes ) + iNext -= m_cNodes; + else if( iNext < 0 ) + iNext += m_cNodes; nCount = 0; - //ALERT(at_aiconsole, "REP: iNext=%d\n", iNext); + //ALERT( at_aiconsole, "REP: iNext=%d\n", iNext ); } else { - //ALERT(at_aiconsole, "REP: nCount - ch+1 (%d - %d+1)\n", nCount, ch); + //ALERT( at_aiconsole, "REP: nCount - ch+1 (%d - %d+1)\n", nCount, ch ); nCount = nCount - ch - 1; } pRoute++; @@ -576,28 +579,28 @@ int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) // 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 CGraph::FindShortestPath( int *piPath, int iStart, int iDest, int iHull, int afCapMask ) { - int iVisitNode; - int iCurrentNode; - int iNumPathNodes; - int iHullMask; + int iVisitNode; + int iCurrentNode; + int iNumPathNodes; + int iHullMask; - if ( !m_fGraphPresent || !m_fGraphPointersSet ) + 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 ); + ALERT( at_aiconsole, "Graph not ready!\n" ); return FALSE; } - if (iStart == iDest) + 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; @@ -606,7 +609,7 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, // Is routing information present. // - if (m_fRoutingComplete) + if( m_fRoutingComplete ) { int iCap = CapIndex( afCapMask ); @@ -615,33 +618,33 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, iCurrentNode = iStart; int iNext; - //ALERT(at_aiconsole, "GOAL: %d to %d\n", iStart, iDest); + //ALERT( at_aiconsole, "GOAL: %d to %d\n", iStart, iDest ); // Until we arrive at the destination // - while (iCurrentNode != iDest) + while( iCurrentNode != iDest ) { iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) + if( iCurrentNode == iNext ) { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); + //ALERT( at_aiconsole, "SVD: Can't get there from here..\n" ); return 0; break; } - if (iNumPathNodes >= MAX_PATH_SIZE) + if( iNumPathNodes >= MAX_PATH_SIZE ) { - //ALERT(at_aiconsole, "SVD: Don't return the entire path.\n"); + //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); + //ALERT( at_aiconsole, "SVD: Path with %d nodes.\n", iNumPathNodes ); } else { int i; - CQueuePriority queue; + CQueuePriority queue; switch( iHull ) { @@ -663,58 +666,59 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, // for ( i = 0; i < m_cNodes; i++) { - m_pNodes[ i ].m_flClosestSoFar = -1.0; + 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 + 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() ) + + while( !queue.Empty() ) { // now pull a node out of the queue float flCurrentDistance; - iCurrentNode = queue.Remove(flCurrentDistance); + iCurrentNode = queue.Remove( flCurrentDistance ); // For straight-line weights, the following Shortcut works. For arbitrary weights, // it doesn't. // - if (iCurrentNode == iDest) break; + if( iCurrentNode == iDest ) + break; - CNode *pCurrentNode = &m_pNodes[ iCurrentNode ]; + CNode *pCurrentNode = &m_pNodes[iCurrentNode]; - for ( i = 0 ; i < pCurrentNode->m_cNumLinks ; i++ ) + 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 ) + 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 ); + //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 ) + 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 ) ) + 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 ) + 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 ); + queue.Insert( iVisitNode, flOurDistance ); } } } - if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) + if( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) { // Destination is unreachable, no path found. return 0; @@ -725,50 +729,50 @@ int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, iCurrentNode = iDest; iNumPathNodes = 1;// count the dest - while ( iCurrentNode != iStart ) + while( iCurrentNode != iStart ) { iNumPathNodes++; - iCurrentNode = m_pNodes[ iCurrentNode ].m_iPreviousNode; + iCurrentNode = m_pNodes[iCurrentNode].m_iPreviousNode; } iCurrentNode = iDest; - for ( i = iNumPathNodes - 1 ; i >= 0 ; i-- ) + for( i = iNumPathNodes - 1; i >= 0; i-- ) { - piPath[ i ] = iCurrentNode; - iCurrentNode = m_pNodes [ iCurrentNode ].m_iPreviousNode; + piPath[i] = iCurrentNode; + iCurrentNode = m_pNodes[iCurrentNode].m_iPreviousNode; } } #if 0 - if (m_fRoutingComplete) + if( m_fRoutingComplete ) { // This will draw the entire path that was generated for the monster. - for ( int i = 0 ; i < iNumPathNodes - 1 ; i++ ) + 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_BYTE( TE_SHOWLINE ); - 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 ); + 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_BYTE( TE_SHOWLINE ); - 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 ); + 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; @@ -785,7 +789,7 @@ inline ULONG Hash( void *p, int len ) void inline CalcBounds( int &Lower, int &Upper, int Goal, int Best ) { int Temp = 2 * Goal - Best; - if ( Best > Goal ) + if( Best > Goal ) { Lower = max( 0, Temp ); Upper = Best; @@ -804,12 +808,14 @@ 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) +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; + if( Upper < maxValue ) + maxValue = Upper; + if( minValue < Lower ) + minValue = Lower; } void CGraph::CheckNode( Vector vecOrigin, int iNode ) @@ -828,7 +834,7 @@ void CGraph::CheckNode( Vector vecOrigin, int iNode ) TraceResult tr; // make sure that vecOrigin can trace to this node! - UTIL_TraceLine ( vecOrigin, m_pNodes[iNode].m_vecOriginPeek, ignore_monsters, 0, &tr ); + UTIL_TraceLine( vecOrigin, m_pNodes[iNode].m_vecOriginPeek, ignore_monsters, 0, &tr ); if( tr.flFraction == 1.0 ) { @@ -842,12 +848,12 @@ void CGraph::CheckNode( Vector vecOrigin, int iNode ) // 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]); + 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] ); } } } @@ -857,34 +863,34 @@ void CGraph::CheckNode( Vector vecOrigin, int iNode ) // the given vector -1 is failure (couldn't find a valid // near node ) //========================================================= -int CGraph::FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) +int CGraph::FindNearestNode( const Vector &vecOrigin, CBaseEntity *pEntity ) { return FindNearestNode( vecOrigin, NodeType( pEntity ) ); } -int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) +int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) { - int i; + 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" ); + 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) + ULONG iHash = ( CACHE_SIZE - 1 ) & Hash( (void *)(const float *)vecOrigin, sizeof(vecOrigin) ); + if( m_Cache[iHash].v == vecOrigin ) { - //ALERT(at_aiconsole, "Cache Hit.\n"); + //ALERT( at_aiconsole, "Cache Hit.\n" ); return m_Cache[iHash].n; } /* else { - //ALERT(at_aiconsole, "Cache Miss.\n"); + //ALERT( at_aiconsole, "Cache Miss.\n" ); } */ // Mark all points as unchecked. @@ -892,7 +898,7 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) m_CheckedCounter++; if( m_CheckedCounter == 0 ) { - for ( i = 0; i < m_cNodes; i++ ) + for( i = 0; i < m_cNodes; i++ ) { m_di[i].m_CheckedEvent = 0; } @@ -913,19 +919,19 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) 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]); + 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 halfX = ( m_minX + m_maxX ) / 2; + int halfY = ( m_minY + m_maxY ) / 2; + int halfZ = ( m_minZ + m_maxZ ) / 2; int j; @@ -933,7 +939,7 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) { for( j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++ ) { - if ( !( m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes ) ) + 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]; @@ -975,13 +981,13 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) if( rgX > m_maxBoxX ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); + 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++) + 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; @@ -1000,58 +1006,73 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) if( rgY > m_maxBoxY ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); + 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; + 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; + 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]); - } - } + 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; + 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; + 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]); - } - } + 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; + 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; + 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( rgY < m_minBoxY ) + continue; + if( rgY > m_maxBoxY ) + continue; + CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); + } + } #if 0 // Verify our answers. @@ -1059,16 +1080,16 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) int iNearestCheck = -1; m_flShortest = 8192;// find nodes within this radius - for ( i = 0 ; i < m_cNodes ; i++ ) + for( i = 0; i < m_cNodes; i++ ) { - float flDist = ( vecOrigin - m_pNodes[ i ].m_vecOriginPeek ).Length(); + float flDist = ( vecOrigin - m_pNodes[i].m_vecOriginPeek ).Length(); - if ( flDist < m_flShortest ) + 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 ); + UTIL_TraceLine( vecOrigin, m_pNodes[i].m_vecOriginPeek, ignore_monsters, 0, &tr ); - if ( tr.flFraction == 1.0 ) + if( tr.flFraction == 1.0 ) { iNearestCheck = i; m_flShortest = flDist; @@ -1076,7 +1097,7 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) } } - if (iNearestCheck != m_iNearest) + if( iNearestCheck != m_iNearest ) { ALERT( at_aiconsole, "NOT closest %d(%f,%f,%f) %d(%f,%f,%f).\n", iNearestCheck, @@ -1084,13 +1105,13 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) 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)); + ( 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) + if( m_iNearest == -1 ) { - ALERT(at_aiconsole, "All that work for nothing.\n"); + ALERT( at_aiconsole, "All that work for nothing.\n" ); } #endif m_Cache[iHash].v = vecOrigin; @@ -1102,46 +1123,47 @@ int CGraph::FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) // CGraph - ShowNodeConnections - draws a line from the given node // to all connected nodes //========================================================= -void CGraph :: ShowNodeConnections ( int iNode ) +void CGraph::ShowNodeConnections( int iNode ) { - Vector vecSpot; - CNode *pNode; - CNode *pLinkNode; - int i; + 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" ); + 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 ) + if( iNode < 0 ) { ALERT( at_aiconsole, "Can't show connections for node %d\n", iNode ); return; } - pNode = &m_pNodes[ iNode ]; + pNode = &m_pNodes[iNode]; UTIL_ParticleEffect( pNode->m_vecOrigin, g_vecZero, 255, 20 );// show node position - - if ( pNode->m_cNumLinks <= 0 ) - {// no connections! + + if( pNode->m_cNumLinks <= 0 ) + { + // no connections! ALERT ( at_aiconsole, "**No Connections!\n" ); } - for ( i = 0 ; i < pNode->m_cNumLinks ; i++ ) + for( i = 0; i < pNode->m_cNumLinks; i++ ) { - - pLinkNode = &Node( NodeLink( iNode, i).m_iDestNode ); + 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_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 ); @@ -1162,196 +1184,194 @@ void CGraph :: ShowNodeConnections ( int iNode ) // 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 CGraph::LinkVisibleNodes( CLink *pLinkPool, FILE *file, int *piBadNode ) { - int i,j,z; - edict_t *pTraceEnt; - int cTotalLinks, cLinksThisNode, cMaxInitialLinks; - TraceResult tr; - + 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 ) + if( m_cNodes <= 0 ) { - ALERT ( at_aiconsole, "No Nodes!\n" ); + 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 ) + if( !file ) { - ALERT ( at_aiconsole, "**LinkVisibleNodes:\ncan't write to file." ); + ALERT( at_aiconsole, "**LinkVisibleNodes:\ncan't write to file." ); } else { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "LinkVisibleNodes - Initial Connections\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); + 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++ ) + for( i = 0; i < m_cNodes; i++ ) { cLinksThisNode = 0;// reset this count for each node. - if ( file ) + if( file ) { - fprintf ( file, "Node #%4d:\n\n", i ); + 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; + 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; + 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++ ) + for( j = 0; j < m_cNodes; j++ ) { - if ( j == i ) - {// don't connect to self! + 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) ) + 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) ) + 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 ) + 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. - + 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 ); - + 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" ) ) + if( tr.pHit == pTraceEnt && !FClassnameIs( tr.pHit, "worldspawn" ) ) { // get a pointer - pLinkPool [ cTotalLinks ].m_pLinkEnt = VARS( tr.pHit ); + 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 ); + 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 ) ) + 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. + { + // even if the ent wasn't there, these nodes couldn't be connected. Skip. continue; } } - if ( file ) + if( file ) { - fprintf ( file, "%4d", j ); + 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 ) ); + 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", j ); - fprintf ( file, "\n" ); + + //fprintf( file, "\n", j ); + fprintf( file, "\n" ); } - pLinkPool [ cTotalLinks ].m_iDestNode = j; + 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 ) + 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 ); + 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; + return FALSE; } - else if ( cTotalLinks > MAX_NODE_INITIAL_LINKS * m_cNodes ) - {// this is paranoia - ALERT ( at_aiconsole, "**LinkVisibleNodes:\nTotalLinks > MAX_NODE_INITIAL_LINKS * NUMNODES" ); + 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; + return FALSE; } - if ( cLinksThisNode == 0 ) + if( cLinksThisNode == 0 ) { - fprintf ( file, "**NO INITIAL LINKS**\n" ); + fprintf( file, "**NO INITIAL LINKS**\n" ); } // record the connection info in the link pool - WorldGraph.m_pNodes [ i ].m_cNumLinks = cLinksThisNode; - + 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 ) + if( cLinksThisNode > cMaxInitialLinks ) { cMaxInitialLinks = cLinksThisNode; } } - - if ( file ) + if( file ) { - fprintf ( file, "----------------------------------------------------------------------------\n" ); + 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" ); + fprintf( file, "\n%4d Total Initial Connections - %4d Maximum connections for a single node.\n", cTotalLinks, cMaxInitialLinks ); + fprintf( file, "----------------------------------------------------------------------------\n\n\n" ); return cTotalLinks; } @@ -1362,76 +1382,76 @@ int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ) // want status reports written to disk ). RETURNS the number // of connections that were rejected //========================================================= -int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) +int CGraph::RejectInlineLinks( CLink *pLinkPool, FILE *file ) { - int i,j,k; + int i, j, k; + int cRejectedLinks; - int cRejectedLinks; + BOOL fRestartLoop;// have to restart the J loop if we eliminate a link. - 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) - 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; - float flDistToTestNode, flDistToCheckNode; + Vector2D vec2DirToTestNode, vec2DirToCheckNode; - Vector2D vec2DirToTestNode, vec2DirToCheckNode; - - if ( file ) + if( file ) { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "InLine Rejection:\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); + fprintf( file, "----------------------------------------------------------------------------\n" ); + fprintf( file, "InLine Rejection:\n" ); + fprintf( file, "----------------------------------------------------------------------------\n" ); } cRejectedLinks = 0; - for ( i = 0 ; i < m_cNodes ; i++ ) + for( i = 0; i < m_cNodes; i++ ) { - pSrcNode = &m_pNodes[ i ]; + pSrcNode = &m_pNodes[i]; - if ( file ) + if( file ) { - fprintf ( file, "Node %3d:\n", i ); + fprintf( file, "Node %3d:\n", i ); } - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) + for( j = 0; j < pSrcNode->m_cNumLinks; j++ ) { - pCheckNode = &m_pNodes[ pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; + 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; + pLinkPool[pSrcNode->m_iFirstLink + j].m_flWeight = flDistToCheckNode; fRestartLoop = FALSE; - for ( k = 0 ; k < pSrcNode->m_cNumLinks && !fRestartLoop ; k++ ) + for( k = 0; k < pSrcNode->m_cNumLinks && !fRestartLoop; k++ ) { - if ( k == j ) - {// don't check against same node + if( k == j ) + { + // don't check against same node continue; } - pTestNode = &m_pNodes [ pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode ]; + 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 ) + 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( flDistToTestNode < flDistToCheckNode ) { - if ( file ) + 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 ) ); + 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 ) ]; + pLinkPool[pSrcNode->m_iFirstLink + j] = pLinkPool[pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 )]; pSrcNode->m_cNumLinks--; j--; @@ -1443,9 +1463,9 @@ int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) } } - if ( file ) + if( file ) { - fprintf ( file, "----------------------------------------------------------------------------\n\n" ); + fprintf( file, "----------------------------------------------------------------------------\n\n" ); } } @@ -1460,14 +1480,14 @@ class CTestHull : public CBaseMonster { public: void Spawn( entvars_t *pevMasterNode ); - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + 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 ); + void BuildNodeGraph( void ); + void EXPORT ShowBadNode( void ); + void EXPORT DropDelay( void ); + void EXPORT PathFind( void ); - Vector vecBadNodeOrigin; + Vector vecBadNodeOrigin; }; LINK_ENTITY_TO_CLASS( testhull, CTestHull ) @@ -1475,19 +1495,20 @@ LINK_ENTITY_TO_CLASS( testhull, CTestHull ) //========================================================= // CTestHull::Spawn //========================================================= -void CTestHull :: Spawn( entvars_t *pevMasterNode ) +void CTestHull::Spawn( entvars_t *pevMasterNode ) { - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + 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; + 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 + if( WorldGraph.m_fGraphPresent ) + { + // graph loaded from disk, so we don't need the test hull SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } @@ -1507,11 +1528,11 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode ) // TestHull::DropDelay - spawns TestHull on top of // the 0th node and drops it to the ground. //========================================================= -void CTestHull::DropDelay ( void ) +void CTestHull::DropDelay( void ) { UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); - UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); + UTIL_SetOrigin( VARS( pev ), WorldGraph.m_pNodes[0].m_vecOrigin ); SetThink( &CTestHull::CallBuildNodeGraph ); @@ -1522,15 +1543,15 @@ void CTestHull::DropDelay ( void ) // 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 ) +void CNodeEnt::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "hinttype")) + if( FStrEq( pkvd->szKeyName, "hinttype" ) ) { m_sHintType = (short)atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - if (FStrEq(pkvd->szKeyName, "activity")) + if( FStrEq( pkvd->szKeyName, "activity" ) ) { m_sHintActivity = (short)atoi( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -1541,39 +1562,41 @@ void CNodeEnt :: KeyValue( KeyValueData *pkvd ) //========================================================= //========================================================= -void CNodeEnt :: Spawn( void ) +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 + 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); + 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 ) + if( WorldGraph.m_cNodes >= MAX_NODES ) { - ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" ); + 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; + 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; + 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_pNodes[WorldGraph.m_cNodes].m_afNodeInfo = 0; WorldGraph.m_cNodes++; @@ -1586,18 +1609,18 @@ void CNodeEnt :: Spawn( void ) // hull will be placed up the bad node's location and will generate // particles //========================================================= -void CTestHull :: ShowBadNode( void ) +void CTestHull::ShowBadNode( void ) { pev->movetype = MOVETYPE_FLY; pev->angles.y = pev->angles.y + 4; - UTIL_MakeVectors ( pev->angles ); + 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 ); + 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; } @@ -1621,59 +1644,58 @@ void CTestHull::CallBuildNodeGraph( void ) // 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 ) +void CTestHull::BuildNodeGraph( void ) { - //TraceResult tr; - FILE *file; + //TraceResult tr; + FILE *file; - char szNrpFilename [MAX_PATH];// text node report filename + char szNrpFilename [MAX_PATH];// text node report filename - CLink *pTempPool; // temporary link pool + CLink *pTempPool; // temporary link pool - CNode *pSrcNode;// node we're currently working with - CNode *pDestNode;// the other node in comparison operations + 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? + 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 i, j, hull; - int iBadNode;// this is the node that caused graph generation to fail + int iBadNode;// this is the node that caused graph generation to fail - int cMaxInitialLinks = 0; - int cMaxValidLinks = 0; + int cMaxInitialLinks = 0; + int cMaxValidLinks = 0; - int iPoolIndex = 0; - int cPoolLinks;// number of links in the pool. + int iPoolIndex = 0; + int cPoolLinks;// number of links in the pool. - Vector vecDirToCheckNode; - Vector vecDirToTestNode; - Vector vecStepCheckDir; - Vector vecTraceSpot; - Vector vecSpot; + Vector vecDirToCheckNode; + Vector vecDirToTestNode; + Vector vecStepCheckDir; + Vector vecTraceSpot; + Vector vecSpot; - Vector2D vec2DirToCheckNode; - Vector2D vec2DirToTestNode; - Vector2D vec2StepCheckDir; - Vector2D vec2TraceSpot; - Vector2D vec2Spot; + 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; + float flYaw;// use this stuff to walk the hull between nodes + float flDist; + int step; SetThink( &CBaseEntity::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 ) + pTempPool = (CLink *)calloc( sizeof(CLink), ( WorldGraph.m_cNodes * MAX_NODE_INITIAL_LINKS ) ); + if( !pTempPool ) { - ALERT ( at_aiconsole, "**Could not malloc TempPool!\n" ); + ALERT( at_aiconsole, "**Could not malloc TempPool!\n" ); return; } - // make sure directories have been made GET_GAME_DIR( szNrpFilename ); strcat( szNrpFilename, "/maps" ); @@ -1685,81 +1707,82 @@ void CTestHull :: BuildNodeGraph( void ) strcat( szNrpFilename, STRING( gpGlobals->mapname ) ); strcat( szNrpFilename, ".nrp" ); - file = fopen ( szNrpFilename, "w+" ); + file = fopen( szNrpFilename, "w+" ); - if ( !file ) - {// file error - ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); + if( !file ) + { + // file error + ALERT( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); - if ( pTempPool ) + if( pTempPool ) { - free ( 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 ); + 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)); + 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, "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" ); - + fprintf( file, "\n\n" ); // Automatically recognize WATER nodes and drop the LAND nodes to the floor. // - for ( i = 0; i < WorldGraph.m_cNodes; i++) + for( i = 0; i < WorldGraph.m_cNodes; i++) { - if (WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_AIR) + if( WorldGraph.m_pNodes[i].m_afNodeInfo & bits_NODE_AIR ) { // do nothing } - else if (UTIL_PointContents(WorldGraph.m_pNodes[ i ].m_vecOrigin) == CONTENTS_WATER) + else if( UTIL_PointContents( WorldGraph.m_pNodes[i].m_vecOrigin ) == CONTENTS_WATER ) { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_WATER; + WorldGraph.m_pNodes[i].m_afNodeInfo |= bits_NODE_WATER; } else { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_LAND; + 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; + 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 ); + 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 ); + 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( trEnt.flFraction < tr.flFraction ) { // If it was a world brush entity, copy the node location - if ( trEnt.pHit && (trEnt.pHit->v.flags & FL_WORLDBRUSH) ) + if( trEnt.pHit && ( trEnt.pHit->v.flags & FL_WORLDBRUSH ) ) tr.vecEndPos = trEnt.vecEndPos; } @@ -1769,23 +1792,24 @@ void CTestHull :: BuildNodeGraph( void ) } cPoolLinks = WorldGraph.LinkVisibleNodes( pTempPool, file, &iBadNode ); - - if ( !cPoolLinks ) + + if( !cPoolLinks ) { - ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - + 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 ) + pev->origin = WorldGraph.m_pNodes[iBadNode].m_vecOrigin; + + if( pTempPool ) { - free ( pTempPool ); + free( pTempPool ); } - if ( file ) - {// close the file - fclose ( file ); + if( file ) + { + // close the file + fclose( file ); } return; @@ -1793,88 +1817,88 @@ void CTestHull :: BuildNodeGraph( void ) // 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"); + fprintf( file, "----------------------------------------------------------------------------\n" ); + fprintf( file, "Walk Rejection:\n"); - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + for( i = 0; i < WorldGraph.m_cNodes; i++ ) { - pSrcNode = &WorldGraph.m_pNodes[ i ]; + pSrcNode = &WorldGraph.m_pNodes[i]; - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Node %4d:\n\n", i ); - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) + 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; - + 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++ ) + for( hull = 0; hull < MAX_NODE_HULLS; hull++ ) { - if (fSkipRemainingHulls && (hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL)) // skip the remaining walk hulls + if( fSkipRemainingHulls && ( hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL ) ) // skip the remaining walk hulls continue; - switch ( hull ) + switch( hull ) { case NODE_SMALL_HULL: - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); + 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 ); + 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)); + 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)); + 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 + UTIL_SetOrigin( pev, pSrcNode->m_vecOrigin );// place the hull on the node - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) + if( !FBitSet( pev->flags, FL_ONGROUND ) ) { - ALERT ( at_aiconsole, "OFFGROUND!\n" ); + ALERT( at_aiconsole, "OFFGROUND!\n" ); } // now build a yaw that points to the dest node, and get the distance. - if ( j < 0 ) + if( j < 0 ) { - ALERT ( at_aiconsole, "**** j = %d ****\n", j ); - if ( pTempPool ) + ALERT( at_aiconsole, "**** j = %d ****\n", j ); + if( pTempPool ) { - free ( pTempPool ); + free( pTempPool ); } - if ( file ) - {// close the file - fclose ( file ); + if( file ) + { + // close the file + fclose( file ); } return; } - pDestNode = &WorldGraph.m_pNodes [ pTempPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; + 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) + if( hull < NODE_FLY_HULL ) { int SaveFlags = pev->flags; int MoveMode = WALKMOVE_WORLDONLY; - if (pSrcNode->m_afNodeInfo & bits_NODE_WATER) + if( pSrcNode->m_afNodeInfo & bits_NODE_WATER ) { pev->flags |= FL_SWIM; MoveMode = WALKMOVE_NORMAL; } - flYaw = UTIL_VecToYaw ( pDestNode->m_vecOrigin - pev->origin ); + flYaw = UTIL_VecToYaw( pDestNode->m_vecOrigin - pev->origin ); flDist = ( vecSpot - pev->origin ).Length2D(); @@ -1882,49 +1906,48 @@ void CTestHull :: BuildNodeGraph( void ) // 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 ) + 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 + 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) + if( !fWalkFailed && ( pev->origin - vecSpot ).Length() > 64 ) { - // ALERT( at_console, "bogus walk\n"); + // ALERT( at_console, "bogus walk\n" ); // we thought we fWalkFailed = TRUE; } - if (fWalkFailed) + if( fWalkFailed ) { - - //pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; + //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 ) + 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); + 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); + 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; + fprintf( file, "NODE_LARGE_HULL step %d\n", step ); + pTempPool[pSrcNode->m_iFirstLink + j].m_afLinkInfo &= ~bits_LINK_LARGE_HULL; break; } } @@ -1935,19 +1958,19 @@ void CTestHull :: BuildNodeGraph( void ) 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) + if( tr.fStartSolid || tr.flFraction < 1.0 ) { - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_FLY_HULL; + pTempPool[pSrcNode->m_iFirstLink + j].m_afLinkInfo &= ~bits_LINK_FLY_HULL; } } } - if (pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo == 0) + 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" ); - + 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--; @@ -1955,23 +1978,25 @@ void CTestHull :: BuildNodeGraph( void ) } } - fprintf ( file, "-------------------------------------------------------------------------------\n\n\n"); + fprintf( file, "-------------------------------------------------------------------------------\n\n\n" ); - cPoolLinks -= WorldGraph.RejectInlineLinks ( pTempPool, file ); + 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 ); + 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 ) + if( !WorldGraph.m_pLinkPool ) + { + // couldn't make the link pool! + ALERT( at_aiconsole, "Couldn't malloc LinkPool!\n" ); + if( pTempPool ) { - free ( pTempPool ); + free( pTempPool ); } - if ( file ) - {// close the file - fclose ( file ); + if( file ) + { + // close the file + fclose( file ); } return; @@ -1982,19 +2007,18 @@ void CTestHull :: BuildNodeGraph( void ) int iFinalPoolIndex = 0; int iOldFirstLink; - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) + 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 + 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; + WorldGraph.m_pNodes[i].m_iFirstLink = iFinalPoolIndex; - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) + for( j = 0; j < WorldGraph.m_pNodes[i].m_cNumLinks; j++ ) { - WorldGraph.m_pLinkPool[ iFinalPoolIndex++ ] = pTempPool[ iOldFirstLink + j ]; + WorldGraph.m_pLinkPool[iFinalPoolIndex++] = pTempPool[iOldFirstLink + j]; } } - // Node sorting numbers linked nodes close to each other // WorldGraph.SortNodes(); @@ -2005,67 +2029,65 @@ void CTestHull :: BuildNodeGraph( void ) fPairsValid = TRUE; // assume that the connection pairs are all valid to start - fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); - fprintf ( file, "Link Pairings:\n"); + 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( i = 0; i < WorldGraph.m_cNodes; i++ ) { - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) + for( j = 0; j < WorldGraph.m_pNodes[i].m_cNumLinks; j++ ) { int iLink; - WorldGraph.HashSearch(WorldGraph.INodeLink(i,j), i, iLink); - if (iLink < 0) + 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); + 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 ) + if( fPairsValid ) { - fprintf ( file, "\nAll Connections are Paired!\n"); + fprintf( file, "\nAll Connections are Paired!\n" ); } - 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: %d bytes\n", sizeof ( CLink ) * cPoolLinks ); - fprintf ( file, "-------------------------------------------------------------------------------\n"); + 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: %d bytes\n", sizeof(CLink) * cPoolLinks ); + fprintf( file, "-------------------------------------------------------------------------------\n" ); + ALERT( at_aiconsole, "%d Nodes, %d Connections\n", WorldGraph.m_cNodes, cPoolLinks ); - 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++ ) + for( i = 0; i < WorldGraph.m_cNodes; i++ ) { - if ((WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_LAND)) + if( ( WorldGraph.m_pNodes[i].m_afNodeInfo & bits_NODE_LAND ) ) { - WorldGraph.m_pNodes[ i ].m_vecOrigin.z -= NODE_HEIGHT; + WorldGraph.m_pNodes[i].m_vecOrigin.z -= NODE_HEIGHT; } } - - if ( pTempPool ) - {// free the temp pool - free ( pTempPool ); + if( pTempPool ) + { + // free the temp pool + free( pTempPool ); } - if ( file ) + if( file ) { - fclose ( file ); + fclose( file ); } // We now have some graphing capabilities. @@ -2080,63 +2102,62 @@ void CTestHull :: BuildNodeGraph( void ) // save the node graph for this level WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); - ALERT( at_console, "Done.\n"); + ALERT( at_console, "Done.\n" ); } //========================================================= // returns a hardcoded path. //========================================================= -void CTestHull :: PathFind ( void ) +void CTestHull::PathFind( void ) { - int iPath[ 50 ]; - int iPathSize; - int i; - CNode *pNode, *pNextNode; + 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" ); + 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 + iPathSize = WorldGraph.FindShortestPath( iPath, 0, 19, 0, 0 ); // UNDONE use hull constant - if ( !iPathSize ) + if( !iPathSize ) { - ALERT ( at_aiconsole, "No Path!\n" ); + ALERT( at_aiconsole, "No Path!\n" ); return; } - ALERT ( at_aiconsole, "%d\n", iPathSize ); + ALERT( at_aiconsole, "%d\n", iPathSize ); - pNode = &WorldGraph.m_pNodes[ iPath [ 0 ] ]; + pNode = &WorldGraph.m_pNodes[iPath[0]]; - for ( i = 0 ; i < iPathSize - 1 ; i++ ) + for( i = 0; i < iPathSize - 1; i++ ) { - - pNextNode = &WorldGraph.m_pNodes[ iPath [ i + 1 ] ]; + pNextNode = &WorldGraph.m_pNodes[iPath[i + 1]]; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - + 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); + 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 ) +CStack::CStack( void ) { m_level = 0; } @@ -2144,11 +2165,11 @@ CStack :: CStack( void ) //========================================================= // pushes a value onto the stack //========================================================= -void CStack :: Push( int value ) +void CStack::Push( int value ) { - if ( m_level >= MAX_STACK_NODES ) + if( m_level >= MAX_STACK_NODES ) { - printf("Error!\n"); + printf( "Error!\n" ); return; } m_stack[m_level] = value; @@ -2158,40 +2179,40 @@ void CStack :: Push( int value ) //========================================================= // pops a value off of the stack //========================================================= -int CStack :: Pop( void ) +int CStack::Pop( void ) { - if ( m_level <= 0 ) + if( m_level <= 0 ) return -1; m_level--; - return m_stack[ m_level ]; + return m_stack[m_level]; } //========================================================= // returns the value on the top of the stack //========================================================= -int CStack :: Top ( void ) +int CStack::Top( void ) { - return m_stack[ m_level - 1 ]; + return m_stack[m_level - 1]; } //========================================================= // copies every element on the stack into an array LIFO //========================================================= -void CStack :: CopyToArray ( int *piArray ) +void CStack::CopyToArray( int *piArray ) { - int i; + int i; - for ( i = 0 ; i < m_level ; i++ ) + for( i = 0; i < m_level; i++ ) { - piArray[ i ] = m_stack[ i ]; + piArray[i] = m_stack[i]; } } //========================================================= // CQueue constructor //========================================================= -CQueue :: CQueue( void ) +CQueue::CQueue( void ) { m_cSize = 0; m_head = 0; @@ -2201,46 +2222,47 @@ CQueue :: CQueue( void ) //========================================================= // inserts a value into the queue //========================================================= -void CQueue :: Insert ( int iValue, float fPriority ) +void CQueue::Insert( int iValue, float fPriority ) { - - if ( Full() ) + if( Full() ) { - printf ( "Queue is full!\n" ); + printf( "Queue is full!\n" ); return; } m_tail++; - if ( m_tail == MAX_STACK_NODES ) - {//wrap around + if( m_tail == MAX_STACK_NODES ) + { + //wrap around m_tail = 0; } - m_queue[ m_tail ].Id = iValue; - m_queue[ m_tail ].Priority = fPriority; + 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 ) +int CQueue::Remove( float &fPriority ) { - if ( m_head == MAX_STACK_NODES ) - {// wrap + if( m_head == MAX_STACK_NODES ) + { + // wrap m_head = 0; } m_cSize--; - fPriority = m_queue[ m_head ].Priority; - return m_queue[ m_head++ ].Id; + fPriority = m_queue[m_head].Priority; + return m_queue[m_head++].Id; } //========================================================= // CQueue constructor //========================================================= -CQueuePriority :: CQueuePriority( void ) +CQueuePriority::CQueuePriority( void ) { m_cSize = 0; } @@ -2248,82 +2270,81 @@ CQueuePriority :: CQueuePriority( void ) //========================================================= // inserts a value into the priority queue //========================================================= -void CQueuePriority :: Insert( int iValue, float fPriority ) +void CQueuePriority::Insert( int iValue, float fPriority ) { - - if ( Full() ) + if( Full() ) { - printf ( "Queue is full!\n" ); + printf( "Queue is full!\n" ); return; } - m_heap[ m_cSize ].Priority = fPriority; - m_heap[ m_cSize ].Id = iValue; - m_cSize++; - Heap_SiftUp(); + 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 CQueuePriority::Remove( float &fPriority ) { - int iReturn = m_heap[ 0 ].Id; - fPriority = m_heap[ 0 ].Priority; + int iReturn = m_heap[0].Id; + fPriority = m_heap[0].Priority; m_cSize--; - m_heap[ 0 ] = m_heap[ m_cSize ]; + m_heap[0] = m_heap[m_cSize]; - Heap_SiftDown(0); - return iReturn; + 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) +#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) +void CQueuePriority::Heap_SiftDown( int iSubRoot ) { int parent = iSubRoot; - int child = HEAP_LEFT_CHILD(parent); + int child = HEAP_LEFT_CHILD( parent ); - struct tag_HEAP_NODE Ref = m_heap[ parent ]; + struct tag_HEAP_NODE Ref = m_heap[parent]; - while (child < m_cSize) + while( child < m_cSize ) { - int rightchild = HEAP_RIGHT_CHILD(parent); - if (rightchild < m_cSize) + int rightchild = HEAP_RIGHT_CHILD( parent ); + if( rightchild < m_cSize ) { - if ( m_heap[ rightchild ].Priority < m_heap[ child ].Priority ) + if( m_heap[rightchild].Priority < m_heap[child].Priority ) { child = rightchild; } } - if ( Ref.Priority <= m_heap[ child ].Priority ) + if( Ref.Priority <= m_heap[child].Priority ) break; - m_heap[ parent ] = m_heap[ child ]; + m_heap[parent] = m_heap[child]; parent = child; - child = HEAP_LEFT_CHILD(parent); + child = HEAP_LEFT_CHILD( parent ); } - m_heap[ parent ] = Ref; + m_heap[parent] = Ref; } -void CQueuePriority::Heap_SiftUp(void) +void CQueuePriority::Heap_SiftUp( void ) { - int child = m_cSize-1; - while (child) + int child = m_cSize - 1; + while( child ) { - int parent = HEAP_PARENT(child); - if ( m_heap[ parent ].Priority <= m_heap[ child ].Priority ) + 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; + Tmp = m_heap[child]; + m_heap[child] = m_heap[parent]; + m_heap[parent] = Tmp; child = parent; } @@ -2335,29 +2356,29 @@ void CQueuePriority::Heap_SiftUp(void) // will be loaded. If file cannot be loaded, the node tree // will be created and saved to disk. //========================================================= -int CGraph :: FLoadGraph ( char *szMapName ) +int CGraph::FLoadGraph( char *szMapName ) { - char szFilename[MAX_PATH]; - int iVersion; - int length; - byte *aMemFile; - byte *pMemFile; + char szFilename[MAX_PATH]; + int iVersion; + int length; + byte *aMemFile; + byte *pMemFile; // make sure the directories have been made - char szDirName[MAX_PATH]; + 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 ); + strcpy( szFilename, "maps/graphs/" ); + strcat( szFilename, szMapName ); strcat( szFilename, ".nod" ); - pMemFile = aMemFile = LOAD_FILE_FOR_ME(szFilename, &length); + pMemFile = aMemFile = LOAD_FILE_FOR_ME( szFilename, &length ); - if ( !aMemFile ) + if( !aMemFile ) { return FALSE; } @@ -2366,133 +2387,139 @@ int CGraph :: FLoadGraph ( char *szMapName ) // Read the graph version number // length -= sizeof(int); - if (length < 0) goto ShortFile; - memcpy(&iVersion, pMemFile, sizeof(int)); + if( length < 0 ) + goto ShortFile; + memcpy( &iVersion, pMemFile, sizeof(int) ); pMemFile += sizeof(int); - if ( iVersion != GRAPH_VERSION ) + 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 ); + 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)); + 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_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 ); + m_pNodes = (CNode *)calloc( sizeof(CNode), m_cNodes ); - if ( !m_pNodes ) + if( !m_pNodes ) { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", m_cNodes ); + 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); + 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 ); + m_pLinkPool = (CLink *)calloc( sizeof(CLink), m_cLinks ); - if ( !m_pLinkPool ) + if( !m_pLinkPool ) { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d link!\n", m_cLinks ); + 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; + 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 ) + if( !m_di ) { - ALERT ( at_aiconsole, "***ERROR**\nCouldn't malloc %d entries sorting nodes!\n", m_cNodes ); + 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; + 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 = (signed char *)calloc( sizeof(signed char), m_nRouteInfo ); - if ( !m_pRouteInfo ) + if( !m_pRouteInfo ) { - ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d route bytes!\n", m_nRouteInfo ); + 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++) + 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;; + 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) + 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 ); + 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; + 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) + FREE_FILE( aMemFile ); + + if( length != 0 ) { - ALERT ( at_aiconsole, "***WARNING***:Node graph was longer than expected by %d bytes.!\n", length); + ALERT( at_aiconsole, "***WARNING***:Node graph was longer than expected by %d bytes.!\n", length ); } return TRUE; @@ -2500,7 +2527,7 @@ int CGraph :: FLoadGraph ( char *szMapName ) ShortFile: NoMemory: - FREE_FILE(aMemFile); + FREE_FILE( aMemFile ); return FALSE; } @@ -2508,16 +2535,16 @@ NoMemory: // CGraph - FSaveGraph - It's not rocket science. // this WILL overwrite existing files. //========================================================= -int CGraph :: FSaveGraph ( char *szMapName ) +int CGraph::FSaveGraph( char *szMapName ) { - - int iVersion = GRAPH_VERSION; - char szFilename[MAX_PATH]; - FILE *file; + 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" ); + 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; } @@ -2532,43 +2559,44 @@ int CGraph :: FSaveGraph ( char *szMapName ) strcat( szFilename, szMapName ); strcat( szFilename, ".nod" ); - file = fopen ( szFilename, "wb" ); + file = fopen( szFilename, "wb" ); - ALERT ( at_aiconsole, "Created: %s\n", szFilename ); + ALERT( at_aiconsole, "Created: %s\n", szFilename ); - if ( !file ) - {// couldn't create - ALERT ( at_aiconsole, "Couldn't Create: %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 version + fwrite( &iVersion, sizeof(int), 1, file ); - // write the CGraph class - fwrite ( this, sizeof ( CGraph ), 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 nodes + fwrite( m_pNodes, sizeof(CNode), m_cNodes, file ); - // write the links - fwrite ( m_pLinkPool, sizeof ( CLink ), m_cLinks, file ); + // write the links + fwrite( m_pLinkPool, sizeof(CLink), m_cLinks, file ); - fwrite ( m_di, sizeof(DIST_INFO), m_cNodes, file ); + fwrite( m_di, sizeof(DIST_INFO), m_cNodes, file ); // Write the route info. // - if ( m_pRouteInfo && m_nRouteInfo ) + if( m_pRouteInfo && m_nRouteInfo ) { - fwrite ( m_pRouteInfo, sizeof( signed char ), m_nRouteInfo, file ); + fwrite( m_pRouteInfo, sizeof(signed char), m_nRouteInfo, file ); } - if (m_pHashLinks && m_nHashLinks) + if( m_pHashLinks && m_nHashLinks ) { - fwrite(m_pHashLinks, sizeof(short), m_nHashLinks, file); + fwrite( m_pHashLinks, sizeof(short), m_nHashLinks, file ); } - fclose ( file ); + fclose( file ); return TRUE; } } @@ -2580,15 +2608,15 @@ int CGraph :: FSaveGraph ( char *szMapName ) // this is done after loading the graph from disk, whereupon // the pointers are not valid. //========================================================= -int CGraph :: FSetGraphPointers ( void ) +int CGraph::FSetGraphPointers( void ) { - int i; + 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 ) + 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 @@ -2596,24 +2624,24 @@ int CGraph :: FSetGraphPointers ( void ) // 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 ); + memcpy( name, m_pLinkPool[i].m_szLinkEntModelname, 4 ); name[4] = 0; pentLinkEnt = FIND_ENTITY_BY_STRING( NULL, "model", name ); - if ( FNullEnt ( pentLinkEnt ) ) + 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; + // 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 ); + m_pLinkPool[i].m_pLinkEnt = VARS( pentLinkEnt ); - if ( !FBitSet( m_pLinkPool[ i ].m_pLinkEnt->flags, FL_GRAPHED ) ) + if( !FBitSet( m_pLinkPool[i].m_pLinkEnt->flags, FL_GRAPHED ) ) { - m_pLinkPool[ i ].m_pLinkEnt->flags += FL_GRAPHED; + m_pLinkPool[i].m_pLinkEnt->flags += FL_GRAPHED; } } } @@ -2639,30 +2667,30 @@ int CGraph :: FSetGraphPointers ( void ) // 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 CGraph::CheckNODFile( char *szMapName ) { - int retValue; + int retValue; - char szBspFilename[MAX_PATH]; - char szGraphFilename[MAX_PATH]; - + char szBspFilename[MAX_PATH]; + char szGraphFilename[MAX_PATH]; - strcpy ( szBspFilename, "maps/" ); - strcat ( szBspFilename, szMapName ); - strcat ( szBspFilename, ".bsp" ); + strcpy( szBspFilename, "maps/" ); + strcat( szBspFilename, szMapName ); + strcat( szBspFilename, ".bsp" ); + + strcpy( szGraphFilename, "maps/graphs/" ); + strcat( szGraphFilename, szMapName ); + strcat( szGraphFilename, ".nod" ); - strcpy ( szGraphFilename, "maps/graphs/" ); - strcat ( szGraphFilename, szMapName ); - strcat ( szGraphFilename, ".nod" ); - retValue = TRUE; int iCompare; - if (COMPARE_FILE_TIME(szBspFilename, szGraphFilename, &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" ); + if( iCompare > 0 ) + { + // BSP file is newer. + ALERT( at_aiconsole, ".NOD File will be updated\n\n" ); retValue = FALSE; } } @@ -2682,53 +2710,55 @@ struct tagNodePair short iDest; }; -void CGraph::HashInsert(int iSrcNode, int iDestNode, int iKey) +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); + 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; - } + 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) +void CGraph::HashSearch( int iSrcNode, int iDestNode, int &iKey ) { struct tagNodePair np; - np.iSrc = iSrcNode; + np.iSrc = iSrcNode; np.iDest = iDestNode; CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(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) - { + 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; - } - } + } + else + { + i += di; + if( i >= m_nHashLinks ) + i -= m_nHashLinks; + } + } iKey = m_pHashLinks[i]; } @@ -2747,72 +2777,73 @@ int Primes[NUMBER_OF_PRIMES] = 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) +void CGraph::HashChoosePrimes( int TableSize ) { - int iPrime, iZone; - int LargestPrime = TableSize/2; - if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) - { - LargestPrime = Primes[NUMBER_OF_PRIMES-2]; - } - int Spacing = LargestPrime/16; + int iPrime, iZone; + 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. - // - 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; - } - } + // 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. + // + 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]; - } + // 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; - } + // 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) +void CGraph::SortNodes( void ) { // We are using m_iPreviousNode to be the new node number. // After assigning new node numbers to everything, we move @@ -2820,19 +2851,19 @@ void CGraph::SortNodes(void) // int i, iNodeCnt = 0; m_pNodes[0].m_iPreviousNode = iNodeCnt++; - for (i = 1; i < m_cNodes; i++) + for( i = 1; i < m_cNodes; i++ ) { m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; } - for (i = 0; i < m_cNodes; i++) + 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++ ) + for( int j = 0; j < m_pNodes[i].m_cNumLinks; j++ ) { - int iDestNode = INodeLink(i, j); - if (m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE) + int iDestNode = INodeLink( i, j ); + if( m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE ) { m_pNodes[iDestNode].m_iPreviousNode = iNodeCnt++; } @@ -2841,9 +2872,9 @@ void CGraph::SortNodes(void) // Assign remaining node numbers to unlinked nodes. // - for (i = 0; i < m_cNodes; i++) + for( i = 0; i < m_cNodes; i++ ) { - if (m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE) + if( m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE ) { m_pNodes[i].m_iPreviousNode = iNodeCnt++; } @@ -2851,7 +2882,7 @@ void CGraph::SortNodes(void) // Alter links to reflect new node numbers. // - for (i = 0; i < m_cLinks; i++) + 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; @@ -2859,9 +2890,9 @@ void CGraph::SortNodes(void) // Rearrange nodes to reflect new node numbering. // - for (i = 0; i < m_cNodes; i++) + for( i = 0; i < m_cNodes; i++ ) { - while (m_pNodes[i].m_iPreviousNode != 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. @@ -2874,140 +2905,141 @@ void CGraph::SortNodes(void) } } -void CGraph::BuildLinkLookups(void) +void CGraph::BuildLinkLookups( void ) { int i; - m_nHashLinks = 3*m_cLinks/2 + 3; + m_nHashLinks = 3 * m_cLinks / 2 + 3; - HashChoosePrimes(m_nHashLinks); - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) + HashChoosePrimes( m_nHashLinks ); + m_pHashLinks = (short *)calloc( sizeof(short), m_nHashLinks ); + if( !m_pHashLinks ) { - ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); + ALERT( at_aiconsole, "Couldn't allocated Link Lookup Table.\n" ); return; } - for ( i = 0; i < m_nHashLinks; i++ ) + for( i = 0; i < m_nHashLinks; i++ ) { m_pHashLinks[i] = ENTRY_STATE_EMPTY; } - for (i = 0; i < m_cLinks; i++) + for( i = 0; i < m_cLinks; i++ ) { - CLink &link = Link(i); - HashInsert(link.m_iSrcNode, link.m_iDestNode, i); + CLink &link = Link( i ); + HashInsert( link.m_iSrcNode, link.m_iDestNode, i ); } #if 0 - for (i = 0; i < m_cLinks; i++) + for( i = 0; i < m_cLinks; i++ ) { - CLink &link = Link(i); + CLink &link = Link( i ); int iKey; - HashSearch(link.m_iSrcNode, link.m_iDestNode, iKey); - if (iKey != i) + HashSearch( link.m_iSrcNode, link.m_iDestNode, iKey ); + if( iKey != i ) { - ALERT(at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey); + ALERT( at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey ); } } #endif } -void CGraph::BuildRegionTables(void) +void CGraph::BuildRegionTables( void ) { int i, j; - if (m_di) free(m_di); + 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) + m_di = (DIST_INFO *)calloc( sizeof(DIST_INFO), m_cNodes ); + if( !m_di ) { - ALERT(at_aiconsole, "Couldn't allocated node ordering array.\n"); + ALERT( at_aiconsole, "Couldn't allocated node ordering array.\n" ); return; } // Calculate regions for all the nodes. // // - for ( i = 0; i < 3; 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++) + for( i = 0; i < m_cNodes; i++ ) { - if (m_pNodes[i].m_vecOrigin.x < m_RegionMin[0]) + 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]) + 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]) + 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]) + 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]) + 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]) + 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++) + 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]); + 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++) + for( i = 0; i < 3; i++ ) { - for (j = 0; j < NUM_RANGES; 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++) + for( j = 0; j < m_cNodes; j++ ) { m_di[j].m_SortedBy[i] = j; } - for (j = 0; j < m_cNodes - 1; 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) + switch( i ) { case 0: - jCode = (jCodeX << 16) + (jCodeY << 8) + jCodeZ; + jCode = ( jCodeX << 16 ) + ( jCodeY << 8 ) + jCodeZ; break; case 1: - jCode = (jCodeY << 16) + (jCodeZ << 8) + jCodeX; + jCode = ( jCodeY << 16 ) + ( jCodeZ << 8 ) + jCodeX; break; case 2: - jCode = (jCodeZ << 16) + (jCodeX << 8) + jCodeY; + jCode = ( jCodeZ << 16 ) + ( jCodeX << 8 ) + jCodeY; break; } - for (int k = j+1; k < m_cNodes; k++) + 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) + switch( i ) { case 0: - kCode = (kCodeX << 16) + (kCodeY << 8) + kCodeZ; + kCode = ( kCodeX << 16 ) + ( kCodeY << 8 ) + kCodeZ; break; case 1: - kCode = (kCodeY << 16) + (kCodeZ << 8) + kCodeX; + kCode = ( kCodeY << 16 ) + ( kCodeZ << 8 ) + kCodeX; break; case 2: - kCode = (kCodeZ << 16) + (kCodeX << 8) + kCodeY; + kCode = ( kCodeZ << 16 ) + ( kCodeX << 8 ) + kCodeY; break; } - if (kCode < jCode) + if( kCode < jCode ) { // Swap j and k entries. // @@ -3021,102 +3053,100 @@ void CGraph::BuildRegionTables(void) // Generate lookup tables. // - for (i = 0; i < m_cNodes; i++) + 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; - } + 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)); + memset( m_Cache, 0, sizeof(m_Cache) ); } -void CGraph :: ComputeStaticRoutingTables( void ) +void CGraph::ComputeStaticRoutingTables( void ) { int iFrom; - int nRoutes = m_cNodes*m_cNodes; -#define FROM_TO(x,y) ((x)*m_cNodes+(y)) + 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]; signed char *pRoute = new signed char[m_cNodes*2]; - - if (Routes && pMyPath && BestNextNodes && pRoute) + if( Routes && pMyPath && BestNextNodes && pRoute ) { int nTotalCompressedSize = 0; - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) + for( int iHull = 0; iHull < MAX_NODE_HULLS; iHull++ ) { - for (int iCap = 0; iCap < 2; iCap++) + for( int iCap = 0; iCap < 2; iCap++ ) { int iCapMask; - switch (iCap) + 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. // - for (iFrom = 0; iFrom < m_cNodes; iFrom++) + for( iFrom = 0; iFrom < m_cNodes; iFrom++ ) { - for (int iTo = 0; iTo < m_cNodes; iTo++) + for( int iTo = 0; iTo < m_cNodes; iTo++ ) { - Routes[FROM_TO(iFrom, iTo)] = -1; + Routes[FROM_TO( iFrom, iTo )] = -1; } } - for (iFrom = 0; iFrom < m_cNodes; iFrom++) + for( iFrom = 0; iFrom < m_cNodes; iFrom++ ) { - for (int iTo = m_cNodes-1; iTo >= 0; iTo--) + for( int iTo = m_cNodes - 1; iTo >= 0; iTo-- ) { - if (Routes[FROM_TO(iFrom, iTo)] != -1) continue; + if( Routes[FROM_TO( iFrom, iTo )] != -1 ) + continue; - int cPathSize = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + int cPathSize = FindShortestPath( pMyPath, iFrom, iTo, iHull, iCapMask ); // Use the computed path to update the routing table. // - if (cPathSize > 1) + if( cPathSize > 1 ) { - for (int iNode = 0; iNode < cPathSize-1; iNode++) + 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 iNext = pMyPath[iNode + 1]; + for( int iNode1 = iNode + 1; iNode1 < cPathSize; iNode1++ ) { int iEnd = pMyPath[iNode1]; Routes[FROM_TO(iStart, iEnd)] = iNext; @@ -3128,31 +3158,31 @@ void CGraph :: ComputeStaticRoutingTables( void ) // particular direction. Some links don't appear to have links in // the opposite direction. // - for (iNode = cPathSize-1; iNode >= 1; iNode--) + 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 iNext = pMyPath[iNode - 1]; + for( int iNode1 = iNode-1; iNode1 >= 0; iNode1-- ) { int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; + Routes[FROM_TO( iStart, iEnd )] = iNext; } } #endif } else { - Routes[FROM_TO(iFrom, iTo)] = iFrom; - Routes[FROM_TO(iTo, iFrom)] = iTo; + Routes[FROM_TO( iFrom, iTo )] = iFrom; + Routes[FROM_TO( iTo, iFrom )] = iTo; } } } - for (iFrom = 0; iFrom < m_cNodes; iFrom++) + for( iFrom = 0; iFrom < m_cNodes; iFrom++ ) { - for (int iTo = 0; iTo < m_cNodes; iTo++) + for( int iTo = 0; iTo < m_cNodes; iTo++ ) { - BestNextNodes[iTo] = Routes[FROM_TO(iFrom, iTo)]; + BestNextNodes[iTo] = Routes[FROM_TO( iFrom, iTo )]; } // Compress this node's routing table. @@ -3162,14 +3192,14 @@ void CGraph :: ComputeStaticRoutingTables( void ) int cRepeats = 0; int CompressedSize = 0; signed char *p = pRoute; - for (int i = 0; i < m_cNodes; i++) + for( int i = 0; i < m_cNodes; i++ ) { - BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); - BOOL CanSequence = (BestNextNodes[i] == i && cSequence < 128); + BOOL CanRepeat = ( ( BestNextNodes[i] == iLastNode ) && cRepeats < 127 ); + BOOL CanSequence = ( BestNextNodes[i] == i && cSequence < 128 ); - if (cRepeats) + if( cRepeats ) { - if (CanRepeat) + if( CanRepeat ) { cRepeats++; } @@ -3182,25 +3212,25 @@ void CGraph :: ComputeStaticRoutingTables( void ) int a = iLastNode - iFrom; int b = iLastNode - iFrom + m_cNodes; int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) + if( -128 <= a && a <= 127 ) { *p++ = a; } - else if (-128 <= b && b <= 127) + else if( -128 <= b && b <= 127 ) { *p++ = b; } - else if (-128 <= c && c <= 127) + else if( -128 <= c && c <= 127 ) { *p++ = c; } else { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); + ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom ); } cRepeats = 0; - if (CanSequence) + if( CanSequence ) { // Start a sequence. // @@ -3214,9 +3244,9 @@ void CGraph :: ComputeStaticRoutingTables( void ) } } } - else if (cSequence) + else if( cSequence ) { - if (CanSequence) + if( CanSequence ) { cSequence++; } @@ -3226,7 +3256,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) // a single-entry sequence phrase with the // next repeat phrase. // - if (cSequence == 1 && CanRepeat) + if( cSequence == 1 && CanRepeat ) { // Combine with repeat phrase. // @@ -3249,7 +3279,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) } else { - if (CanSequence) + if( CanSequence ) { // Start a sequence phrase. // @@ -3264,7 +3294,7 @@ void CGraph :: ComputeStaticRoutingTables( void ) } iLastNode = BestNextNodes[i]; } - if (cRepeats) + if( cRepeats ) { // Emit the repeat phrase. // @@ -3272,30 +3302,32 @@ void CGraph :: ComputeStaticRoutingTables( void ) *p++ = cRepeats - 1; #if 0 iLastNode = iFrom + *pRoute; - if (iLastNode >= m_cNodes) iLastNode -= m_cNodes; - else if (iLastNode < 0) iLastNode += m_cNodes; + 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) + if( -128 <= a && a <= 127 ) { *p++ = a; } - else if (-128 <= b && b <= 127) + else if( -128 <= b && b <= 127 ) { *p++ = b; } - else if (-128 <= c && c <= 127) + else if( -128 <= c && c <= 127 ) { *p++ = c; } else { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); + ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom ); } } - if (cSequence) + if( cSequence ) { // Emit the Sequence phrase. // @@ -3306,28 +3338,28 @@ void CGraph :: ComputeStaticRoutingTables( void ) // Go find a place to store this thing and point to it. // int nRoute = p - pRoute; - if (m_pRouteInfo) + if( m_pRouteInfo ) { int i; - for (i = 0; i < m_nRouteInfo - nRoute; i++) + for( i = 0; i < m_nRouteInfo - nRoute; i++ ) { - if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) + if( memcmp( m_pRouteInfo + i, pRoute, nRoute ) == 0 ) { break; } } - if (i < m_nRouteInfo - nRoute) + if( i < m_nRouteInfo - nRoute ) { - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = i; + m_pNodes[iFrom].m_pNextBestNode[iHull][iCap] = i; } else { - signed char *Tmp = (signed char *)calloc(sizeof(signed char), (m_nRouteInfo + nRoute)); - memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); - free(m_pRouteInfo); + signed char *Tmp = (signed char *)calloc( sizeof(signed 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; + memcpy( m_pRouteInfo + m_nRouteInfo, pRoute, nRoute ); + m_pNodes[iFrom].m_pNextBestNode[iHull][iCap] = m_nRouteInfo; m_nRouteInfo += nRoute; nTotalCompressedSize += CompressedSize; } @@ -3335,20 +3367,24 @@ void CGraph :: ComputeStaticRoutingTables( void ) else { m_nRouteInfo = nRoute; - m_pRouteInfo = (signed char *)calloc(sizeof(signed char), nRoute); - memcpy(m_pRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; + m_pRouteInfo = (signed char *)calloc( sizeof(signed 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); + } + 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; + if( Routes ) + delete[] Routes; + if( BestNextNodes ) + delete[] BestNextNodes; + if( pRoute ) + delete[] pRoute; + if( pMyPath ) + delete[] pMyPath; Routes = 0; BestNextNodes = 0; pRoute = 0; @@ -3361,114 +3397,116 @@ void CGraph :: ComputeStaticRoutingTables( void ) // Test those routing tables. Doesn't really work, yet. // -void CGraph :: TestRoutingTables( void ) +void CGraph::TestRoutingTables( void ) { int i; int *pMyPath = new int[m_cNodes]; int *pMyPath2 = new int[m_cNodes]; - if (pMyPath && pMyPath2) + if( pMyPath && pMyPath2 ) { - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) + for( int iHull = 0; iHull < MAX_NODE_HULLS; iHull++ ) { - for (int iCap = 0; iCap < 2; iCap++) + for( int iCap = 0; iCap < 2; iCap++ ) { int iCapMask; - switch (iCap) + 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 iFrom = 0; iFrom < m_cNodes; iFrom++ ) { - for (int iTo = 0; iTo < m_cNodes; iTo++) + for( int iTo = 0; iTo < m_cNodes; iTo++ ) { m_fRoutingComplete = FALSE; - int cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + int cPathSize1 = FindShortestPath( pMyPath, iFrom, iTo, iHull, iCapMask ); m_fRoutingComplete = TRUE; - int cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); + 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; + if( cPathSize2 == MAX_PATH_SIZE ) + continue; // Compare distances. // #if 1 float flDistance1 = 0.0; - for ( i = 0; i < cPathSize1-1; 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; + if( pMyPath[i] == pMyPath[i + 1] ) + continue; int iVisitNode; BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++) + for( int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++ ) { - iVisitNode = INodeLink ( pMyPath[i], iLink ); - if (iVisitNode == pMyPath[i+1]) + iVisitNode = INodeLink( pMyPath[i], iLink ); + if( iVisitNode == pMyPath[i + 1] ) { - flDistance1 += m_pLinkPool[ m_pNodes[ pMyPath[i] ].m_iFirstLink + iLink].m_flWeight; + flDistance1 += m_pLinkPool[m_pNodes[pMyPath[i]].m_iFirstLink + iLink].m_flWeight; bFound = TRUE; break; } } - if (!bFound) + if( !bFound ) { - ALERT(at_aiconsole, "No link.\n"); + ALERT( at_aiconsole, "No link.\n" ); } } float flDistance2 = 0.0; - for (i = 0; i < cPathSize2-1; i++) + for( i = 0; i < cPathSize2 - 1; i++ ) { // Find the link from pMyPath2[i] to pMyPath2[i+1] // - if (pMyPath2[i] == pMyPath2[i+1]) continue; + if( pMyPath2[i] == pMyPath2[i + 1] ) + continue; int iVisitNode; BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++) + for( int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++ ) { - iVisitNode = INodeLink ( pMyPath2[i], iLink ); - if (iVisitNode == pMyPath2[i+1]) + iVisitNode = INodeLink( pMyPath2[i], iLink ); + if( iVisitNode == pMyPath2[i + 1] ) { - flDistance2 += m_pLinkPool[ m_pNodes[ pMyPath2[i] ].m_iFirstLink + iLink].m_flWeight; + flDistance2 += m_pLinkPool[m_pNodes[pMyPath2[i]].m_iFirstLink + iLink].m_flWeight; bFound = TRUE; break; } } - if (!bFound) + if( !bFound ) { - ALERT(at_aiconsole, "No link.\n"); + ALERT( at_aiconsole, "No link.\n" ); } } - if (fabs(flDistance1 - flDistance2) > 0.10) + if( fabs( flDistance1 - flDistance2 ) > 0.10 ) { #else - if (cPathSize1 != cPathSize2 || memcmp(pMyPath, pMyPath2, sizeof(int)*cPathSize1) != 0) + 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 ( i = 0; i < cPathSize1; i++ ) + ALERT( at_aiconsole, "Routing is inconsistent!!!\n" ); + ALERT( at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap ); + for( i = 0; i < cPathSize1; i++ ) { - ALERT(at_aiconsole, "%d ", pMyPath[i]); + ALERT( at_aiconsole, "%d ", pMyPath[i] ); } - ALERT(at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap); - for (i = 0; i < cPathSize2; i++) + ALERT( at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap ); + for( i = 0; i < cPathSize2; i++ ) { - ALERT(at_aiconsole, "%d ", pMyPath2[i]); + ALERT( at_aiconsole, "%d ", pMyPath2[i] ); } - ALERT(at_aiconsole, "\n"); + ALERT( at_aiconsole, "\n" ); m_fRoutingComplete = FALSE; - cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); + cPathSize1 = FindShortestPath( pMyPath, iFrom, iTo, iHull, iCapMask ); m_fRoutingComplete = TRUE; - cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); + cPathSize2 = FindShortestPath( pMyPath2, iFrom, iTo, iHull, iCapMask ); goto EnoughSaid; } } @@ -3478,8 +3516,10 @@ void CGraph :: TestRoutingTables( void ) } EnoughSaid: - if (pMyPath) delete[] pMyPath; - if (pMyPath2) delete[] pMyPath2; + if( pMyPath ) + delete[] pMyPath; + if( pMyPath2 ) + delete[] pMyPath2; pMyPath = 0; pMyPath2 = 0; } @@ -3496,7 +3536,7 @@ public: int m_iBaseNode; int m_iDraw; - int m_nVisited; + int m_nVisited; int m_aFrom[128]; int m_aTo[128]; int m_iHull; @@ -3513,23 +3553,23 @@ 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( ) +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" ); + 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")) + 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")) + else if( FClassnameIs( pev, "node_viewer_large" ) ) { m_iHull = NODE_LARGE_HULL; m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; @@ -3542,10 +3582,9 @@ void CNodeViewer::Spawn( ) m_vecColor = Vector( 255, 160, 100 ); } + m_iBaseNode = WorldGraph.FindNearestNode( pev->origin, m_afNodeType ); - m_iBaseNode = WorldGraph.FindNearestNode ( pev->origin, m_afNodeType ); - - if ( m_iBaseNode < 0 ) + if( m_iBaseNode < 0 ) { ALERT( at_console, "No nearby node\n" ); return; @@ -3555,11 +3594,11 @@ void CNodeViewer::Spawn( ) ALERT( at_aiconsole, "basenode %d\n", m_iBaseNode ); - if (WorldGraph.m_cNodes < 128) + if( WorldGraph.m_cNodes < 128 ) { - for (int i = 0; i < WorldGraph.m_cNodes; i++) + for( int i = 0; i < WorldGraph.m_cNodes; i++ ) { - AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 )); + AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 ) ); } } else @@ -3569,15 +3608,15 @@ void CNodeViewer::Spawn( ) int start = 0; int end; - do { + do{ end = m_nVisited; // ALERT( at_console, "%d :", m_nVisited ); - for (end = m_nVisited; start < end; start++) + for( end = m_nVisited; start < end; start++ ) { FindNodeConnections( m_aFrom[start] ); FindNodeConnections( m_aTo[start] ); } - } while (end != m_nVisited); + } while( end != m_nVisited ); } ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); @@ -3587,32 +3626,32 @@ void CNodeViewer::Spawn( ) pev->nextthink = gpGlobals->time; } -void CNodeViewer :: FindNodeConnections ( int iNode ) +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++ ) + 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 )); + 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) + if( m_nVisited >= 128 ) { return; } else { - if (iFrom == iTo) + if( iFrom == iTo ) return; - for (int i = 0; i < m_nVisited; i++) + for( int i = 0; i < m_nVisited; i++ ) { - if (m_aFrom[i] == iFrom && m_aTo[i] == iTo) + if( m_aFrom[i] == iFrom && m_aTo[i] == iTo ) return; - if (m_aFrom[i] == iTo && m_aTo[i] == iFrom) + if( m_aFrom[i] == iTo && m_aTo[i] == iFrom ) return; } m_aFrom[m_nVisited] = iFrom; @@ -3621,14 +3660,13 @@ void CNodeViewer::AddNode( int iFrom, int iTo ) } } - -void CNodeViewer :: DrawThink( void ) +void CNodeViewer::DrawThink( void ) { pev->nextthink = gpGlobals->time; - for (int i = 0; i < 10; i++) + for( int i = 0; i < 10; i++ ) { - if (m_iDraw == m_nVisited) + if( m_iDraw == m_nVisited ) { UTIL_Remove( this ); return; @@ -3637,13 +3675,13 @@ void CNodeViewer :: DrawThink( void ) 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_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_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 diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index 97747f2b..95088d2b 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -38,15 +38,15 @@ typedef struct 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; } - + 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; } + int Classify( void ) { return CLASS_MACHINE; }; + int BloodColor( void ) { return DONT_BLEED; } void Killed( entvars_t *pevAttacker, int iGib ); void UpdateGoal( void ); @@ -62,8 +62,8 @@ public: 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); + // 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; @@ -84,7 +84,7 @@ public: float m_flRightHealth; float m_flLeftHealth; - int m_iUnits; + int m_iUnits; EHANDLE m_hGrunt[MAX_CARRY]; Vector m_vecOrigin[MAX_CARRY]; EHANDLE m_hRepel[4]; @@ -95,9 +95,9 @@ public: int m_iPitch; int m_iExplode; - int m_iTailGibs; - int m_iBodyGibs; - int m_iEngineGibs; + int m_iTailGibs; + int m_iBodyGibs; + int m_iEngineGibs; int m_iDoLeftSmokePuff; int m_iDoRightSmokePuff; @@ -140,35 +140,35 @@ TYPEDESCRIPTION COsprey::m_SaveData[] = IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ) -void COsprey :: Spawn( void ) +void COsprey::Spawn( void ) { - Precache( ); + 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)); + 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; + 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); + ResetSequenceInfo(); + pev->frame = RANDOM_LONG( 0, 0xFF ); InitBoneControllers(); SetThink( &COsprey::FindAllThink ); SetUse( &COsprey::CommandUse ); - if (!(pev->spawnflags & SF_WAITFORTRIGGER)) + if( !( pev->spawnflags & SF_WAITFORTRIGGER ) ) { pev->nextthink = gpGlobals->time + 1.0; } @@ -182,15 +182,15 @@ void COsprey::Precache( void ) { UTIL_PrecacheOther( "monster_human_grunt" ); - PRECACHE_MODEL("models/osprey.mdl"); - PRECACHE_MODEL("models/HVR.mdl"); + PRECACHE_MODEL( "models/osprey.mdl" ); + PRECACHE_MODEL( "models/HVR.mdl" ); - PRECACHE_SOUND("apache/ap_rotor4.wav"); - PRECACHE_SOUND("weapons/mortarhit.wav"); + 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_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" ); @@ -201,24 +201,24 @@ void COsprey::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP pev->nextthink = gpGlobals->time + 0.1; } -void COsprey :: FindAllThink( void ) +void COsprey::FindAllThink( void ) { CBaseEntity *pEntity = NULL; m_iUnits = 0; - while (m_iUnits < MAX_CARRY && (pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" )) != NULL) + while( m_iUnits < MAX_CARRY && ( pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" ) ) != NULL ) { - if (pEntity->IsAlive()) + if( pEntity->IsAlive() ) { - m_hGrunt[m_iUnits] = pEntity; - m_vecOrigin[m_iUnits] = pEntity->pev->origin; + m_hGrunt[m_iUnits] = pEntity; + m_vecOrigin[m_iUnits] = pEntity->pev->origin; m_iUnits++; } } - if (m_iUnits == 0) + if( m_iUnits == 0 ) { - ALERT( at_console, "osprey error: no grunts to resupply\n"); + ALERT( at_console, "osprey error: no grunts to resupply\n" ); UTIL_Remove( this ); return; } @@ -227,7 +227,7 @@ void COsprey :: FindAllThink( void ) m_startTime = gpGlobals->time; } -void COsprey :: DeployThink( void ) +void COsprey::DeployThink( void ) { UTIL_MakeAimVectors( pev->angles ); @@ -238,8 +238,8 @@ void COsprey :: DeployThink( void ) 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 ); + 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 ); @@ -257,11 +257,11 @@ void COsprey :: DeployThink( void ) pev->nextthink = gpGlobals->time + 0.1; } -BOOL COsprey :: HasDead( ) +BOOL COsprey::HasDead() { - for (int i = 0; i < m_iUnits; i++) + for( int i = 0; i < m_iUnits; i++ ) { - if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) + if( m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive() ) { return TRUE; } @@ -273,26 +273,26 @@ BOOL COsprey :: HasDead( ) return FALSE; } -CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) +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) + 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++) + for( int i = 0; i < m_iUnits; i++ ) { - if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) + if( m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive() ) { - if (m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal) + if( m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal ) { - m_hGrunt[i]->SUB_StartFadeOut( ); + m_hGrunt[i]->SUB_StartFadeOut(); } pEntity = Create( "monster_human_grunt", vecSrc, pev->angles ); - pGrunt = pEntity->MyMonsterPointer( ); + pGrunt = pEntity->MyMonsterPointer(); pGrunt->pev->movetype = MOVETYPE_FLY; pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); pGrunt->SetActivity( ACT_GLIDE ); @@ -314,18 +314,18 @@ CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) return NULL; } -void COsprey :: HoverThink( void ) +void COsprey::HoverThink( void ) { int i; - for (i = 0; i < 4; i++) + for( i = 0; i < 4; i++ ) { - if (m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) + if( m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !( m_hRepel[i]->pev->flags & FL_ONGROUND ) ) { break; } } - if (i == 4) + if( i == 4 ) { m_startTime = gpGlobals->time; SetThink( &COsprey::FlyThink ); @@ -333,12 +333,12 @@ void COsprey :: HoverThink( void ) pev->nextthink = gpGlobals->time + 0.1; UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); + ShowDamage(); } -void COsprey::UpdateGoal( ) +void COsprey::UpdateGoal() { - if (m_pGoalEnt) + if( m_pGoalEnt ) { m_pos1 = m_pos2; m_ang1 = m_ang2; @@ -349,65 +349,65 @@ void COsprey::UpdateGoal( ) 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); + m_dTime = 2.0 * ( m_pos1 - m_pos2 ).Length() / ( m_vel1.Length() + m_pGoalEnt->pev->speed ); - if (m_ang1.y - m_ang2.y < -180) + if( m_ang1.y - m_ang2.y < -180 ) { m_ang1.y += 360; } - else if (m_ang1.y - m_ang2.y > 180) + else if( m_ang1.y - m_ang2.y > 180 ) { m_ang1.y -= 360; } - if (m_pGoalEnt->pev->speed < 400) + if( m_pGoalEnt->pev->speed < 400 ) m_flIdealtilt = 0; else m_flIdealtilt = -90; } else { - ALERT( at_console, "osprey missing target"); + ALERT( at_console, "osprey missing target" ); } } void COsprey::FlyThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target + 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( ); + m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ) ); + UpdateGoal(); } - if (gpGlobals->time > m_startTime + m_dTime) + if( gpGlobals->time > m_startTime + m_dTime ) { - if (m_pGoalEnt->pev->speed == 0) + 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( ); + 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( ); + Flight(); + ShowDamage(); } -void COsprey::Flight( ) +void COsprey::Flight() { - float t = (gpGlobals->time - m_startTime); + 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; + 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; @@ -416,28 +416,27 @@ void COsprey::Flight( ) // float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity ); - float m_flIdealtilt = (160 - flSpeed) / 10.0; + float m_flIdealtilt = ( 160 - flSpeed ) / 10.0; // ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt ); - if (m_flRotortilt < m_flIdealtilt) + if( m_flRotortilt < m_flIdealtilt ) { m_flRotortilt += 0.5; - if (m_flRotortilt > 0) + if ( m_flRotortilt > 0 ) m_flRotortilt = 0; } - if (m_flRotortilt > m_flIdealtilt) + if( m_flRotortilt > m_flIdealtilt ) { m_flRotortilt -= 0.5; - if (m_flRotortilt < -90) + if( m_flRotortilt < -90 ) m_flRotortilt = -90; } SetBoneController( 0, m_flRotortilt ); - - if (m_iSoundState == 0) + 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 ); + 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 } @@ -447,28 +446,28 @@ void COsprey::Flight( ) pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) + if( pPlayer ) { - float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); + float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, ( pPlayer->pev->origin - pev->origin ).Normalize() ); - pitch = (int)(100 + pitch / 75.0); + pitch = (int)( 100 + pitch / 75.0 ); - if (pitch > 250) + if( pitch > 250 ) pitch = 250; - if (pitch < 50) + if( pitch < 50 ) pitch = 50; - if (pitch == 100) + if( pitch == 100 ) pitch = 101; - if (pitch != m_iPitch) + 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); + 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); + // EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); } } @@ -481,7 +480,7 @@ void COsprey::HitTouch( CBaseEntity *pOther ) /* int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if (m_flRotortilt <= -90) + if( m_flRotortilt <= -90 ) { m_flRotortilt = 0; } @@ -494,15 +493,15 @@ int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float } */ -void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) +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" ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, "apache/ap_rotor4.wav" ); - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); + UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); SetThink( &COsprey::DyingThink ); SetTouch( &COsprey::CrashTouch ); pev->nextthink = gpGlobals->time + 0.1; @@ -515,7 +514,7 @@ void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) void COsprey::CrashTouch( CBaseEntity *pOther ) { // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) + if( pOther->pev->solid == SOLID_BSP ) { SetTouch( NULL ); m_startTime = gpGlobals->time; @@ -524,46 +523,45 @@ void COsprey::CrashTouch( CBaseEntity *pOther ) } } -void COsprey :: DyingThink( void ) +void COsprey::DyingThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; pev->avelocity = pev->avelocity * 1.02; // still falling? - if (m_startTime > gpGlobals->time ) + if( m_startTime > gpGlobals->time ) { UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); + 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_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( 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_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 + WRITE_BYTE( 10 ); // framerate MESSAGE_END(); - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_BREAKMODEL); @@ -595,12 +593,9 @@ void COsprey :: DyingThink( void ) 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; @@ -608,7 +603,7 @@ void COsprey :: DyingThink( void ) } else { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; + Vector vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -618,7 +613,7 @@ void COsprey :: DyingThink( void ) WRITE_COORD( vecSpot.z + 512 ); WRITE_SHORT( m_iExplode ); WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate + WRITE_BYTE( 10 ); // framerate MESSAGE_END(); */ @@ -641,7 +636,7 @@ void COsprey :: DyingThink( void ) WRITE_COORD( vecSpot.z + 300 ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 6 ); // framerate + WRITE_BYTE( 6 ); // framerate MESSAGE_END(); */ @@ -667,19 +662,19 @@ void COsprey :: DyingThink( void ) WRITE_BYTE( 0 ); // speed MESSAGE_END(); - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); + 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; + 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); + WRITE_COORD( vecSpot.z + 64 ); // size WRITE_COORD( 800 ); @@ -704,7 +699,6 @@ void COsprey :: DyingThink( void ) WRITE_BYTE( 200 );// 10.0 seconds // flags - WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); @@ -712,9 +706,9 @@ void COsprey :: DyingThink( void ) } } -void COsprey :: ShowDamage( void ) +void COsprey::ShowDamage( void ) { - if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0,99) > m_flLeftHealth) + 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 ); @@ -723,13 +717,13 @@ void COsprey :: ShowDamage( void ) WRITE_COORD( vecSrc.y ); WRITE_COORD( vecSrc.z ); WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 + WRITE_BYTE( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 WRITE_BYTE( 12 ); // framerate MESSAGE_END(); - if (m_iDoLeftSmokePuff > 0) + if( m_iDoLeftSmokePuff > 0 ) m_iDoLeftSmokePuff--; } - if (m_iDoRightSmokePuff > 0 || RANDOM_LONG(0,99) > m_flRightHealth) + 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 ); @@ -738,39 +732,39 @@ void COsprey :: ShowDamage( void ) WRITE_COORD( vecSrc.y ); WRITE_COORD( vecSrc.z ); WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 + WRITE_BYTE( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 WRITE_BYTE( 12 ); // framerate MESSAGE_END(); - if (m_iDoRightSmokePuff > 0) + if( m_iDoRightSmokePuff > 0 ) m_iDoRightSmokePuff--; } } -void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +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( ptr->iHitgroup == 3 ) { - if (m_flRightHealth < 0) + if( m_flRightHealth < 0 ) return; else m_flRightHealth -= flDamage; - m_iDoLeftSmokePuff = 3 + (flDamage / 5.0); + m_iDoLeftSmokePuff = 3 + ( flDamage / 5.0 ); } - if (ptr->iHitgroup == 2) + if( ptr->iHitgroup == 2 ) { - if (m_flLeftHealth < 0) + if( m_flLeftHealth < 0 ) return; else m_flLeftHealth -= flDamage; - m_iDoRightSmokePuff = 3 + (flDamage / 5.0); + m_iDoRightSmokePuff = 3 + ( flDamage / 5.0 ); } // hit hard, hits cockpit, hits engines - if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3) + if( flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3 ) { // ALERT( at_console, "%.0f\n", flDamage ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); diff --git a/dlls/pathcorner.cpp b/dlls/pathcorner.cpp index 3717ee8b..bc999675 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -25,17 +25,17 @@ class CPathCorner : public CPointEntity { public: - void Spawn( ); + 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[]; + //void Touch( CBaseEntity *pOther ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; private: - float m_flWait; + float m_flWait; }; LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ) @@ -51,67 +51,68 @@ IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ) // // Cache user-entity-field values until spawn is called. // -void CPathCorner :: KeyValue( KeyValueData *pkvd ) +void CPathCorner::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "wait")) + if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_flWait = atof(pkvd->szValue); + m_flWait = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else CPointEntity::KeyValue( pkvd ); } -void CPathCorner :: Spawn( ) +void CPathCorner::Spawn() { - ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname"); + ASSERTSZ( !FStringNull( pev->targetname ), "path_corner without a targetname" ); } #if 0 -void CPathCorner :: Touch( CBaseEntity *pOther ) +void CPathCorner::Touch( CBaseEntity *pOther ) { - entvars_t* pevToucher = pOther->pev; + entvars_t *pevToucher = pOther->pev; - if ( FBitSet ( pevToucher->flags, FL_MONSTER ) ) - {// monsters don't navigate path corners based on touch anymore + 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 ) + if( pOther->m_pGoalEnt != this ) { return; } // If OTHER has an enemy, this touch is incidental, ignore - if ( !FNullEnt(pevToucher->enemy) ) + 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"); + 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)) + if( FStringNull( pev->target ) ) { - ALERT(at_warning, "PathCornerTouch: no next stop specified"); + ALERT( at_warning, "PathCornerTouch: no next stop specified" ); } - pOther->m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ) ); + 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 ) + if( !pOther->m_pGoalEnt ) { - ALERT(at_console, "PathCornerTouch--%s couldn't find next stop in path: %s", STRING(pev->classname), STRING(pev->target)); + 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 ); + pevToucher->ideal_yaw = UTIL_VecToYaw( pOther->m_pGoalEnt->pev->origin - pevToucher->origin ); } #endif @@ -130,28 +131,28 @@ LINK_ENTITY_TO_CLASS( path_track, CPathTrack ) // // Cache user-entity-field values until spawn is called. // -void CPathTrack :: KeyValue( KeyValueData *pkvd ) +void CPathTrack::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "altpath")) + if( FStrEq( pkvd->szKeyName, "altpath" ) ) { - m_altName = ALLOC_STRING(pkvd->szValue); + 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 ) +void CPathTrack::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int on; // Use toggles between two paths - if ( m_paltpath ) + if( m_paltpath ) { on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ); - if ( ShouldToggle( useType, on ) ) + if( ShouldToggle( useType, on ) ) { - if ( on ) + if( on ) SetBits( pev->spawnflags, SF_PATH_ALTERNATE ); else ClearBits( pev->spawnflags, SF_PATH_ALTERNATE ); @@ -161,9 +162,9 @@ void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE { on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED ); - if ( ShouldToggle( useType, on ) ) + if( ShouldToggle( useType, on ) ) { - if ( on ) + if( on ) SetBits( pev->spawnflags, SF_PATH_DISABLED ); else ClearBits( pev->spawnflags, SF_PATH_DISABLED ); @@ -171,35 +172,35 @@ void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } } -void CPathTrack :: Link( void ) +void CPathTrack::Link( void ) { edict_t *pentTarget; - if ( !FStringNull(pev->target) ) + if( !FStringNull( pev->target ) ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - if ( !FNullEnt(pentTarget) ) + 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 + 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) ); + ALERT( at_console, "Dead end link %s\n", STRING( pev->target ) ); } // Find "alternate" path - if ( m_altName ) + if( m_altName ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_altName) ); - if ( !FNullEnt(pentTarget) ) + 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 + if( m_paltpath ) // If no next pointer, this is the end of a path { m_paltpath->SetPrevious( this ); } @@ -207,10 +208,10 @@ void CPathTrack :: Link( void ) } } -void CPathTrack :: Spawn( void ) +void CPathTrack::Spawn( void ) { pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + UTIL_SetSize( pev, Vector( -8, -8, -8 ), Vector( 8, 8, 8 ) ); m_pnext = NULL; m_pprevious = NULL; @@ -223,26 +224,26 @@ void CPathTrack :: Spawn( void ) void CPathTrack::Activate( void ) { - if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link + if( !FStringNull( pev->targetname ) ) // Link to next, and back-link Link(); } -CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag ) +CPathTrack *CPathTrack::ValidPath( CPathTrack *ppath, int testFlag ) { - if ( !ppath ) + if( !ppath ) return NULL; - if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) + if( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) return NULL; return ppath; } -void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) +void CPathTrack::Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) { - if ( pstart && pend ) + if( pstart && pend ) { - Vector dir = (pend->pev->origin - pstart->pev->origin); + Vector dir = pend->pev->origin - pstart->pev->origin; dir = dir.Normalize(); *origin = pend->pev->origin + dir * dist; } @@ -250,58 +251,56 @@ void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin CPathTrack *CPathTrack::GetNext( void ) { - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) + 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 ) ) + 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) ) ) + 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 *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 + if( dist < 0 ) // Travelling backwards through path { dist = -dist; - while ( dist > 0 ) + while( dist > 0 ) { Vector dir = pcurrent->pev->origin - currentPos; float length = dir.Length(); - if ( !length ) + if( !length ) { - if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. + if( !ValidPath( pcurrent->GetPrevious(), move ) ) // If there is no previous node, or it's disabled, return now. { - if ( !move ) + if( !move ) Project( pcurrent->GetNext(), pcurrent, origin, dist ); return NULL; } pcurrent = pcurrent->GetPrevious(); } - else if ( length > dist ) // enough left in this path to move + else if( length > dist ) // enough left in this path to move { - *origin = currentPos + (dir * (dist / length)); + *origin = currentPos + ( dir * ( dist / length ) ); return pcurrent; } else @@ -309,7 +308,7 @@ CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) 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. + if( !ValidPath( pcurrent->GetPrevious(), move ) ) // If there is no previous node, or it's disabled, return now. return NULL; pcurrent = pcurrent->GetPrevious(); @@ -320,23 +319,23 @@ CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) } else { - while ( dist > 0 ) + while( dist > 0 ) { - if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now. + if( !ValidPath( pcurrent->GetNext(), move ) ) // If there is no next node, or it's disabled, return now. { - if ( !move ) + 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( !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 + if( length > dist ) // enough left in this path to move { *origin = currentPos + (dir * (dist / length)); return pcurrent; @@ -354,15 +353,14 @@ CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) return pcurrent; } - -// Assumes this is ALWAYS enabled -CPathTrack *CPathTrack :: Nearest( Vector origin ) -{ - int deadCount; - float minDist, dist; - Vector delta; - CPathTrack *ppath, *pnearest; +// 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; @@ -372,18 +370,18 @@ CPathTrack *CPathTrack :: Nearest( Vector origin ) // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) deadCount = 0; - while ( ppath && ppath != this ) + while( ppath && ppath != this ) { deadCount++; - if ( deadCount > 9999 ) + if( deadCount > 9999 ) { - ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) ); + 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 ) + if( dist < minDist ) { minDist = dist; pnearest = ppath; @@ -394,21 +392,20 @@ CPathTrack *CPathTrack :: Nearest( Vector origin ) } CPathTrack *CPathTrack::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "path_track" ) ) - return (CPathTrack *)GET_PRIVATE(pent); +{ + if( FClassnameIs( pent, "path_track" ) ) + return (CPathTrack *)GET_PRIVATE( pent ); return NULL; } // DEBUGGING CODE #if PATH_SPARKLE_DEBUG -void CPathTrack :: Sparkle( void ) +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); + 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); + UTIL_ParticleEffect( pev->origin, Vector( 0, 0, 100 ), 84, 10 ); } #endif diff --git a/dlls/plane.cpp b/dlls/plane.cpp index 689a0c29..44a8b275 100644 --- a/dlls/plane.cpp +++ b/dlls/plane.cpp @@ -19,7 +19,7 @@ //========================================================= // Plane //========================================================= -CPlane :: CPlane ( void ) +CPlane::CPlane( void ) { m_fInitialized = FALSE; } @@ -28,10 +28,10 @@ CPlane :: CPlane ( void ) // InitializePlane - Takes a normal for the plane and a // point on the plane and //========================================================= -void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ) +void CPlane::InitializePlane( const Vector &vecNormal, const Vector &vecPoint ) { m_vecNormal = vecNormal; - m_flDist = DotProduct ( m_vecNormal, vecPoint ); + m_flDist = DotProduct( m_vecNormal, vecPoint ); m_fInitialized = TRUE; } @@ -39,18 +39,18 @@ void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint // PointInFront - determines whether the given vector is // in front of the plane. //========================================================= -BOOL CPlane :: PointInFront ( const Vector &vecPoint ) +BOOL CPlane::PointInFront( const Vector &vecPoint ) { float flFace; - if ( !m_fInitialized ) + if( !m_fInitialized ) { return FALSE; } - flFace = DotProduct ( m_vecNormal, vecPoint ) - m_flDist; + flFace = DotProduct( m_vecNormal, vecPoint ) - m_flDist; - if ( flFace >= 0 ) + if( flFace >= 0 ) { return TRUE; } diff --git a/dlls/plane.h b/dlls/plane.h index af70f1cc..35a17611 100644 --- a/dlls/plane.h +++ b/dlls/plane.h @@ -1,7 +1,7 @@ /*** * * 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. @@ -18,10 +18,10 @@ //========================================================= // Plane //========================================================= -class CPlane +class CPlane { public: - CPlane ( void ); + CPlane( void ); //========================================================= // InitializePlane - Takes a normal for the plane and a @@ -33,11 +33,10 @@ public: // PointInFront - determines whether the given vector is // in front of the plane. //========================================================= - BOOL PointInFront ( const Vector &vecPoint ); + BOOL PointInFront( const Vector &vecPoint ); - Vector m_vecNormal; - float m_flDist; - BOOL m_fInitialized; + Vector m_vecNormal; + float m_flDist; + BOOL m_fInitialized; }; - #endif // PLANE_H diff --git a/dlls/player.cpp b/dlls/player.cpp index 866898c8..708096b2 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -38,29 +38,29 @@ // #define DUCKFIX -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_fDrawLines; +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; +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 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; +extern CGraph WorldGraph; -#define TRAIN_ACTIVE 0x80 +#define TRAIN_ACTIVE 0x80 #define TRAIN_NEW 0xc0 #define TRAIN_OFF 0x00 -#define TRAIN_NEUTRAL 0x01 +#define TRAIN_NEUTRAL 0x01 #define TRAIN_SLOW 0x02 -#define TRAIN_MEDIUM 0x03 -#define TRAIN_FAST 0x04 +#define TRAIN_MEDIUM 0x03 +#define TRAIN_FAST 0x04 #define TRAIN_BACK 0x05 #define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes @@ -182,32 +182,32 @@ int gmsgGeigerRange = 0; int gmsgTeamNames = 0; int gmsgStatusText = 0; -int gmsgStatusValue = 0; +int gmsgStatusValue = 0; void LinkUserMessages( void ) { // Already taken care of? - if ( gmsgSelAmmo ) + 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); + 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); + gmsgTrain = REG_USER_MSG( "Train", 1 ); gmsgHudText = REG_USER_MSG( "HudText", -1 ); 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); + 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 @@ -221,41 +221,38 @@ void LinkUserMessages( void ) 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); + 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); + gmsgStatusText = REG_USER_MSG( "StatusText", -1 ); + gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 ); } LINK_ENTITY_TO_CLASS( player, CBasePlayer ) -void CBasePlayer :: Pain( void ) +void CBasePlayer::Pain( void ) { - float flRndSound;//sound randomizer + float flRndSound;//sound randomizer - flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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); + 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); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM ); } -/* - * - */ -Vector VecVelocityForDamage(float flDamage) +Vector VecVelocityForDamage( float flDamage ) { - Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); + Vector vec( RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( 200, 300 ) ); - if (flDamage > -50) + if( flDamage > -50 ) vec = vec * 0.7; - else if (flDamage > -200) + else if( flDamage > -200 ) vec = vec * 2; else vec = vec * 10; @@ -263,48 +260,47 @@ Vector VecVelocityForDamage(float flDamage) return vec; } -#if 0 /* -static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) +#if 0 +static void ThrowGib( entvars_t *pev, char *szGibModel, float flDamage ) { edict_t *pentNew = CREATE_ENTITY(); - entvars_t *pevNew = VARS(pentNew); + entvars_t *pevNew = VARS( pentNew ); pevNew->origin = pev->origin; - SET_MODEL(ENT(pevNew), szGibModel); - UTIL_SetSize(pevNew, g_vecZero, g_vecZero); + 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; + 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) +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); + 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); + ClearBits( pev->flags, FL_ONGROUND ); } -*/ #endif -int TrainSpeed(int iSpeed, int iMax) +int TrainSpeed( int iSpeed, int iMax ) { float fSpeed, fMax; int iRet = 0; @@ -314,13 +310,13 @@ int TrainSpeed(int iSpeed, int iMax) fSpeed = fSpeed/fMax; - if (iSpeed < 0) + if( iSpeed < 0 ) iRet = TRAIN_BACK; - else if (iSpeed == 0) + else if( iSpeed == 0 ) iRet = TRAIN_NEUTRAL; - else if (fSpeed < 0.33) + else if( fSpeed < 0.33 ) iRet = TRAIN_SLOW; - else if (fSpeed < 0.66) + else if( fSpeed < 0.66 ) iRet = TRAIN_MEDIUM; else iRet = TRAIN_FAST; @@ -328,46 +324,45 @@ int TrainSpeed(int iSpeed, int iMax) return iRet; } -void CBasePlayer :: DeathSound( void ) +void CBasePlayer::DeathSound( void ) { // water death sounds /* - if (pev->waterlevel == 3) + if( pev->waterlevel == 3 ) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); + 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)) + switch( RANDOM_LONG( 1, 5 ) ) { case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); + 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); + 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); + 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"); + EMIT_GROUPNAME_SUIT( ENT( pev ), "HEV_DEAD" ); } // override takehealth // bitsDamageType indicates type of damage healed. - -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) +int CBasePlayer::TakeHealth( float flHealth, int bitsDamageType ) { - return CBaseMonster :: TakeHealth (flHealth, bitsDamageType); + return CBaseMonster::TakeHealth( flHealth, bitsDamageType ); } -Vector CBasePlayer :: GetGunPosition( ) +Vector CBasePlayer::GetGunPosition() { - //UTIL_MakeVectors(pev->v_angle); + //UTIL_MakeVectors( pev->v_angle ); //m_HackedGunPos = pev->view_ofs; Vector origin; @@ -379,13 +374,13 @@ Vector CBasePlayer :: GetGunPosition( ) //========================================================= // TraceAttack //========================================================= -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) +void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if ( pev->takedamage ) + if( pev->takedamage ) { m_LastHitGroup = ptr->iHitgroup; - switch ( ptr->iHitgroup ) + switch( ptr->iHitgroup ) { case HITGROUP_GENERIC: break; @@ -410,7 +405,7 @@ void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector break; } - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. + SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } @@ -423,10 +418,10 @@ void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector 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 +#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 ) +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; @@ -442,21 +437,20 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flBonus = ARMOR_BONUS; flRatio = ARMOR_RATIO; - if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) + if( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) { // blasts damage armor more. flBonus *= 2; } // Already dead - if ( !IsAlive() ) + if( !IsAlive() ) return 0; + // go take the damage first + CBaseEntity *pAttacker = CBaseEntity::Instance( pevAttacker ); - - CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); - - if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) + if( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) { // Refuse the damage return 0; @@ -466,53 +460,52 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, m_lastDamageAmount = flDamage; // Armor. - if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! + 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; + flArmor = ( flDamage - flNew ) * flBonus; // Does this use more armor than we have? - if (flArmor > pev->armorvalue) + if( flArmor > pev->armorvalue ) { flArmor = pev->armorvalue; - flArmor *= (1/flBonus); + 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); + 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)) + 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_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); + 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 @@ -521,7 +514,7 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, // UNDONE: still need to record damage and heal messages for the following types - // DMG_BURN + // DMG_BURN // DMG_FREEZE // DMG_BLAST // DMG_SHOCK @@ -529,86 +522,86 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, 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) + while( fTookDamage && ( !ftrivial || ( bitsDamage & DMG_TIMEBASED ) ) && ffound && bitsDamage ) { ffound = FALSE; - if (bitsDamage & DMG_CLUB) + if( bitsDamage & DMG_CLUB ) { - if (fmajor) - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture + if( fmajor ) + SetSuitUpdate( "!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC ); // minor fracture bitsDamage &= ~DMG_CLUB; ffound = TRUE; } - if (bitsDamage & (DMG_FALL | DMG_CRUSH)) + if( bitsDamage & ( DMG_FALL | DMG_CRUSH ) ) { - if (fmajor) - SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture + if( fmajor ) + SetSuitUpdate( "!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC ); // major fracture else - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture + SetSuitUpdate( "!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC ); // minor fracture - bitsDamage &= ~(DMG_FALL | DMG_CRUSH); + bitsDamage &= ~( DMG_FALL | DMG_CRUSH ); ffound = TRUE; } - if (bitsDamage & DMG_BULLET) + if( bitsDamage & DMG_BULLET ) { - if (m_lastDamageAmount > 5) - SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected + 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 + // SetSuitUpdate( "!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC ); // minor laceration bitsDamage &= ~DMG_BULLET; ffound = TRUE; } - if (bitsDamage & DMG_SLASH) + if( bitsDamage & DMG_SLASH ) { - if (fmajor) - SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration + if( fmajor ) + SetSuitUpdate( "!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC ); // major laceration else - SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration + SetSuitUpdate( "!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC ); // minor laceration bitsDamage &= ~DMG_SLASH; ffound = TRUE; } - if (bitsDamage & DMG_SONIC) + if( bitsDamage & DMG_SONIC ) { - if (fmajor) - SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding + if( fmajor ) + SetSuitUpdate( "!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN ); // internal bleeding bitsDamage &= ~DMG_SONIC; ffound = TRUE; } - if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) + if( bitsDamage & ( DMG_POISON | DMG_PARALYZE ) ) { - SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected - 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) + if( bitsDamage & DMG_ACID ) { - SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected + SetSuitUpdate( "!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN ); // hazardous chemicals detected bitsDamage &= ~DMG_ACID; ffound = TRUE; } - if (bitsDamage & DMG_NERVEGAS) + if( bitsDamage & DMG_NERVEGAS ) { - SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected + SetSuitUpdate( "!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN ); // biohazard detected bitsDamage &= ~DMG_NERVEGAS; ffound = TRUE; } - if (bitsDamage & DMG_RADIATION) + if( bitsDamage & DMG_RADIATION ) { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected + SetSuitUpdate( "!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN ); // radiation detected bitsDamage &= ~DMG_RADIATION; ffound = TRUE; } - if (bitsDamage & DMG_SHOCK) + if( bitsDamage & DMG_SHOCK ) { bitsDamage &= ~DMG_SHOCK; ffound = TRUE; @@ -617,40 +610,40 @@ int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, pev->punchangle.x = -2; - if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) + 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 + 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 + SetSuitUpdate( "!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN ); // morphine shot } - if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) + 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 + 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( !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( fTookDamage && ( bitsDamageType & DMG_TIMEBASED ) && flHealthPrev < 75 ) + { + if( flHealthPrev < 50 ) { - 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 + 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; } @@ -667,19 +660,19 @@ 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]; + 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, NULL, sizeof(rgpPackWeapons) ); - memset(iPackAmmo, -1, sizeof(iPackAmmo) ); + memset( rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); + memset( iPackAmmo, -1, sizeof(iPackAmmo) ); - // get the game rules + // 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 ) + 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 ); @@ -687,26 +680,26 @@ void CBasePlayer::PackDeadPlayerItems( void ) } // go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[ i ] ) + if( m_rgpPlayerItems[i] ) { // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[i]; - while ( pPlayerItem ) + while( pPlayerItem ) { switch( iWeaponRules ) { case GR_PLR_DROP_GUN_ACTIVE: - if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) + if( m_pActiveItem && pPlayerItem == m_pActiveItem ) { // this is the active item. Pack it. - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + rgpPackWeapons[iPW++] = (CBasePlayerWeapon *)pPlayerItem; } break; case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + rgpPackWeapons[iPW++] = (CBasePlayerWeapon *)pPlayerItem; break; default: break; @@ -718,28 +711,28 @@ void CBasePlayer::PackDeadPlayerItems( void ) } // now go through ammo and make a list of which types to pack. - if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) + if( iAmmoRules != GR_PLR_DROP_AMMO_NO ) { - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + for( i = 0; i < MAX_AMMO_SLOTS; i++ ) { - if ( m_rgAmmo[ i ] > 0 ) + if( m_rgAmmo[i] > 0 ) { // player has some ammo of this type. - switch ( iAmmoRules ) + switch( iAmmoRules ) { case GR_PLR_DROP_AMMO_ALL: - iPackAmmo[ iPA++ ] = i; + iPackAmmo[iPA++] = i; break; case GR_PLR_DROP_AMMO_ACTIVE: - if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) + if( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) { // this is the primary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; + iPackAmmo[iPA++] = i; } - else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) + else if( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) { // this is the secondary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; + iPackAmmo[iPA++] = i; } break; default: @@ -762,17 +755,17 @@ void CBasePlayer::PackDeadPlayerItems( void ) iPW = 0; // pack the ammo - while ( iPackAmmo[ iPA ] != -1 ) + while( iPackAmmo[iPA] != -1 ) { - pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName ), m_rgAmmo[ iPackAmmo[ iPA ] ] ); + 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 ] ) + while( rgpPackWeapons[iPW] ) { // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); + pWeaponBox->PackWeapon( rgpPackWeapons[iPW] ); iPW++; } @@ -784,10 +777,10 @@ void CBasePlayer::PackDeadPlayerItems( void ) void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { - if (m_pActiveItem) + if( m_pActiveItem ) { - ResetAutoaim( ); - m_pActiveItem->Holster( ); + ResetAutoaim(); + m_pActiveItem->Holster(); m_pActiveItem = NULL; } @@ -795,37 +788,37 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) int i; CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) + while( m_pActiveItem ) { pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->Drop( ); + m_pActiveItem->Drop(); m_pActiveItem = pPendingItem; } m_rgpPlayerItems[i] = NULL; } m_pActiveItem = NULL; - pev->viewmodel = 0; - pev->weaponmodel = 0; + pev->viewmodel = 0; + pev->weaponmodel = 0; - if ( removeSuit ) + if( removeSuit ) pev->weapons = 0; else pev->weapons &= ~WEAPON_ALLWEAPONS; - for ( i = 0; i < MAX_AMMO_SLOTS;i++) + 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); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); MESSAGE_END(); } @@ -842,12 +835,12 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) CSound *pSound; // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); + if( m_pActiveItem ) + m_pActiveItem->Holster(); g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - if ( m_pTank != NULL ) + if( m_pTank != NULL ) { m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; @@ -856,7 +849,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) // 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 ) + if( pSound ) { pSound->Reset(); } @@ -868,14 +861,14 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) pev->modelindex = g_ulModelIndexPlayer; // don't use eyes - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; + 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); + 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); + SetSuitUpdate( NULL, FALSE, 0 ); // send "health" update message to zero m_iClientHealth = 0; @@ -885,24 +878,24 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) // Tell Ammo Hud that the player is dead MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0XFF); - WRITE_BYTE(0xFF); + 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); + 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 ); + // UTIL_ScreenFade( edict(), Vector( 128, 0, 0 ), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); - if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) + if( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) { - pev->solid = SOLID_NOT; + pev->solid = SOLID_NOT; GibMonster(); // This clears pev->model pev->effects |= EF_NODRAW; return; @@ -926,13 +919,13 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) speed = pev->velocity.Length2D(); - if (pev->flags & FL_FROZEN) + if( pev->flags & FL_FROZEN ) { speed = 0; playerAnim = PLAYER_IDLE; } - switch (playerAnim) + switch( playerAnim ) { case PLAYER_JUMP: m_IdealActivity = ACT_HOP; @@ -942,9 +935,9 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) break; case PLAYER_DIE: m_IdealActivity = ACT_DIESIMPLE; - m_IdealActivity = GetDeathActivity( ); + m_IdealActivity = GetDeathActivity(); break; - case PLAYER_ATTACK1: + case PLAYER_ATTACK1: switch( m_Activity ) { case ACT_HOVER: @@ -961,13 +954,13 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) break; case PLAYER_IDLE: case PLAYER_WALK: - if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping + 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 ) + else if( pev->waterlevel > 1 ) { - if ( speed == 0 ) + if( speed == 0 ) m_IdealActivity = ACT_HOVER; else m_IdealActivity = ACT_SWIM; @@ -979,7 +972,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) break; } - switch (m_IdealActivity) + switch( m_IdealActivity ) { case ACT_HOVER: case ACT_LEAP: @@ -987,56 +980,56 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) case ACT_HOP: case ACT_DIESIMPLE: default: - if ( m_Activity == m_IdealActivity) + if( m_Activity == m_IdealActivity ) return; m_Activity = m_IdealActivity; animDesired = LookupActivity( m_Activity ); // Already using the desired animation? - if (pev->sequence == animDesired) + if( pev->sequence == animDesired ) return; pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); + pev->sequence = animDesired; + pev->frame = 0; + ResetSequenceInfo(); return; case ACT_RANGE_ATTACK1: - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching + 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) + if( animDesired == -1 ) animDesired = 0; - if ( pev->sequence != animDesired || !m_fSequenceLoops ) + if( pev->sequence != animDesired || !m_fSequenceLoops ) { pev->frame = 0; } - if (!m_fSequenceLoops) + if( !m_fSequenceLoops ) { pev->effects |= EF_NOINTERP; } m_Activity = m_IdealActivity; - pev->sequence = animDesired; - ResetSequenceInfo( ); + pev->sequence = animDesired; + ResetSequenceInfo(); break; case ACT_WALK: - if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished) + if( m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished ) { - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching + 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) + if( animDesired == -1 ) animDesired = 0; m_Activity = ACT_WALK; } @@ -1046,41 +1039,41 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) } } - if ( FBitSet( pev->flags, FL_DUCKING ) ) + if( FBitSet( pev->flags, FL_DUCKING ) ) { - if ( speed == 0) + if( speed == 0 ) { - pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE ); - // pev->gaitsequence = LookupActivity( ACT_CROUCH ); + pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE ); + // pev->gaitsequence = LookupActivity( ACT_CROUCH ); } else { - pev->gaitsequence = LookupActivity( ACT_CROUCH ); + pev->gaitsequence = LookupActivity( ACT_CROUCH ); } } - else if ( speed > 220 ) + else if( speed > 220 ) { - pev->gaitsequence = LookupActivity( ACT_RUN ); + pev->gaitsequence = LookupActivity( ACT_RUN ); } - else if (speed > 0) + else if( speed > 0 ) { - pev->gaitsequence = LookupActivity( ACT_WALK ); + pev->gaitsequence = LookupActivity( ACT_WALK ); } else { - // pev->gaitsequence = LookupActivity( ACT_WALK ); - pev->gaitsequence = LookupSequence( "deep_idle" ); + // pev->gaitsequence = LookupActivity( ACT_WALK ); + pev->gaitsequence = LookupSequence( "deep_idle" ); } // Already using the desired animation? - if (pev->sequence == animDesired) + 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( ); + pev->sequence = animDesired; + pev->frame = 0; + ResetSequenceInfo(); } /* @@ -1102,7 +1095,6 @@ void CBasePlayer::TabulateAmmo() ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) ); } - /* =========== WaterMove @@ -1114,10 +1106,10 @@ void CBasePlayer::WaterMove() { int air; - if (pev->movetype == MOVETYPE_NOCLIP) + if( pev->movetype == MOVETYPE_NOCLIP ) return; - if (pev->health < 0) + if( pev->health < 0 ) return; // waterlevel 0 - not in water @@ -1125,21 +1117,21 @@ void CBasePlayer::WaterMove() // waterlevel 2 - waist in water // waterlevel 3 - head in water - if (pev->waterlevel != 3) + 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); + 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) + if( m_idrowndmg > m_idrownrestored ) { // set drowning damage bit. hack - dmg_drownrecover actually // makes the time based damage code 'give back' health over time. @@ -1159,15 +1151,15 @@ void CBasePlayer::WaterMove() m_bitsDamageType &= ~DMG_DROWNRECOVER; m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - if (pev->air_finished < gpGlobals->time) // drown! + if( pev->air_finished < gpGlobals->time ) // drown! { - if (pev->pain_finished < gpGlobals->time) + if( pev->pain_finished < gpGlobals->time ) { // take drowning damage pev->dmg += 1; - if (pev->dmg > 5) + if( pev->dmg > 5 ) pev->dmg = 5; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); + TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), pev->dmg, DMG_DROWN ); pev->pain_finished = gpGlobals->time + 1; // track drowning damage, give it back when @@ -1182,42 +1174,50 @@ void CBasePlayer::WaterMove() } } - if (!pev->waterlevel) + if( !pev->waterlevel ) { - if (FBitSet(pev->flags, FL_INWATER)) - { - ClearBits(pev->flags, FL_INWATER); + 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) + 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; + 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->watertype == CONTENT_LAVA ) // do damage { - if (pev->dmgtime < gpGlobals->time) - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); + if( pev->dmgtime < gpGlobals->time ) + TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 10 * pev->waterlevel, DMG_BURN ); } - else if (pev->watertype == CONTENT_SLIME) // do damage + else if( pev->watertype == CONTENT_SLIME ) // do damage { pev->dmgtime = gpGlobals->time + 1; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); + TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 4 * pev->waterlevel, DMG_ACID ); } - if (!FBitSet(pev->flags, FL_INWATER)) + if( !FBitSet( pev->flags, FL_INWATER ) ) { - SetBits(pev->flags, FL_INWATER); + SetBits( pev->flags, FL_INWATER ); pev->dmgtime = 0; } } @@ -1228,20 +1228,20 @@ BOOL CBasePlayer::IsOnLadder( void ) return ( pev->movetype == MOVETYPE_FLY ); } -void CBasePlayer::PlayerDeathThink(void) +void CBasePlayer::PlayerDeathThink( void ) { float flForward; - if (FBitSet(pev->flags, FL_ONGROUND)) + if( FBitSet( pev->flags, FL_ONGROUND ) ) { flForward = pev->velocity.Length() - 20; - if (flForward <= 0) + if( flForward <= 0 ) pev->velocity = g_vecZero; else pev->velocity = flForward * pev->velocity.Normalize(); } - if ( HasWeapons() ) + 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 @@ -1250,21 +1250,21 @@ void CBasePlayer::PlayerDeathThink(void) PackDeadPlayerItems(); } - if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) + if( pev->modelindex && ( !m_fSequenceFinished ) && ( pev->deadflag == DEAD_DYING ) ) { - StudioFrameAdvance( ); + 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 + 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) ) + if( pev->movetype != MOVETYPE_NONE && FBitSet( pev->flags, FL_ONGROUND ) ) pev->movetype = MOVETYPE_NONE; - if (pev->deadflag == DEAD_DYING) + if( pev->deadflag == DEAD_DYING ) pev->deadflag = DEAD_DEAD; StopAnimation(); @@ -1272,15 +1272,15 @@ void CBasePlayer::PlayerDeathThink(void) pev->effects |= EF_NOINTERP; pev->framerate = 0.0; - BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); + BOOL fAnyButtonDown = ( pev->button & ~IN_SCORE ); // wait for all buttons released - if (pev->deadflag == DEAD_DEAD) + if( pev->deadflag == DEAD_DEAD ) { - if (fAnyButtonDown) + if( fAnyButtonDown ) return; - if ( g_pGameRules->FPlayerCanRespawn( this ) ) + if( g_pGameRules->FPlayerCanRespawn( this ) ) { m_fDeadTime = gpGlobals->time; pev->deadflag = DEAD_RESPAWNABLE; @@ -1292,23 +1292,22 @@ void CBasePlayer::PlayerDeathThink(void) // 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) ) + if( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > ( m_fDeadTime + 6 ) ) && !( m_afPhysicsFlags & PFLAG_OBSERVER ) ) { // go to dead camera. StartDeathCam(); } // 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))) ) + 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"); + //ALERT( at_console, "Respawn\n" ); - respawn(pev, !(m_afPhysicsFlags & PFLAG_OBSERVER) );// don't copy a corpse if we're in deathcam. + respawn( pev, !( m_afPhysicsFlags & PFLAG_OBSERVER ) );// don't copy a corpse if we're in deathcam. pev->nextthink = -1; } @@ -1321,24 +1320,24 @@ void CBasePlayer::StartDeathCam( void ) edict_t *pSpot, *pNewSpot; int iRand; - if ( pev->view_ofs == g_vecZero ) + if( pev->view_ofs == g_vecZero ) { // don't accept subsequent attempts to StartDeathCam() return; } - pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); + pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission" ); - if ( !FNullEnt( pSpot ) ) + if( !FNullEnt( pSpot ) ) { // at least one intermission spot in the world. iRand = RANDOM_LONG( 0, 3 ); - while ( iRand > 0 ) + while( iRand > 0 ) { - pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); + pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission" ); - if ( pNewSpot ) + if( pNewSpot ) { pSpot = pNewSpot; } @@ -1355,7 +1354,7 @@ void CBasePlayer::StartDeathCam( void ) TraceResult tr; CopyToBodyQue( pev ); UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); + StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); return; } } @@ -1379,16 +1378,16 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) // #define PLAYER_SEARCH_RADIUS (float)64 -void CBasePlayer::PlayerUse ( void ) +void CBasePlayer::PlayerUse( void ) { // Was use pressed or released? - if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) + if( !( ( pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE ) ) return; // Hit Use on a train? - if ( m_afButtonPressed & IN_USE ) + if( m_afButtonPressed & IN_USE ) { - if ( m_pTank != NULL ) + if( m_pTank != NULL ) { // Stop controlling the tank // TODO: Send HUD Update @@ -1398,7 +1397,7 @@ void CBasePlayer::PlayerUse ( void ) } else { - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + if( m_afPhysicsFlags & PFLAG_ONTRAIN ) { m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW|TRAIN_OFF; @@ -1408,12 +1407,12 @@ void CBasePlayer::PlayerUse ( void ) { // 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) ) + 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(pTrain->pev->speed, pTrain->pev->impulse); + m_iTrain = TrainSpeed( pTrain->pev->speed, pTrain->pev->impulse ); m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM ); return; } } @@ -1422,28 +1421,27 @@ void CBasePlayer::PlayerUse ( void ) CBaseEntity *pObject = NULL; CBaseEntity *pClosest = NULL; - Vector vecLOS; + Vector vecLOS; float flMaxDot = VIEW_FIELD_NARROW; float flDot; - UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing + UTIL_MakeVectors( pev->v_angle );// so we know which way we are facing - while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) + while( ( pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS ) ) != NULL ) { - - if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE)) + 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)); + 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 ) + flDot = DotProduct( vecLOS , gpGlobals->v_forward ); + if( flDot > flMaxDot ) { // only if the item is in front of the user pClosest = pObject; @@ -1456,46 +1454,46 @@ void CBasePlayer::PlayerUse ( void ) pObject = pClosest; // Found an object - if (pObject ) + 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( 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( ( ( pev->button & IN_USE ) && ( caps & FCAP_CONTINUOUS_USE ) ) || + ( ( m_afButtonPressed & IN_USE ) && ( caps & ( FCAP_IMPULSE_USE | FCAP_ONOFF_USE ) ) ) ) { - if ( caps & FCAP_CONTINUOUS_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 + 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); + 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; + 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)) + if( FBitSet( pev->flags, FL_WATERJUMP ) ) return; - if (pev->waterlevel >= 2) + if( pev->waterlevel >= 2 ) { return; } @@ -1503,23 +1501,23 @@ void CBasePlayer::Jump() // 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 ) ) + if( !FBitSet( m_afButtonPressed, IN_JUMP ) ) return; // don't pogo stick - if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) + if( !( pev->flags & FL_ONGROUND ) || !pev->groundentity ) { return; } // many features in this function use v_forward, so makevectors now. - UTIL_MakeVectors (pev->angles); + UTIL_MakeVectors( pev->angles ); - // ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk + // ClearBits( pev->flags, FL_ONGROUND ); // don't stairwalk SetAnimation( PLAYER_JUMP ); - if ( m_fLongJump && - (pev->button & IN_DUCK) && + if( m_fLongJump && + ( pev->button & IN_DUCK ) && ( pev->flDuckTime > 0 ) && pev->velocity.Length() > 50 ) { @@ -1527,8 +1525,8 @@ void CBasePlayer::Jump() } // 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) ) + entvars_t *pevGround = VARS( pev->groundentity ); + if( pevGround && ( pevGround->flags & FL_CONVEYOR ) ) { pev->velocity = pev->velocity + pev->basevelocity; } @@ -1542,21 +1540,21 @@ 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++ ) + 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 ++; + if( trace.fStartSolid ) + pPlayer->v.origin.z++; else break; } } -void CBasePlayer::Duck( ) +void CBasePlayer::Duck() { - if (pev->button & IN_DUCK) + if( pev->button & IN_DUCK ) { - if ( m_IdealActivity != ACT_LEAP ) + if( m_IdealActivity != ACT_LEAP ) { SetAnimation( PLAYER_WALK ); } @@ -1566,7 +1564,7 @@ void CBasePlayer::Duck( ) // // ID's player as such. // -int CBasePlayer::Classify ( void ) +int CBasePlayer::Classify( void ) { return CLASS_PLAYER; } @@ -1574,14 +1572,14 @@ int CBasePlayer::Classify ( void ) void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { // Positive score always adds - if ( score < 0 ) + if( score < 0 ) { - if ( !bAllowNegativeScore ) + if( !bAllowNegativeScore ) { - if ( pev->frags < 0 ) // Can't go more negative + if( pev->frags < 0 ) // Can't go more negative return; - if ( -score > pev->frags ) // Will this go negative? + if( -score > pev->frags ) // Will this go negative? { score = -pev->frags; // Sum will be 0 } @@ -1591,7 +1589,7 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) pev->frags += score; MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(edict()) ); + WRITE_BYTE( ENTINDEX( edict() ) ); WRITE_SHORT( pev->frags ); WRITE_SHORT( m_iDeaths ); WRITE_SHORT( 0 ); @@ -1603,13 +1601,13 @@ void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { int index = entindex(); - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer && i != index ) + if( pPlayer && i != index ) { - if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) + if( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) { pPlayer->AddPoints( score, bAllowNegativeScore ); } @@ -1626,8 +1624,8 @@ void CBasePlayer::InitStatusBar() void CBasePlayer::UpdateStatusBar() { - int newSBarState[ SBAR_END ]; - char sbuf0[ SBAR_STRING_SIZE ]; + int newSBarState[SBAR_END]; + char sbuf0[SBAR_STRING_SIZE]; char sbuf1[ SBAR_STRING_SIZE ]; memset( newSBarState, 0, sizeof(newSBarState) ); @@ -1638,42 +1636,42 @@ void CBasePlayer::UpdateStatusBar() 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); + Vector vecEnd = vecSrc + ( gpGlobals->v_forward * MAX_ID_RANGE ); + UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr ); - if (tr.flFraction != 1.0) + if( tr.flFraction != 1.0 ) { - if ( !FNullEnt( tr.pHit ) ) + if( !FNullEnt( tr.pHit ) ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if (pEntity->Classify() == CLASS_PLAYER ) + if( pEntity->Classify() == CLASS_PLAYER ) { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); + 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 ) + if( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) { - newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health); - newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. + newSBarState[SBAR_ID_TARGETHEALTH] = 100 * ( pEntity->pev->health / pEntity->pev->max_health ); + newSBarState[SBAR_ID_TARGETARMOR] = 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 ) + 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 ]; + 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 ) ) + if( strcmp( sbuf0, m_SbarString0 ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev ); WRITE_BYTE( 0 ); @@ -1686,7 +1684,7 @@ void CBasePlayer::UpdateStatusBar() bForceResend = TRUE; } - if ( strcmp( sbuf1, m_SbarString1 ) ) + if( strcmp( sbuf1, m_SbarString1 ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev ); WRITE_BYTE( 1 ); @@ -1700,9 +1698,9 @@ void CBasePlayer::UpdateStatusBar() } // Check values and send if they don't match - for (int i = 1; i < SBAR_END; i++) + for( int i = 1; i < SBAR_END; i++ ) { - if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) + if( newSBarState[i] != m_izSBarState[i] || bForceResend ) { MESSAGE_BEGIN( MSG_ONE, gmsgStatusValue, NULL, pev ); WRITE_BYTE( i ); @@ -1714,32 +1712,32 @@ void CBasePlayer::UpdateStatusBar() } } -#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing +#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) +void CBasePlayer::PreThink( void ) { - int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame + 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" + m_afButtonReleased = buttonsChanged & ( ~pev->button ); // The ones not down are "released" g_pGameRules->PlayerThink( this ); - if ( g_fGameOver ) + if( g_fGameOver ) return; // intermission or finale - UTIL_MakeVectors(pev->v_angle); // is this still used? + UTIL_MakeVectors( pev->v_angle ); // is this still used? - ItemPreFrame( ); + ItemPreFrame(); WaterMove(); - if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) + if( g_pGameRules && g_pGameRules->FAllowFlashlight() ) m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; else m_iHideHUD |= HIDEHUD_FLASHLIGHT; @@ -1751,7 +1749,7 @@ void CBasePlayer::PreThink(void) CheckSuitUpdate(); - if (pev->deadflag >= DEAD_DYING) + if( pev->deadflag >= DEAD_DYING ) { PlayerDeathThink(); return; @@ -1759,28 +1757,28 @@ void CBasePlayer::PreThink(void) // So the correct flags get sent to client asap. // - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + if( m_afPhysicsFlags & PFLAG_ONTRAIN ) pev->flags |= FL_ONTRAIN; else pev->flags &= ~FL_ONTRAIN; // Train speed control - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) + if( m_afPhysicsFlags & PFLAG_ONTRAIN ) { CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); float vel; - if ( !pTrain ) + 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 ); + 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 ) + if( trainTrace.flFraction != 1.0 && trainTrace.pHit ) pTrain = CBaseEntity::Instance( trainTrace.pHit ); - if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) + if( !pTrain || !( pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) || !pTrain->OnControls( pev ) ) { //ALERT( at_error, "In train mode with no train!\n" ); m_afPhysicsFlags &= ~PFLAG_ONTRAIN; @@ -1788,37 +1786,37 @@ void CBasePlayer::PreThink(void) return; } } - else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) + 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; + m_iTrain = TRAIN_NEW | TRAIN_OFF; return; } pev->velocity = g_vecZero; vel = 0; - if ( m_afButtonPressed & IN_FORWARD ) + if( m_afButtonPressed & IN_FORWARD ) { vel = 1; pTrain->Use( this, this, USE_SET, (float)vel ); } - else if ( m_afButtonPressed & IN_BACK ) + else if( m_afButtonPressed & IN_BACK ) { vel = -1; pTrain->Use( this, this, USE_SET, (float)vel ); } - if (vel) + if( vel ) { - m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse); + m_iTrain = TrainSpeed( 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( pev->button & IN_JUMP ) { // If on a ladder, jump off the ladder // else Jump @@ -1826,20 +1824,20 @@ void CBasePlayer::PreThink(void) } // 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) ) + if( ( pev->button & IN_DUCK ) || FBitSet( pev->flags,FL_DUCKING ) || ( m_afPhysicsFlags & PFLAG_DUCKING ) ) Duck(); - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) + if( !FBitSet( pev->flags, FL_ONGROUND ) ) { m_flFallVelocity = -pev->velocity.z; } - // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? + // StudioFrameAdvance();//!!!HACKHACK!!! Can't be hit by traceline when not animating? // Clear out ladder pointer m_hEnemy = NULL; - if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) + if( m_afPhysicsFlags & PFLAG_ONBARNACLE ) { pev->velocity = g_vecZero; } @@ -1849,10 +1847,10 @@ void CBasePlayer::PreThink(void) #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_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_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 @@ -1896,28 +1894,26 @@ void CBasePlayer::PreThink(void) // 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_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_DURATION 16 //#define NERVEGAS_DAMAGE 5.0 //#define POISON_DURATION 25 -//#define POISON_DAMAGE 2.0 +//#define POISON_DAMAGE 2.0 -//#define RADIATION_DURATION 50 -//#define RADIATION_DAMAGE 1.0 +//#define RADIATION_DURATION 50 +//#define RADIATION_DAMAGE 1.0 -//#define ACID_DURATION 10 +//#define ACID_DURATION 10 //#define ACID_DAMAGE 5.0 -//#define SLOWBURN_DURATION 2 +//#define SLOWBURN_DURATION 2 //#define SLOWBURN_DAMAGE 1.0 -//#define SLOWFREEZE_DURATION 1.0 -//#define SLOWFREEZE_DAMAGE 3.0 - -/* */ +//#define SLOWFREEZE_DURATION 1.0 +//#define SLOWFREEZE_DAMAGE 3.0 void CBasePlayer::CheckTimeBasedDamage() { @@ -1926,87 +1922,87 @@ void CBasePlayer::CheckTimeBasedDamage() static float gtbdPrev = 0.0; - if (!(m_bitsDamageType & DMG_TIMEBASED)) + if( !( m_bitsDamageType & DMG_TIMEBASED ) ) return; // only check for time based damage approx. every 2 seconds - if ( fabs( gpGlobals->time - m_tbdPrev ) < 2.0 ) + if( fabs( gpGlobals->time - m_tbdPrev ) < 2.0 ) return; m_tbdPrev = gpGlobals->time; - for (i = 0; i < CDMG_TIMEBASED; i++) + for( i = 0; i < CDMG_TIMEBASED; i++ ) { // make sure bit is set for damage type - if (m_bitsDamageType & (DMG_PARALYZE << i)) + if( m_bitsDamageType & ( DMG_PARALYZE << i ) ) { - switch (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); + //TakeDamage( pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC ); bDuration = NERVEGAS_DURATION; break; case itbd_Poison: - TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); + TakeDamage( pev, pev, POISON_DAMAGE, DMG_GENERIC ); bDuration = POISON_DURATION; break; case itbd_Radiation: - //TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); + //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) + if( m_idrowndmg > m_idrownrestored ) { - int idif = min(m_idrowndmg - m_idrownrestored, 10); + int idif = min( m_idrowndmg - m_idrownrestored, 10 ); - TakeHealth(idif, DMG_GENERIC); + 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); + //TakeDamage( pev, pev, ACID_DAMAGE, DMG_GENERIC ); bDuration = ACID_DURATION; break; case itbd_SlowBurn: - //TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); + //TakeDamage( pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC ); bDuration = SLOWBURN_DURATION; break; case itbd_SlowFreeze: - //TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); + //TakeDamage( pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC ); bDuration = SLOWFREEZE_DURATION; break; default: bDuration = 0; } - if (m_rgbTimeBasedDamage[i]) + 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( ( ( i == itbd_NerveGas ) && ( m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION ) ) || + ( ( i == itbd_Poison ) && ( m_rgbTimeBasedDamage[i] < POISON_DURATION ) ) ) { - if (m_rgItems[ITEM_ANTIDOTE]) + if( m_rgItems[ITEM_ANTIDOTE] ) { m_rgbTimeBasedDamage[i] = 0; m_rgItems[ITEM_ANTIDOTE]--; - SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK); + SetSuitUpdate( "!HEV_HEAL4", FALSE, SUIT_REPEAT_OK ); } } // decrement damage duration, detect when done. - if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) + if( !m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0 ) { m_rgbTimeBasedDamage[i] = 0; // if we're done, clear damage bits - m_bitsDamageType &= ~(DMG_PARALYZE << i); + m_bitsDamageType &= ~( DMG_PARALYZE << i ); } } else @@ -2086,20 +2082,20 @@ Things powered by the battery #define GEIGERDELAY 0.25 -void CBasePlayer :: UpdateGeigerCounter( void ) +void CBasePlayer::UpdateGeigerCounter( void ) { BYTE range; // delay per update ie: don't flood net with these msgs - if (gpGlobals->time < m_flgeigerDelay) + if( gpGlobals->time < m_flgeigerDelay ) return; m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; // send range to radition source to client - range = (BYTE) (m_flgeigerRange / 4); + range = (BYTE)( m_flgeigerRange / 4 ); - if (range != m_igeigerRangePrev) + if( range != m_igeigerRangePrev ) { m_igeigerRangePrev = range; @@ -2109,7 +2105,7 @@ void CBasePlayer :: UpdateGeigerCounter( void ) } // reset counter and semaphore - if (!RANDOM_LONG(0,3)) + if( !RANDOM_LONG( 0, 3 ) ) m_flgeigerRange = 1000; } @@ -2121,8 +2117,8 @@ Play suit update if it's time ================ */ -#define SUITUPDATETIME 3.5 -#define SUITFIRSTUPDATETIME 0.1 +#define SUITUPDATETIME 3.5 +#define SUITFIRSTUPDATETIME 0.1 void CBasePlayer::CheckSuitUpdate() { @@ -2131,45 +2127,45 @@ void CBasePlayer::CheckSuitUpdate() int isearch = m_iSuitPlayNext; // Ignore suit updates if no suit - if ( !(pev->weapons & (1<weapons & ( 1 << WEAPON_SUIT ) ) ) return; // if in range of radiation source, ping geiger counter UpdateGeigerCounter(); - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { // don't bother updating HEV voice in multiplayer. return; } - if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) + if( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0 ) { // play a sentence off of the end of the queue - for (i = 0; i < CSUITPLAYLIST; i++) + for( i = 0; i < CSUITPLAYLIST; i++ ) { - if ( ( isentence = m_rgSuitPlayList[isearch] ) ) + if( ( isentence = m_rgSuitPlayList[isearch] ) ) break; - if (++isearch == CSUITPLAYLIST) + if( ++isearch == CSUITPLAYLIST ) isearch = 0; } - if (isentence) + if( isentence ) { m_rgSuitPlayList[isearch] = 0; - if (isentence > 0) + if( isentence > 0 ) { // play sentence number char sentence[CBSENTENCENAME_MAX + 1]; - strcpy(sentence, "!"); - strcat(sentence, gszallsentencenames[isentence]); - EMIT_SOUND_SUIT(ENT(pev), sentence); + strcpy( sentence, "!" ); + strcat( sentence, gszallsentencenames[isentence] ); + EMIT_SOUND_SUIT( ENT( pev ), sentence ); } else { // play sentence group - EMIT_GROUPID_SUIT(ENT(pev), -isentence); + EMIT_GROUPID_SUIT( ENT( pev ), -isentence ); } m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; } @@ -2185,52 +2181,51 @@ void CBasePlayer::CheckSuitUpdate() // seconds, then we won't repeat playback of this word or sentence // for at least that number of seconds. -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) +void CBasePlayer::SetSuitUpdate( char *name, int fgroup, int iNoRepeatTime ) { int i; int isentence; int iempty = -1; // Ignore suit updates if no suit - if ( !(pev->weapons & (1<weapons & ( 1 << WEAPON_SUIT ) ) ) return; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->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) + if( !name ) { - for (i = 0; i < CSUITPLAYLIST; i++) + for( i = 0; i < CSUITPLAYLIST; i++ ) m_rgSuitPlayList[i] = 0; return; } // get sentence or group number - if (!fgroup) + if( !fgroup ) { - isentence = SENTENCEG_Lookup(name, NULL); - if (isentence < 0) + isentence = SENTENCEG_Lookup( name, NULL ); + if( isentence < 0 ) return; } else // mark group number as negative - isentence = -SENTENCEG_GetIndex(name); + 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++) + for( i = 0; i < CSUITNOREPEAT; i++ ) { - if (isentence == m_rgiSuitNoRepeat[i]) + if( isentence == m_rgiSuitNoRepeat[i] ) { // this sentence or group is already in // the norepeat list - if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) + if( m_rgflSuitNoRepeatTime[i] < gpGlobals->time ) { // norepeat time has expired, clear it out m_rgiSuitNoRepeat[i] = 0; @@ -2245,28 +2240,27 @@ void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) } } // keep track of empty slot - if (!m_rgiSuitNoRepeat[i]) + if( !m_rgiSuitNoRepeat[i] ) iempty = i; } // sentence is not in norepeat list, save if norepeat time was given - if (iNoRepeatTime) + if( iNoRepeatTime ) { - if (iempty < 0) - iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over + 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) + if( m_iSuitPlayNext == CSUITPLAYLIST ) m_iSuitPlayNext = 0; - if (m_flSuitUpdate <= gpGlobals->time) + if( m_flSuitUpdate <= gpGlobals->time ) { - if (m_flSuitUpdate == 0) + if( m_flSuitUpdate == 0 ) // play queue is empty, don't delay too long before playback m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; else @@ -2283,9 +2277,9 @@ Check for turning off powerups GLOBALS ASSUMED SET: g_ulModelIndexPlayer ================ */ -static void CheckPowerups(entvars_t *pev) +static void CheckPowerups( entvars_t *pev ) { - if (pev->health <= 0) + if( pev->health <= 0 ) return; pev->modelindex = g_ulModelIndexPlayer; // don't use eyes @@ -2295,17 +2289,17 @@ static void CheckPowerups(entvars_t *pev) // UpdatePlayerSound - updates the position of the player's // reserved sound slot in the sound list. //========================================================= -void CBasePlayer :: UpdatePlayerSound ( void ) +void CBasePlayer::UpdatePlayerSound( void ) { int iBodyVolume; int iVolume; CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); + pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); - if ( !pSound ) + if( !pSound ) { - ALERT ( at_console, "Client lost reserved sound!\n" ); + ALERT( at_console, "Client lost reserved sound!\n" ); return; } @@ -2313,13 +2307,13 @@ void CBasePlayer :: UpdatePlayerSound ( void ) // 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 ) ) - { + if( FBitSet( pev->flags, FL_ONGROUND ) ) + { iBodyVolume = 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 ) + if( iBodyVolume > 512 ) { iBodyVolume = 512; } @@ -2329,13 +2323,13 @@ void CBasePlayer :: UpdatePlayerSound ( void ) iBodyVolume = 0; } - if ( pev->button & IN_JUMP ) + if( pev->button & IN_JUMP ) { iBodyVolume += 100; } // convert player move speed and actions into sound audible by monsters. - if ( m_iWeaponVolume > iBodyVolume ) + if( m_iWeaponVolume > iBodyVolume ) { m_iTargetVolume = m_iWeaponVolume; @@ -2349,7 +2343,7 @@ void CBasePlayer :: UpdatePlayerSound ( void ) // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while m_iWeaponVolume -= 250 * gpGlobals->frametime; - if ( m_iWeaponVolume < 0 ) + if( m_iWeaponVolume < 0 ) { iVolume = 0; } @@ -2360,34 +2354,34 @@ void CBasePlayer :: UpdatePlayerSound ( void ) // to hear a sound, especially if they don't listen every frame. iVolume = pSound->m_iVolume; - if ( m_iTargetVolume > iVolume ) + if( m_iTargetVolume > iVolume ) { iVolume = m_iTargetVolume; } - else if ( iVolume > m_iTargetVolume ) + else if( iVolume > m_iTargetVolume ) { iVolume -= 250 * gpGlobals->frametime; - if ( iVolume < m_iTargetVolume ) + if( iVolume < m_iTargetVolume ) { iVolume = 0; } } - if ( m_fNoPlayerSound ) + if( m_fNoPlayerSound ) { // debugging flag, lets players move around and shoot without monsters hearing. iVolume = 0; } - if ( gpGlobals->time > m_flStopExtraSoundTime ) + 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 ) + if( pSound ) { pSound->m_vecOrigin = pev->origin; pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); @@ -2396,31 +2390,31 @@ void CBasePlayer :: UpdatePlayerSound ( void ) // keep track of virtual muzzle flash m_iWeaponFlash -= 256 * gpGlobals->frametime; - if (m_iWeaponFlash < 0) + if( m_iWeaponFlash < 0 ) m_iWeaponFlash = 0; - //UTIL_MakeVectors ( pev->angles ); + //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 ); + // 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( g_fGameOver ) + goto pt_end; // intermission or finale - if (!IsAlive()) + if( !IsAlive() ) goto pt_end; // Handle Tank controlling - if ( m_pTank != NULL ) + if( m_pTank != NULL ) { // if they've moved too far from the gun, or selected a weapon, unuse the gun - if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ) + if( m_pTank->OnControls( pev ) && !pev->weaponmodel ) { m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun } @@ -2433,74 +2427,73 @@ void CBasePlayer::PostThink() } // do weapon stuff - ItemPostFrame( ); + 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 + // 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 ) + 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) + // 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); + // 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 ) + 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 ) + 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); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM ); } - if ( flFallDamage > 0 ) + if( flFallDamage > 0 ) { - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); + TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), flFallDamage, DMG_FALL ); pev->punchangle.x = 0; } } - if ( IsAlive() ) + if( IsAlive() ) { SetAnimation( PLAYER_WALK ); } } - if (FBitSet(pev->flags, FL_ONGROUND)) - { - if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) + if( FBitSet( pev->flags, FL_ONGROUND ) ) + { + if( m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer() ) { - CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); + CSoundEnt::InsertSound( bits_SOUND_PLAYER, pev->origin, 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( IsAlive() ) { - if (!pev->velocity.x && !pev->velocity.y) + if( !pev->velocity.x && !pev->velocity.y ) SetAnimation( PLAYER_IDLE ); - else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) + else if( ( pev->velocity.x || pev->velocity.y ) && ( FBitSet( pev->flags, FL_ONGROUND ) ) ) SetAnimation( PLAYER_WALK ); - else if (pev->waterlevel > 1) + else if( pev->waterlevel > 1 ) SetAnimation( PLAYER_WALK ); } - StudioFrameAdvance( ); - CheckPowerups(pev); + StudioFrameAdvance(); + CheckPowerups( pev ); UpdatePlayerSound(); @@ -2511,37 +2504,37 @@ 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++ ) + for( int i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[ i ] ) + if( m_rgpPlayerItems[i] ) { - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[i]; - while ( pPlayerItem ) + while( pPlayerItem ) { CBasePlayerWeapon *gun; gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) + 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 ); + 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 ) + if( gun->m_flTimeWeaponIdle != 1000 ) { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); + gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); } - if ( gun->pev->fuser1 != 1000 ) + if( gun->pev->fuser1 != 1000 ) { - gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 ); + gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 ); } // Only decrement if not flagged as NO_DECREMENT - /*if ( gun->m_flPumpTime != 1000 ) + /*if( gun->m_flPumpTime != 1000 ) { - gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); + gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); }*/ } @@ -2551,22 +2544,22 @@ pt_end: } m_flNextAttack -= gpGlobals->frametime; - if ( m_flNextAttack < -0.001 ) + if( m_flNextAttack < -0.001 ) m_flNextAttack = -0.001; - if ( m_flNextAmmoBurn != 1000 ) + if( m_flNextAmmoBurn != 1000 ) { m_flNextAmmoBurn -= gpGlobals->frametime; - - if ( m_flNextAmmoBurn < -0.001 ) + + if( m_flNextAmmoBurn < -0.001 ) m_flNextAmmoBurn = -0.001; } - if ( m_flAmmoStartCharge != 1000 ) + if( m_flAmmoStartCharge != 1000 ) { m_flAmmoStartCharge -= gpGlobals->frametime; - - if ( m_flAmmoStartCharge < -0.001 ) + + if( m_flAmmoStartCharge < -0.001 ) m_flAmmoStartCharge = -0.001; } #else @@ -2579,15 +2572,15 @@ BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) { CBaseEntity *ent = NULL; - if ( !pSpot->IsTriggered( pPlayer ) ) + if( !pSpot->IsTriggered( pPlayer ) ) { return FALSE; } - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) + 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 ) + if( ent->IsPlayer() && ent != pPlayer ) return FALSE; } @@ -2595,7 +2588,7 @@ BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) } DLL_GLOBAL CBaseEntity *g_pLastSpawn; -inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); } +inline int FNullEnt( CBaseEntity *ent ) { return ( ent == NULL ) || FNullEnt( ent->edict() ); } /* ============ @@ -2609,39 +2602,39 @@ USES AND SETS GLOBAL g_pLastSpawn edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) { CBaseEntity *pSpot; - edict_t *player; + edict_t *player; player = pPlayer->edict(); // choose a info_player_deathmatch point - if (g_pGameRules->IsCoOp()) + if( g_pGameRules->IsCoOp() ) { - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop"); - if ( !FNullEnt(pSpot) ) + pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop" ); + if( !FNullEnt( pSpot ) ) goto ReturnSpot; - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start"); - if ( !FNullEnt(pSpot) ) + pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start" ); + if( !FNullEnt(pSpot) ) goto ReturnSpot; } - else if ( g_pGameRules->IsDeathmatch() ) + else if( g_pGameRules->IsDeathmatch() ) { pSpot = g_pLastSpawn; // Randomize the start spot - for ( int i = RANDOM_LONG(1,5); i > 0; i-- ) + 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 + if( FNullEnt( pSpot ) ) // skip over the null point pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); CBaseEntity *pFirstSpot = pSpot; do { - if ( pSpot ) + if( pSpot ) { // check if pSpot is valid - if ( IsSpawnPointValid( pPlayer, pSpot ) ) + if( IsSpawnPointValid( pPlayer, pSpot ) ) { - if ( pSpot->pev->origin == Vector( 0, 0, 0 ) ) + if( pSpot->pev->origin == Vector( 0, 0, 0 ) ) { pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); continue; @@ -2653,41 +2646,41 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) } // increment pSpot pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - } while ( pSpot != pFirstSpot ); // loop if we're not back to the start + } 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 ) ) + if( !FNullEnt( pSpot ) ) { CBaseEntity *ent = NULL; - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != 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 ); + 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))) + if( FStringNull( gpGlobals->startspot ) || !strlen(STRING( gpGlobals->startspot ) ) ) { - pSpot = UTIL_FindEntityByClassname(NULL, "info_player_start"); - if ( !FNullEnt(pSpot) ) + pSpot = UTIL_FindEntityByClassname( NULL, "info_player_start" ); + if( !FNullEnt( pSpot ) ) goto ReturnSpot; } else { - pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) ); - if ( !FNullEnt(pSpot) ) + pSpot = UTIL_FindEntityByTargetname( NULL, STRING( gpGlobals->startspot ) ); + if( !FNullEnt( pSpot ) ) goto ReturnSpot; } ReturnSpot: - if ( FNullEnt( pSpot ) ) + if( FNullEnt( pSpot ) ) { - ALERT(at_error, "PutClientInServer: no info_player_start on level"); - return INDEXENT(0); + ALERT( at_error, "PutClientInServer: no info_player_start on level" ); + return INDEXENT( 0 ); } g_pLastSpawn = pSpot; @@ -2696,45 +2689,45 @@ ReturnSpot: 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. + 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 + 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_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_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_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(); + m_bloodColor = BLOOD_COLOR_RED; + m_flNextAttack = UTIL_WeaponTimeBase(); StartSneaking(); m_iFlashBattery = 99; @@ -2746,22 +2739,22 @@ void CBasePlayer::Spawn( void ) g_pGameRules->SetDefaultPlayerTeam( this ); g_pGameRules->GetPlayerSpawnSpot( this ); - SET_MODEL(ENT(pev), "models/player.mdl"); + SET_MODEL( ENT( pev ), "models/player.mdl" ); g_ulModelIndexPlayer = pev->modelindex; - pev->sequence = LookupActivity( ACT_IDLE ); + pev->sequence = LookupActivity( ACT_IDLE ); - if ( FBitSet(pev->flags, FL_DUCKING) ) - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); + 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); + UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); pev->view_ofs = VEC_VIEW; Precache(); - m_HackedGunPos = Vector( 0, 32, 0 ); + m_HackedGunPos = Vector( 0, 32, 0 ); - if ( m_iPlayerSound == SOUNDLIST_EMPTY ) + if( m_iPlayerSound == SOUNDLIST_EMPTY ) { - ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); + ALERT( at_console, "Couldn't alloc player sound slot!\n" ); } m_fNoPlayerSound = FALSE;// normal sound behavior. @@ -2774,35 +2767,35 @@ void CBasePlayer::Spawn( void ) m_iClientBattery = -1; // reset all ammo values to 0 - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) + 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 ) +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.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) { - if ( !WorldGraph.FSetGraphPointers() ) + if( !WorldGraph.FSetGraphPointers() ) { - ALERT ( at_console, "**Graph pointers were not set!\n"); + ALERT( at_console, "**Graph pointers were not set!\n" ); } else { - ALERT ( at_console, "**Graph Pointers Set!\n" ); - } + ALERT( at_console, "**Graph Pointers Set!\n" ); + } } // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) @@ -2828,43 +2821,43 @@ void CBasePlayer :: Precache( void ) m_iUpdateTime = 5; // won't update for 1/2 a second - if ( gInitHUD ) + if( gInitHUD ) m_fInitHUD = TRUE; } int CBasePlayer::Save( CSave &save ) { - if ( !CBaseMonster::Save(save) ) + if( !CBaseMonster::Save( save ) ) return 0; - return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); + 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) +void CBasePlayer::RenewItems( void ) { } int CBasePlayer::Restore( CRestore &restore ) { - if ( !CBaseMonster::Restore(restore) ) + if( !CBaseMonster::Restore( restore ) ) return 0; - int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); + int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE( m_playerSaveData ) ); SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; // landmark isn't present. - if ( !pSaveData->fUseLandmark ) + 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; + 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; @@ -2872,25 +2865,25 @@ int CBasePlayer::Restore( CRestore &restore ) pev->fixangle = TRUE; // turn this way immediately // Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; + m_bloodColor = BLOOD_COLOR_RED; g_ulModelIndexPlayer = pev->modelindex; - if ( FBitSet(pev->flags, FL_DUCKING) ) + 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); + UTIL_SetSize( pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); } else { - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); } g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - if ( m_fLongJump ) + if( m_fLongJump ) { g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); } @@ -2914,118 +2907,118 @@ void CBasePlayer::SelectNextItem( int iItem ) { CBasePlayerItem *pItem; - pItem = m_rgpPlayerItems[ iItem ]; - - if (!pItem) + pItem = m_rgpPlayerItems[iItem]; + + if( !pItem ) return; - if (pItem == m_pActiveItem) + if( pItem == m_pActiveItem ) { // select the next one in the chain pItem = m_pActiveItem->m_pNext; - if (! pItem) + if( !pItem ) { return; } CBasePlayerItem *pLast; pLast = pItem; - while (pLast->m_pNext) + while( pLast->m_pNext ) pLast = pLast->m_pNext; // relink chain pLast->m_pNext = m_pActiveItem; m_pActiveItem->m_pNext = NULL; - m_rgpPlayerItems[ iItem ] = pItem; + m_rgpPlayerItems[iItem] = pItem; } - ResetAutoaim( ); + ResetAutoaim(); // FIX, this needs to queue them up and delay - if (m_pActiveItem) + if( m_pActiveItem ) { - m_pActiveItem->Holster( ); + m_pActiveItem->Holster(); } - + m_pActiveItem = pItem; - if (m_pActiveItem) + if( m_pActiveItem ) { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); + m_pActiveItem->Deploy(); + m_pActiveItem->UpdateItemInfo(); } } -void CBasePlayer::SelectItem(const char *pstr) +void CBasePlayer::SelectItem( const char *pstr ) { - if (!pstr) + if( !pstr ) return; CBasePlayerItem *pItem = NULL; - for (int i = 0; i < MAX_ITEM_TYPES; i++) + for( int i = 0; i < MAX_ITEM_TYPES; i++ ) { - if (m_rgpPlayerItems[i]) + if( m_rgpPlayerItems[i] ) { pItem = m_rgpPlayerItems[i]; - - while (pItem) + + while( pItem ) { - if (FClassnameIs(pItem->pev, pstr)) + if( FClassnameIs( pItem->pev, pstr ) ) break; pItem = pItem->m_pNext; } } - if (pItem) + if( pItem ) break; } - if (!pItem) + if( !pItem ) return; - if (pItem == m_pActiveItem) + if( pItem == m_pActiveItem ) return; - ResetAutoaim( ); + ResetAutoaim(); // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - + if( m_pActiveItem ) + m_pActiveItem->Holster(); + m_pLastItem = m_pActiveItem; m_pActiveItem = pItem; - if (m_pActiveItem) + if( m_pActiveItem ) { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); + m_pActiveItem->Deploy(); + m_pActiveItem->UpdateItemInfo(); } } -void CBasePlayer::SelectLastItem(void) +void CBasePlayer::SelectLastItem( void ) { - if (!m_pLastItem) + if( !m_pLastItem ) { return; } - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + if( m_pActiveItem && !m_pActiveItem->CanHolster() ) { return; } - ResetAutoaim( ); + ResetAutoaim(); // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - + if( m_pActiveItem ) + m_pActiveItem->Holster(); + CBasePlayerItem *pTemp = m_pActiveItem; m_pActiveItem = m_pLastItem; m_pLastItem = pTemp; - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); + m_pActiveItem->Deploy(); + m_pActiveItem->UpdateItemInfo(); } //============================================== @@ -3035,9 +3028,9 @@ BOOL CBasePlayer::HasWeapons( void ) { int i; - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[ i ] ) + if( m_rgpPlayerItems[i] ) { return TRUE; } @@ -3052,7 +3045,7 @@ void CBasePlayer::SelectPrevItem( int iItem ) const char *CBasePlayer::TeamID( void ) { - if ( pev == NULL ) // Not fully connected yet + if( pev == NULL ) // Not fully connected yet return ""; // return their team name @@ -3066,46 +3059,46 @@ const char *CBasePlayer::TeamID( void ) class CSprayCan : public CBaseEntity { public: - void Spawn ( entvars_t *pevOwner ); - void Think( void ); + void Spawn( entvars_t *pevOwner ); + void Think( void ); - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } }; -void CSprayCan::Spawn ( entvars_t *pevOwner ) +void CSprayCan::Spawn( entvars_t *pevOwner ) { - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); + pev->origin = pevOwner->origin + Vector( 0, 0, 32 ); pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); + 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); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM ); } void CSprayCan::Think( void ) { - TraceResult tr; + TraceResult tr; int playernum; int nFrames; CBasePlayer *pPlayer; - - pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); - if (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); + playernum = ENTINDEX( pev->owner ); - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); + // 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) + if( nFrames == -1 ) { UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); UTIL_Remove( this ); @@ -3114,38 +3107,38 @@ void CSprayCan::Think( void ) { UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); // Just painted last custom frame. - if ( pev->frame++ >= (nFrames - 1)) + if( pev->frame++ >= ( nFrames - 1 ) ) UTIL_Remove( this ); } pev->nextthink = gpGlobals->time + 0.1; } -class CBloodSplat : public CBaseEntity +class CBloodSplat : public CBaseEntity { public: - void Spawn ( entvars_t *pevOwner ); - void Spray ( void ); + void Spawn( entvars_t *pevOwner ); + void Spray( void ); }; -void CBloodSplat::Spawn ( entvars_t *pevOwner ) +void CBloodSplat::Spawn( entvars_t *pevOwner ) { - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); + pev->origin = pevOwner->origin + Vector( 0, 0, 32 ); pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); + pev->owner = ENT( pevOwner ); SetThink( &CBloodSplat::Spray ); pev->nextthink = gpGlobals->time + 0.1; } -void CBloodSplat::Spray ( void ) +void CBloodSplat::Spray( void ) { - TraceResult tr; + TraceResult tr; - if ( g_Language != LANGUAGE_GERMAN ) + 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_MakeVectors( pev->angles ); + UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr ); UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); } @@ -3154,17 +3147,16 @@ void CBloodSplat::Spray ( void ) } //============================================== - void CBasePlayer::GiveNamedItem( const char *pszName ) { edict_t *pent; - int istr = MAKE_STRING(pszName); + int istr = MAKE_STRING( pszName ); - pent = CREATE_NAMED_ENTITY(istr); - if ( FNullEnt( pent ) ) + pent = CREATE_NAMED_ENTITY( istr ); + if( FNullEnt( pent ) ) { - ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" ); + ALERT( at_console, "NULL Ent in GiveNamedItem!\n" ); return; } VARS( pent )->origin = pev->origin; @@ -3178,9 +3170,9 @@ 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) ) + 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; @@ -3188,38 +3180,38 @@ CBaseEntity *FindEntityForward( CBaseEntity *pMe ) return NULL; } -BOOL CBasePlayer :: FlashlightIsOn( void ) +BOOL CBasePlayer::FlashlightIsOn( void ) { - return FBitSet(pev->effects, EF_DIMLIGHT); + return FBitSet( pev->effects, EF_DIMLIGHT ); } -void CBasePlayer :: FlashlightTurnOn( void ) +void CBasePlayer::FlashlightTurnOn( void ) { - if ( !g_pGameRules->FAllowFlashlight() ) + if( !g_pGameRules->FAllowFlashlight() ) { return; } - if ( (pev->weapons & (1<weapons & ( 1 << WEAPON_SUIT ) ) ) { - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM ); - SetBits(pev->effects, EF_DIMLIGHT); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM ); + SetBits( pev->effects, EF_DIMLIGHT ); MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(1); - WRITE_BYTE(m_iFlashBattery); + WRITE_BYTE( 1 ); + WRITE_BYTE( m_iFlashBattery ); MESSAGE_END(); m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; } } -void CBasePlayer :: FlashlightTurnOff( void ) +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); + 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); + WRITE_BYTE( 0 ); + WRITE_BYTE( m_iFlashBattery ); MESSAGE_END(); m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; @@ -3234,9 +3226,9 @@ so that the client side .dll can behave correctly. Reset stuff so that the state is transmitted. =============== */ -void CBasePlayer :: ForceClientDllUpdate( void ) +void CBasePlayer::ForceClientDllUpdate( void ) { - m_iClientHealth = -1; + m_iClientHealth = -1; m_iClientBattery = -1; m_iTrain |= TRAIN_NEW; // Force new train message. m_fWeapon = FALSE; // Force weapon send @@ -3255,24 +3247,23 @@ ImpulseCommands */ extern float g_flWeaponCheat; -void CBasePlayer::ImpulseCommands( ) +void CBasePlayer::ImpulseCommands() { - TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs + TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs // Handle use events PlayerUse(); int iImpulse = (int)pev->impulse; - switch (iImpulse) + switch( iImpulse ) { case 99: - { int iOn; - if (!gmsgLogo) + if( !gmsgLogo ) { iOn = 1; - gmsgLogo = REG_USER_MSG("Logo", 1); + gmsgLogo = REG_USER_MSG( "Logo", 1 ); } else { @@ -3283,40 +3274,39 @@ void CBasePlayer::ImpulseCommands( ) // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgLogo, NULL, pev ); - WRITE_BYTE(iOn); + WRITE_BYTE( iOn ); MESSAGE_END(); if(!iOn) gmsgLogo = 0; break; - } case 100: // temporary flashlight for level designers - if ( FlashlightIsOn() ) + if( FlashlightIsOn() ) { FlashlightTurnOff(); } - else + else { FlashlightTurnOn(); } break; case 201: // paint decal - if ( gpGlobals->time < m_flNextDecalTime ) + 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); + 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 ) + if( tr.flFraction != 1.0 ) { // line hit something, so paint a decal m_flNextDecalTime = gpGlobals->time + decalfrequency.value; - CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); + CSprayCan *pCan = GetClassPtr( (CSprayCan *)NULL ); pCan->Spawn( pev ); } break; @@ -3334,7 +3324,7 @@ void CBasePlayer::ImpulseCommands( ) void CBasePlayer::CheatImpulseCommands( int iImpulse ) { #if !defined( HLDEMO_BUILD ) - if ( g_flWeaponCheat == 0.0 ) + if( g_flWeaponCheat == 0.0 ) { return; } @@ -3342,22 +3332,20 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) CBaseEntity *pEntity; TraceResult tr; - switch ( iImpulse ) + switch( iImpulse ) { case 76: + if( !giPrecacheGrunt ) { - 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; + 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" ); @@ -3395,10 +3383,10 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) case 103: // What the hell are you doing? pEntity = FindEntityForward( this ); - if ( pEntity ) + if( pEntity ) { CBaseMonster *pMonster = pEntity->MyMonsterPointer(); - if ( pMonster ) + if( pMonster ) pMonster->ReportAIState(); } break; @@ -3407,94 +3395,98 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) gGlobalState.DumpGlobals(); break; case 105:// player makes no sound for monsters to hear. + if( m_fNoPlayerSound ) { - 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; + 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 ) + if( pEntity ) { - ALERT ( at_console, "Classname: %s", STRING( pEntity->pev->classname ) ); - - if ( !FStringNull ( pEntity->pev->targetname ) ) + ALERT( at_console, "Classname: %s", STRING( pEntity->pev->classname ) ); + + if( !FStringNull( pEntity->pev->targetname ) ) { - ALERT ( at_console, " - Targetname: %s\n", STRING( pEntity->pev->targetname ) ); + ALERT( at_console, " - Targetname: %s\n", STRING( pEntity->pev->targetname ) ); } else { - ALERT ( at_console, " - TargetName: No Targetname\n" ); + 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 ) ); + 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 ); + 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 ) + if( tr.pHit ) pWorld = tr.pHit; const char *pTextureName = TRACE_TEXTURE( pWorld, start, end ); - if ( pTextureName ) + if( pTextureName ) ALERT( at_console, "Texture: %s\n", pTextureName ); } break; - case 195:// show shortest paths for entire level to nearest node + case 195: + // show shortest paths for entire level to nearest node { - Create("node_viewer_fly", pev->origin, pev->angles); + Create( "node_viewer_fly", pev->origin, pev->angles ); } break; - case 196:// show shortest paths for entire level to nearest node + case 196: + // show shortest paths for entire level to nearest node { - Create("node_viewer_large", pev->origin, pev->angles); + Create( "node_viewer_large", pev->origin, pev->angles ); } break; - case 197:// show shortest paths for entire level to nearest node + case 197: + // show shortest paths for entire level to nearest node { - Create("node_viewer_human", pev->origin, pev->angles); + Create( "node_viewer_human", pev->origin, pev->angles ); } break; - case 199:// show nearest node and all connections + 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 ) ); + 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); + 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 ) + if( tr.flFraction != 1.0 ) { // line hit something, so paint a decal - CBloodSplat *pBlood = GetClassPtr((CBloodSplat *)NULL); + CBloodSplat *pBlood = GetClassPtr( (CBloodSplat *)NULL ); pBlood->Spawn( pev ); } break; - case 203:// remove creature. + case 203: + // remove creature. pEntity = FindEntityForward( this ); - if ( pEntity ) + if( pEntity ) { - if ( pEntity->pev->takedamage ) - pEntity->SetThink( &CBaseEntity::SUB_Remove); + if( pEntity->pev->takedamage ) + pEntity->SetThink( &CBaseEntity::SUB_Remove ); } break; } @@ -3510,85 +3502,85 @@ int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; - while (pInsert) + while( pInsert ) { - if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) )) + if( FClassnameIs( pInsert->pev, STRING( pItem->pev->classname ) ) ) { - if (pItem->AddDuplicate( pInsert )) + if( pItem->AddDuplicate( pInsert ) ) { - g_pGameRules->PlayerGotWeapon ( this, pItem ); + 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( ); + pInsert->UpdateItemInfo(); + if( m_pActiveItem ) + m_pActiveItem->UpdateItemInfo(); - pItem->Kill( ); + pItem->Kill(); } - else if (gEvilImpulse101) + else if( gEvilImpulse101 ) { // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); + pItem->Kill(); } return FALSE; } pInsert = pInsert->m_pNext; } - if (pItem->AddToPlayer( this )) + if( pItem->AddToPlayer( this ) ) { - g_pGameRules->PlayerGotWeapon ( this, pItem ); + 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 ) ) + if( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) { SwitchWeapon( pItem ); } return TRUE; } - else if (gEvilImpulse101) + else if( gEvilImpulse101 ) { // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); + pItem->Kill(); } return FALSE; } int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { - if (m_pActiveItem == pItem) + if( m_pActiveItem == pItem ) { - ResetAutoaim( ); - pItem->Holster( ); + 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 ) + else if( m_pLastItem == pItem ) m_pLastItem = NULL; CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()]; - if (pPrev == pItem) + if( pPrev == pItem ) { m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; return TRUE; } else { - while (pPrev && pPrev->m_pNext != pItem) + while( pPrev && pPrev->m_pNext != pItem ) { pPrev = pPrev->m_pNext; } - if (pPrev) + if( pPrev ) { pPrev->m_pNext = pItem->m_pNext; return TRUE; @@ -3600,15 +3592,15 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) // // Returns the unique ID for the ammo, or -1 if error // -int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) +int CBasePlayer::GiveAmmo( int iCount, char *szName, int iMax ) { - if ( !szName ) + if( !szName ) { // no ammo. return -1; } - if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) + if( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) { // game rules say I can't have any more of this ammo type. return -1; @@ -3618,20 +3610,20 @@ int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) i = GetAmmoIndex( szName ); - if ( i < 0 || i >= MAX_AMMO_SLOTS ) + if( i < 0 || i >= MAX_AMMO_SLOTS ) return -1; int iAdd = min( iCount, iMax - m_rgAmmo[i] ); - if ( iAdd < 1 ) + if( iAdd < 1 ) return i; - m_rgAmmo[ i ] += iAdd; + m_rgAmmo[i] += iAdd; - if ( gmsgAmmoPickup ) // make sure the ammo messages have been linked first + 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( GetAmmoIndex( szName ) ); // ammo ID WRITE_BYTE( iAdd ); // amount MESSAGE_END(); } @@ -3651,18 +3643,18 @@ Called every frame by the player PreThink void CBasePlayer::ItemPreFrame() { #if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) + if( m_flNextAttack > 0 ) #else - if ( gpGlobals->time < m_flNextAttack ) + if( gpGlobals->time < m_flNextAttack ) #endif { return; } - if (!m_pActiveItem) + if( !m_pActiveItem ) return; - m_pActiveItem->ItemPreFrame( ); + m_pActiveItem->ItemPreFrame(); } /* @@ -3677,13 +3669,13 @@ void CBasePlayer::ItemPostFrame() static int fInSelect = FALSE; // check if the player is using a tank - if ( m_pTank != NULL ) + if( m_pTank != NULL ) return; #if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) + if( m_flNextAttack > 0 ) #else - if ( gpGlobals->time < m_flNextAttack ) + if( gpGlobals->time < m_flNextAttack ) #endif { return; @@ -3691,35 +3683,35 @@ void CBasePlayer::ItemPostFrame() ImpulseCommands(); - if (!m_pActiveItem) + if( !m_pActiveItem ) return; - m_pActiveItem->ItemPostFrame( ); + m_pActiveItem->ItemPostFrame(); } int CBasePlayer::AmmoInventory( int iAmmoIndex ) { - if (iAmmoIndex == -1) + if( iAmmoIndex == -1 ) { return -1; } - return m_rgAmmo[ iAmmoIndex ]; + return m_rgAmmo[iAmmoIndex]; } -int CBasePlayer::GetAmmoIndex(const char *psz) +int CBasePlayer::GetAmmoIndex( const char *psz ) { int i; - if (!psz) + if( !psz ) return -1; - for (i = 1; i < MAX_AMMO_SLOTS; i++) + for( i = 1; i < MAX_AMMO_SLOTS; i++ ) { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName ) + if( !CBasePlayerItem::AmmoInfoArray[i].pszName ) continue; - if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0) + if( stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0 ) return i; } @@ -3728,11 +3720,11 @@ int CBasePlayer::GetAmmoIndex(const char *psz) // Called from UpdateClientData // makes sure the client has all the necessary ammo info, if values have changed -void CBasePlayer::SendAmmoUpdate(void) +void CBasePlayer::SendAmmoUpdate( void ) { - for (int i=0; i < MAX_AMMO_SLOTS;i++) + for( int i = 0; i < MAX_AMMO_SLOTS; i++ ) { - if (m_rgAmmo[i] != m_rgAmmoLast[i]) + if( m_rgAmmo[i] != m_rgAmmoLast[i] ) { m_rgAmmoLast[i] = m_rgAmmo[i]; @@ -3759,9 +3751,9 @@ ForceClientDllUpdate to ensure the demo gets messages reflecting all of the HUD state info. ========================================================= */ -void CBasePlayer :: UpdateClientData( void ) +void CBasePlayer::UpdateClientData( void ) { - if (m_fInitHUD) + if( m_fInitHUD ) { m_fInitHUD = FALSE; gInitHUD = FALSE; @@ -3770,14 +3762,14 @@ void CBasePlayer :: UpdateClientData( void ) WRITE_BYTE( 0 ); MESSAGE_END(); - if ( !m_fGameHUDInitialized ) + if( !m_fGameHUDInitialized ) { MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, pev ); MESSAGE_END(); g_pGameRules->InitHUD( this ); m_fGameHUDInitialized = TRUE; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); } @@ -3788,7 +3780,7 @@ void CBasePlayer :: UpdateClientData( void ) InitStatusBar(); } - if ( m_iHideHUD != m_iClientHideHUD ) + if( m_iHideHUD != m_iClientHideHUD ) { MESSAGE_BEGIN( MSG_ONE, gmsgHideWeapon, NULL, pev ); WRITE_BYTE( m_iHideHUD ); @@ -3797,7 +3789,7 @@ void CBasePlayer :: UpdateClientData( void ) m_iClientHideHUD = m_iHideHUD; } - if ( m_iFOV != m_iClientFOV ) + if( m_iFOV != m_iClientFOV ) { MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); WRITE_BYTE( m_iFOV ); @@ -3807,7 +3799,7 @@ void CBasePlayer :: UpdateClientData( void ) } // HACKHACK -- send the message to display the game title - if (gDisplayTitle) + if( gDisplayTitle ) { MESSAGE_BEGIN( MSG_ONE, gmsgShowGameTitle, NULL, pev ); WRITE_BYTE( 0 ); @@ -3815,7 +3807,7 @@ void CBasePlayer :: UpdateClientData( void ) gDisplayTitle = 0; } - if (pev->health != m_iClientHealth) + if( pev->health != m_iClientHealth ) { int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent @@ -3827,7 +3819,7 @@ void CBasePlayer :: UpdateClientData( void ) m_iClientHealth = pev->health; } - if (pev->armorvalue != m_iClientBattery) + if( pev->armorvalue != m_iClientBattery ) { m_iClientBattery = pev->armorvalue; @@ -3835,21 +3827,21 @@ void CBasePlayer :: UpdateClientData( void ) // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); - WRITE_SHORT( (int)pev->armorvalue); + WRITE_SHORT( (int)pev->armorvalue ); MESSAGE_END(); } - if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) + 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 ) + if( other ) { - CBaseEntity *pEntity = CBaseEntity::Instance(other); - if ( pEntity ) + CBaseEntity *pEntity = CBaseEntity::Instance( other ); + if( pEntity ) damageOrigin = pEntity->Center(); } @@ -3864,32 +3856,32 @@ void CBasePlayer :: UpdateClientData( void ) 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( ( m_flFlashLightTime ) && ( m_flFlashLightTime <= gpGlobals->time ) ) { - if (FlashlightIsOn()) + if( FlashlightIsOn() ) { - if (m_iFlashBattery) + if( m_iFlashBattery ) { m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; m_iFlashBattery--; - if (!m_iFlashBattery) + if( !m_iFlashBattery ) FlashlightTurnOff(); } } else { - if (m_iFlashBattery < 100) + if( m_iFlashBattery < 100 ) { m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; m_iFlashBattery++; @@ -3899,17 +3891,17 @@ void CBasePlayer :: UpdateClientData( void ) } MESSAGE_BEGIN( MSG_ONE, gmsgFlashBattery, NULL, pev ); - WRITE_BYTE(m_iFlashBattery); + WRITE_BYTE( m_iFlashBattery ); MESSAGE_END(); } - if (m_iTrain & TRAIN_NEW) + if( m_iTrain & TRAIN_NEW ) { ASSERT( gmsgTrain > 0 ); // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgTrain, NULL, pev ); - WRITE_BYTE(m_iTrain & 0xF); + WRITE_BYTE( m_iTrain & 0xF ); MESSAGE_END(); m_iTrain &= ~TRAIN_NEW; @@ -3918,7 +3910,7 @@ void CBasePlayer :: UpdateClientData( void ) // // New Weapon? // - if (!m_fKnownItem) + if( !m_fKnownItem ) { m_fKnownItem = TRUE; @@ -3932,35 +3924,35 @@ void CBasePlayer :: UpdateClientData( void ) // byte Ammo2 Type // byte bucket // byte bucket pos - // byte flags + // byte flags // ???? Icons // Send ALL the weapon info now int i; - for (i = 0; i < MAX_WEAPONS; i++) + for( i = 0; i < MAX_WEAPONS; i++ ) { ItemInfo& II = CBasePlayerItem::ItemInfoArray[i]; - if ( !II.iId ) + if( !II.iId ) continue; const char *pszName; - if (!II.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 + 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(); } } @@ -3968,9 +3960,9 @@ void CBasePlayer :: UpdateClientData( void ) SendAmmoUpdate(); // Update all the items - for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) + for( int i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[i] ) // each item updates it's successors + if( m_rgpPlayerItems[i] ) // each item updates it's successors m_rgpPlayerItems[i]->UpdateClientData( this ); } @@ -3979,7 +3971,7 @@ void CBasePlayer :: UpdateClientData( void ) m_iClientFOV = m_iFOV; // Update Status Bar - if ( m_flNextSBarUpdateTime < gpGlobals->time ) + if( m_flNextSBarUpdateTime < gpGlobals->time ) { UpdateStatusBar(); m_flNextSBarUpdateTime = gpGlobals->time + 0.2; @@ -3990,7 +3982,7 @@ void CBasePlayer :: UpdateClientData( void ) // FBecomeProne - Overridden for the player to set the proper // physics flags when a barnacle grabs player. //========================================================= -BOOL CBasePlayer :: FBecomeProne ( void ) +BOOL CBasePlayer::FBecomeProne( void ) { m_afPhysicsFlags |= PFLAG_ONBARNACLE; return TRUE; @@ -4001,16 +3993,16 @@ BOOL CBasePlayer :: FBecomeProne ( void ) // by Barnacle victims when the barnacle pulls their head // into its mouth. For the player, just die. //========================================================= -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) +void CBasePlayer::BarnacleVictimBitten( entvars_t *pevBarnacle ) { - TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); + TakeDamage( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); } //========================================================= // BarnacleVictimReleased - overridden for player who has // physics flags concerns. //========================================================= -void CBasePlayer :: BarnacleVictimReleased ( void ) +void CBasePlayer::BarnacleVictimReleased( void ) { m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; } @@ -4019,23 +4011,22 @@ void CBasePlayer :: BarnacleVictimReleased ( void ) // Illumination // return player light level plus virtual muzzle flash //========================================================= -int CBasePlayer :: Illumination( void ) +int CBasePlayer::Illumination( void ) { - int iIllum = CBaseEntity::Illumination( ); + int iIllum = CBaseEntity::Illumination(); iIllum += m_iWeaponFlash; - if (iIllum > 255) + if( iIllum > 255 ) return 255; return iIllum; } -void CBasePlayer :: EnableControl(BOOL fControl) +void CBasePlayer::EnableControl( BOOL fControl ) { - if (!fControl) + if( !fControl ) pev->flags |= FL_FROZEN; else pev->flags &= ~FL_FROZEN; - } #define DOT_1DEGREE 0.9998476951564 @@ -4056,20 +4047,20 @@ void CBasePlayer :: EnableControl(BOOL fControl) // Autoaim // set crosshair position to point to enemey //========================================================= -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) +Vector CBasePlayer::GetAutoaimVector( float flDelta ) { - if (g_iSkillLevel == SKILL_HARD) + if( g_iSkillLevel == SKILL_HARD ) { UTIL_MakeVectors( pev->v_angle + pev->punchangle ); return gpGlobals->v_forward; } - Vector vecSrc = GetGunPosition( ); + Vector vecSrc = GetGunPosition(); float flDist = 8192; // always use non-sticky autoaim // UNDONE: use sever variable to chose! - if (1 || g_iSkillLevel == SKILL_MEDIUM) + if( 1 || g_iSkillLevel == SKILL_MEDIUM ) { m_vecAutoAim = Vector( 0, 0, 0 ); // flDelta *= 0.5; @@ -4079,34 +4070,34 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); // update ontarget if changed - if ( !g_pGameRules->AllowAutoTargetCrosshair() ) + if( !g_pGameRules->AllowAutoTargetCrosshair() ) m_fOnTarget = 0; - else if (m_fOldTargeting != m_fOnTarget) + else if( m_fOldTargeting != m_fOnTarget ) { - m_pActiveItem->UpdateItemInfo( ); + m_pActiveItem->UpdateItemInfo(); } - if (angles.x > 180) + if( angles.x > 180 ) angles.x -= 360; - if (angles.x < -180) + if( angles.x < -180 ) angles.x += 360; - if (angles.y > 180) + if( angles.y > 180 ) angles.y -= 360; - if (angles.y < -180) + if( angles.y < -180 ) angles.y += 360; - if (angles.x > 25) + if( angles.x > 25 ) angles.x = 25; - if (angles.x < -25) + if( angles.x < -25 ) angles.x = -25; - if (angles.y > 12) + if( angles.y > 12 ) angles.y = 12; - if (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) + if( 0 || g_iSkillLevel == SKILL_EASY ) { m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33; } @@ -4118,13 +4109,12 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) // m_vecAutoAim = m_vecAutoAim * 0.99; // Don't send across network if sv_aim is 0 - if ( g_psv_aim->value != 0 ) + if( g_psv_aim->value != 0 ) { - if ( m_vecAutoAim.x != m_lastx || - m_vecAutoAim.y != m_lasty ) + if( m_vecAutoAim.x != m_lastx || m_vecAutoAim.y != m_lasty ) { SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - + m_lastx = m_vecAutoAim.x; m_lasty = m_vecAutoAim.y; } @@ -4136,16 +4126,16 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta ) return gpGlobals->v_forward; } -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) +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; + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + CBaseEntity *pEntity; + float bestdot; + Vector bestdir; + edict_t *bestent; TraceResult tr; - if ( g_psv_aim->value == 0 ) + if( g_psv_aim->value == 0 ) { m_fOnTarget = FALSE; return g_vecZero; @@ -4162,78 +4152,75 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) + 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( !( ( pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3 ) || ( pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0 ) ) ) { - if (tr.pHit->v.takedamage == DAMAGE_AIM) + if( tr.pHit->v.takedamage == DAMAGE_AIM ) m_fOnTarget = TRUE; return m_vecAutoAim; } } - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) { Vector center; Vector dir; float dot; - if ( pEdict->free ) // Not in use + if( pEdict->free ) // Not in use continue; - if (pEdict->v.takedamage != DAMAGE_AIM) + if( pEdict->v.takedamage != DAMAGE_AIM ) continue; - if (pEdict == edict()) + if( pEdict == edict() ) continue; - //if (pev->team > 0 && pEdict->v.team == pev->team) + //if( pev->team > 0 && pEdict->v.team == pev->team ) // continue; // don't aim at teammate - if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) + if( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) continue; pEntity = Instance( pEdict ); - if (pEntity == NULL) + if( pEntity == NULL ) continue; - if (!pEntity->IsAlive()) + if( !pEntity->IsAlive() ) continue; // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) + if( ( pev->waterlevel != 3 && pEntity->pev->waterlevel == 3 ) || ( pev->waterlevel == 3 && pEntity->pev->waterlevel == 0 ) ) continue; center = pEntity->BodyTarget( vecSrc ); - dir = (center - vecSrc).Normalize( ); + dir = ( center - vecSrc ).Normalize(); // make sure it's in front of the player - if (DotProduct (dir, gpGlobals->v_forward ) < 0) + if( DotProduct( dir, gpGlobals->v_forward ) < 0 ) continue; - dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) - + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; + 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); + dot *= 1.0 + 0.2 * ( ( center - vecSrc ).Length() / flDist ); - if (dot > bestdot) + 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) + 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( IRelationship( pEntity ) < 0 ) { - if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) - // ALERT( at_console, "friend\n"); + if( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch() ) + // ALERT( at_console, "friend\n" ); continue; } @@ -4243,13 +4230,13 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD bestdir = dir; } - if (bestent) + if( bestent ) { - bestdir = UTIL_VecToAngles (bestdir); + bestdir = UTIL_VecToAngles( bestdir ); bestdir.x = -bestdir.x; bestdir = bestdir - pev->v_angle - pev->punchangle; - if (bestent->v.takedamage == DAMAGE_AIM) + if( bestent->v.takedamage == DAMAGE_AIM ) m_fOnTarget = TRUE; return bestdir; @@ -4258,9 +4245,9 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD return Vector( 0, 0, 0 ); } -void CBasePlayer :: ResetAutoaim( ) +void CBasePlayer::ResetAutoaim() { - if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) + if( m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0 ) { m_vecAutoAim = Vector( 0, 0, 0 ); SET_CROSSHAIRANGLE( edict(), 0, 0 ); @@ -4276,10 +4263,9 @@ SetCustomDecalFrames Note: -1 means no custom frames present. ============= */ -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) +void CBasePlayer::SetCustomDecalFrames( int nFrames ) { - if (nFrames > 0 && - nFrames < 8) + if( nFrames > 0 && nFrames < 8 ) m_nCustomSprayFrames = nFrames; else m_nCustomSprayFrames = -1; @@ -4292,7 +4278,7 @@ GetCustomDecalFrames Returns the # of custom frames this player's custom clan logo contains. ============= */ -int CBasePlayer :: GetCustomDecalFrames( void ) +int CBasePlayer::GetCustomDecalFrames( void ) { return m_nCustomSprayFrames; } @@ -4301,15 +4287,15 @@ int CBasePlayer :: GetCustomDecalFrames( void ) // DropPlayerItem - drop the named item, or if no name, // the active item. //========================================================= -void CBasePlayer::DropPlayerItem ( char *pszItemName ) +void CBasePlayer::DropPlayerItem( char *pszItemName ) { - if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) + if( !g_pGameRules->IsMultiplayer() || ( weaponstay.value > 0 ) ) { // no dropping in single player. return; } - if ( !strlen( pszItemName ) ) + if( !strlen( pszItemName ) ) { // if this string has no length, the client didn't type a name! // assume player wants to drop the active item. @@ -4320,16 +4306,16 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) CBasePlayerItem *pWeapon; int i; - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - pWeapon = m_rgpPlayerItems[ i ]; + pWeapon = m_rgpPlayerItems[i]; - while ( pWeapon ) + while( pWeapon ) { - if ( pszItemName ) + if( pszItemName ) { // try to match by name. - if ( !strcmp( pszItemName, STRING( pWeapon->pev->classname ) ) ) + if( !strcmp( pszItemName, STRING( pWeapon->pev->classname ) ) ) { // match! break; @@ -4338,7 +4324,7 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) else { // trying to drop active item - if ( pWeapon == m_pActiveItem ) + if( pWeapon == m_pActiveItem ) { // active item! break; @@ -4350,13 +4336,13 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) // 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( pWeapon ) { g_pGameRules->GetNextBestWeapon( this, pWeapon ); - UTIL_MakeVectors ( pev->angles ); + UTIL_MakeVectors( pev->angles ); - pev->weapons &= ~(1<m_iId);// take item off hud + pev->weapons &= ~( 1 << pWeapon->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; @@ -4365,24 +4351,24 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; // drop half of the ammo for this weapon. - int iAmmoIndex; + int iAmmoIndex; - iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? - - if ( iAmmoIndex != -1 ) + iAmmoIndex = GetAmmoIndex( pWeapon->pszAmmo1() ); // ??? + + if( iAmmoIndex != -1 ) { // this weapon weapon uses ammo, so pack an appropriate amount. - if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) + 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; + 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; + pWeaponBox->PackAmmo( MAKE_STRING( pWeapon->pszAmmo1() ), m_rgAmmo[iAmmoIndex] / 2 ); + m_rgAmmo[iAmmoIndex] /= 2; } } @@ -4398,9 +4384,9 @@ BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - while (pItem) + while( pItem ) { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) + if( FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname ) ) ) { return TRUE; } @@ -4418,13 +4404,13 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) CBasePlayerItem *pItem; int i; - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - pItem = m_rgpPlayerItems[ i ]; - - while (pItem) + pItem = m_rgpPlayerItems[i]; + + while( pItem ) { - if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) + if( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) { return TRUE; } @@ -4438,22 +4424,22 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) //========================================================= // //========================================================= -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) +BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon ) { - if ( !pWeapon->CanDeploy() ) + if( !pWeapon->CanDeploy() ) { return FALSE; } - ResetAutoaim( ); - - if (m_pActiveItem) + ResetAutoaim(); + + if( m_pActiveItem ) { - m_pActiveItem->Holster( ); + m_pActiveItem->Holster(); } m_pActiveItem = pWeapon; - pWeapon->Deploy( ); + pWeapon->Deploy(); return TRUE; } @@ -4465,24 +4451,33 @@ class CDeadHEV : public CBaseMonster { public: void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } + int Classify( void ) + { + return CLASS_HUMAN_MILITARY; + } void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display -- temporary, don't need to save + int m_iPose;// which sequence to display -- temporary, don't need to save static char *m_szPoses[4]; }; -char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; +char *CDeadHEV::m_szPoses[] = +{ + "deadback", + "deadsitting", + "deadstomach", + "deadtable" +}; void CDeadHEV::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "pose")) + if( FStrEq( pkvd->szKeyName, "pose" ) ) { - m_iPose = atoi(pkvd->szValue); + m_iPose = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else + else CBaseMonster::KeyValue( pkvd ); } @@ -4491,28 +4486,28 @@ LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ) //========================================================= // ********** DeadHEV SPAWN ********** //========================================================= -void CDeadHEV :: Spawn( void ) +void CDeadHEV::Spawn( void ) { - PRECACHE_MODEL("models/player.mdl"); - SET_MODEL(ENT(pev), "models/player.mdl"); + 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->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) + if( pev->sequence == -1 ) { - ALERT ( at_console, "Dead hevsuit with bad pose\n" ); + ALERT( at_console, "Dead hevsuit with bad pose\n" ); pev->sequence = 0; pev->effects = EF_BRIGHTFIELD; } // Corpses have less health - pev->health = 8; + pev->health = 8; MonsterInitDead(); } @@ -4520,55 +4515,55 @@ void CDeadHEV :: Spawn( void ) class CStripWeapons : public CPointEntity { public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + 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 ) +void CStripWeapons::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CBasePlayer *pPlayer = NULL; - if ( pActivator && pActivator->IsPlayer() ) + if( pActivator && pActivator->IsPlayer() ) { pPlayer = (CBasePlayer *)pActivator; } - else if ( !g_pGameRules->IsDeathmatch() ) + else if( !g_pGameRules->IsDeathmatch() ) { pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); } - if ( pPlayer ) + 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 ); + 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[]; + 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 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; } + 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; + float m_messageTime; + float m_loadTime; }; LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ) @@ -4581,44 +4576,44 @@ TYPEDESCRIPTION CRevertSaved::m_SaveData[] = IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ) -void CRevertSaved :: KeyValue( KeyValueData *pkvd ) +void CRevertSaved::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "duration")) + if( FStrEq( pkvd->szKeyName, "duration" ) ) { - SetDuration( atof(pkvd->szValue) ); + SetDuration( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "holdtime")) + else if( FStrEq( pkvd->szKeyName, "holdtime" ) ) { - SetHoldTime( atof(pkvd->szValue) ); + SetHoldTime( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "messagetime")) + else if( FStrEq( pkvd->szKeyName, "messagetime" ) ) { - SetMessageTime( atof(pkvd->szValue) ); + SetMessageTime( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "loadtime")) + else if( FStrEq( pkvd->szKeyName, "loadtime" ) ) { - SetLoadTime( atof(pkvd->szValue) ); + SetLoadTime( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else + else CPointEntity::KeyValue( pkvd ); } -void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CRevertSaved::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); pev->nextthink = gpGlobals->time + MessageTime(); SetThink( &CRevertSaved::MessageThink ); } -void CRevertSaved :: MessageThink( void ) +void CRevertSaved::MessageThink( void ) { - UTIL_ShowMessageAll( STRING(pev->message) ); + UTIL_ShowMessageAll( STRING( pev->message ) ); float nextThink = LoadTime() - MessageTime(); - if ( nextThink > 0 ) + if( nextThink > 0 ) { pev->nextthink = gpGlobals->time + nextThink; SetThink( &CRevertSaved::LoadThink ); @@ -4627,11 +4622,11 @@ void CRevertSaved :: MessageThink( void ) LoadThink(); } -void CRevertSaved :: LoadThink( void ) +void CRevertSaved::LoadThink( void ) { - if ( !gpGlobals->deathmatch ) + if( !gpGlobals->deathmatch ) { - SERVER_COMMAND("reload\n"); + SERVER_COMMAND( "reload\n" ); } } @@ -4654,16 +4649,16 @@ void CInfoIntermission::Spawn( void ) pev->nextthink = gpGlobals->time + 2;// let targets spawn! } -void CInfoIntermission::Think ( void ) +void CInfoIntermission::Think( void ) { edict_t *pTarget; // find my target - pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); + pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ); - if ( !FNullEnt(pTarget) ) + if( !FNullEnt( pTarget ) ) { - pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() ); + pev->v_angle = UTIL_VecToAngles( ( pTarget->v.origin - pev->origin ).Normalize() ); pev->v_angle.x = -pev->v_angle.x; } } diff --git a/dlls/playermonster.cpp b/dlls/playermonster.cpp index 9a5bf898..cd3484ab 100644 --- a/dlls/playermonster.cpp +++ b/dlls/playermonster.cpp @@ -28,9 +28,9 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); + int ISoundMask( void ); }; LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ) @@ -39,20 +39,20 @@ LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CPlayerMonster :: Classify ( void ) +int CPlayerMonster::Classify( void ) { - return CLASS_PLAYER_ALLY; + return CLASS_PLAYER_ALLY; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CPlayerMonster :: SetYawSpeed ( void ) +void CPlayerMonster::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: default: @@ -80,30 +80,30 @@ void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // ISoundMask - player monster can't hear. //========================================================= -int CPlayerMonster :: ISoundMask ( void ) +int CPlayerMonster::ISoundMask( void ) { - return NULL; + return NULL; } //========================================================= // Spawn //========================================================= -void CPlayerMonster :: Spawn() +void CPlayerMonster::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + 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; + 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 ) + if( pev->spawnflags & SF_MONSTERPLAYER_NOTSOLID ) { pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; @@ -113,10 +113,10 @@ void CPlayerMonster :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CPlayerMonster :: Precache() +void CPlayerMonster::Precache() { - PRECACHE_MODEL("models/player.mdl"); -} + PRECACHE_MODEL( "models/player.mdl" ); +} //========================================================= // AI Schedules Specific to this monster diff --git a/dlls/python.cpp b/dlls/python.cpp index a49d0015..7bb71325 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -22,8 +22,8 @@ #include "player.h" #include "gamerules.h" - -enum python_e { +enum python_e +{ PYTHON_IDLE1 = 0, PYTHON_FIDGET, PYTHON_FIRE1, @@ -37,9 +37,9 @@ enum python_e { LINK_ENTITY_TO_CLASS( weapon_python, CPython ) LINK_ENTITY_TO_CLASS( weapon_357, CPython ) -int CPython::GetItemInfo(ItemInfo *p) +int CPython::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "357"; p->iMaxAmmo1 = _357_MAX_CARRY; p->pszAmmo2 = NULL; @@ -56,7 +56,7 @@ int CPython::GetItemInfo(ItemInfo *p) int CPython::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -66,12 +66,12 @@ int CPython::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -void CPython::Spawn( ) +void CPython::Spawn() { - pev->classname = MAKE_STRING("weapon_357"); // hack to allow for old names - Precache( ); + 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"); + SET_MODEL( ENT( pev ), "models/w_357.mdl" ); m_iDefaultAmmo = PYTHON_DEFAULT_GIVE; @@ -80,27 +80,27 @@ void CPython::Spawn( ) 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/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_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"); + 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( ) +BOOL CPython::Deploy() { #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { // enable laser sight geometry. @@ -118,7 +118,7 @@ void CPython::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. - if ( m_fInZoom ) + if( m_fInZoom ) { SecondaryAttack(); } @@ -131,20 +131,20 @@ void CPython::Holster( int skiplocal /* = 0 */ ) void CPython::SecondaryAttack( void ) { #ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) + if( !bIsMultiplayer() ) #else - if ( !g_pGameRules->IsMultiplayer() ) + if( !g_pGameRules->IsMultiplayer() ) #endif { return; } - if ( m_pPlayer->pev->fov != 0 ) + 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 ) + else if( m_pPlayer->pev->fov != 40 ) { m_fInZoom = TRUE; m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; @@ -156,20 +156,20 @@ void CPython::SecondaryAttack( void ) void CPython::PrimaryAttack() { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { - PlayEmptySound( ); + PlayEmptySound(); m_flNextPrimaryAttack = 0.15; return; } - if (m_iClip <= 0) + if( m_iClip <= 0 ) { - if (!m_fFireOnEmpty) - Reload( ); + if( !m_fFireOnEmpty ) + Reload(); else { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM ); m_flNextPrimaryAttack = 0.15; } @@ -181,14 +181,14 @@ void CPython::PrimaryAttack() m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + 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 vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); Vector vecDir; @@ -202,9 +202,9 @@ void CPython::PrimaryAttack() #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) + 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_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); m_flNextPrimaryAttack = 0.75; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); @@ -212,10 +212,10 @@ void CPython::PrimaryAttack() void CPython::Reload( void ) { - if ( m_pPlayer->ammo_357 <= 0 ) + if( m_pPlayer->ammo_357 <= 0 ) return; - if ( m_pPlayer->pev->fov != 0 ) + if( m_pPlayer->pev->fov != 0 ) { m_fInZoom = FALSE; m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov @@ -227,8 +227,7 @@ void CPython::Reload( void ) #else bUseScope = g_pGameRules->IsMultiplayer(); #endif - - if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) + if( DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope ) ) { m_flSoundDelay = 1.5; } @@ -236,41 +235,41 @@ void CPython::Reload( void ) void CPython::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) + if( m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT( 0.8, 0.9 ), ATTN_NORM ); m_flSoundDelay = 0; } - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0f, 1.0f ); - if (flRand <= 0.5) + if( flRand <= 0.5 ) { iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (70.0/30.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 70.0 / 30.0 ); } - else if (flRand <= 0.7) + else if( flRand <= 0.7 ) { iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/30.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 60.0 / 30.0 ); } - else if (flRand <= 0.9) + else if( flRand <= 0.9 ) { iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (88.0/30.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 88.0 / 30.0 ); } else { iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (170.0/30.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 170.0 / 30.0 ); } int bUseScope = FALSE; @@ -279,7 +278,6 @@ void CPython::WeaponIdle( void ) #else bUseScope = g_pGameRules->IsMultiplayer(); #endif - SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); } @@ -287,20 +285,20 @@ class CPythonAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_357ammobox.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + PRECACHE_MODEL( "models/w_357ammobox.mdl" ); + PRECACHE_SOUND( "items/9mmclip1.wav" ); } - BOOL AddAmmo( CBaseEntity *pOther ) + BOOL AddAmmo( CBaseEntity *pOther ) { - if (pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1) + if( pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1 ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; diff --git a/dlls/rat.cpp b/dlls/rat.cpp index 3676d9e5..dd9a5905 100644 --- a/dlls/rat.cpp +++ b/dlls/rat.cpp @@ -32,7 +32,7 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify( void ); }; LINK_ENTITY_TO_CLASS( monster_rat, CRat ) @@ -41,20 +41,20 @@ LINK_ENTITY_TO_CLASS( monster_rat, CRat ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CRat :: Classify ( void ) +int CRat::Classify( void ) { - return CLASS_INSECT; + return CLASS_INSECT; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CRat :: SetYawSpeed ( void ) +void CRat::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: default: @@ -68,20 +68,20 @@ void CRat :: SetYawSpeed ( void ) //========================================================= // Spawn //========================================================= -void CRat :: Spawn() +void CRat::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/bigrat.mdl"); + 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; + 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(); } @@ -89,10 +89,10 @@ void CRat :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CRat :: Precache() +void CRat::Precache() { - PRECACHE_MODEL("models/bigrat.mdl"); -} + PRECACHE_MODEL( "models/bigrat.mdl" ); +} //========================================================= // AI Schedules Specific to this monster diff --git a/dlls/roach.cpp b/dlls/roach.cpp index 78ff1c19..692b4beb 100644 --- a/dlls/roach.cpp +++ b/dlls/roach.cpp @@ -16,20 +16,20 @@ // cockroach //========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "soundent.h" -#include "decals.h" +#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 +#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 @@ -41,22 +41,23 @@ public: void Precache( void ); void SetYawSpeed( void ); void EXPORT MonsterThink ( void ); - void Move ( float flInterval ); - void PickNewDest ( int iCondition ); - void EXPORT Touch ( CBaseEntity *pOther ); + 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 ); - + 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; + BOOL m_fLightHacked; + int m_iMode; // ----------------------------- }; + LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ) //========================================================= @@ -64,16 +65,16 @@ LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ) // of sounds this monster regards. In the base class implementation, // monsters care about all sounds, but no scents. //========================================================= -int CRoach :: ISoundMask ( void ) +int CRoach::ISoundMask( void ) { - return bits_SOUND_CARCASS | bits_SOUND_MEAT; + return bits_SOUND_CARCASS | bits_SOUND_MEAT; } //========================================================= // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CRoach :: Classify ( void ) +int CRoach::Classify( void ) { return CLASS_INSECT; } @@ -81,21 +82,21 @@ int CRoach :: Classify ( void ) //========================================================= // Touch //========================================================= -void CRoach :: Touch ( CBaseEntity *pOther ) +void CRoach::Touch( CBaseEntity *pOther ) { - Vector vecSpot; - TraceResult tr; + Vector vecSpot; + TraceResult tr; - if ( pOther->pev->velocity == g_vecZero || !pOther->IsPlayer() ) + 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); + 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) ); + UTIL_DecalTrace( &tr, DECAL_YBLOOD1 + RANDOM_LONG( 0, 5 ) ); TakeDamage( pOther->pev, pOther->pev, pev->health, DMG_CRUSH ); } @@ -104,7 +105,7 @@ void CRoach :: Touch ( CBaseEntity *pOther ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CRoach :: SetYawSpeed ( void ) +void CRoach::SetYawSpeed( void ) { int ys; @@ -116,66 +117,65 @@ void CRoach :: SetYawSpeed ( void ) //========================================================= // Spawn //========================================================= -void CRoach :: Spawn() +void CRoach::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/roach.mdl"); + 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; + 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 ); + 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; + 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() +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"); -} + 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 ) +void CRoach::Killed( entvars_t *pevAttacker, int iGib ) { pev->solid = SOLID_NOT; //random sound - if ( RANDOM_LONG(0,4) == 1 ) + 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) ); + 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) ); + 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 ); + CSoundEnt::InsertSound( bits_SOUND_WORLD, pev->origin, 128, 1 ); - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); + if( pOwner ) { pOwner->DeathNotice( pev ); } @@ -185,16 +185,16 @@ void CRoach :: Killed( entvars_t *pevAttacker, int iGib ) //========================================================= // MonsterThink, overridden for roaches. //========================================================= -void CRoach :: MonsterThink( void ) +void CRoach::MonsterThink( void ) { - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); + 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 + float flInterval = StudioFrameAdvance(); // animate - if ( !m_fLightHacked ) + 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. @@ -202,89 +202,89 @@ void CRoach :: MonsterThink( void ) m_fLightHacked = TRUE; return; } - else if ( m_flLastLightLevel < 0 ) + 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 ) + switch( m_iMode ) { - case ROACH_IDLE: - case ROACH_EAT: + 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 ) + if( RANDOM_LONG( 0, 3 ) == 1 ) { Look( 150 ); - if (HasConditions(bits_COND_SEE_FEAR)) + 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 + //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 ); + SetActivity( ACT_WALK ); } - else if ( RANDOM_LONG(0,149) == 1 ) + 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" ); + //ALERT( at_aiconsole, "Bored\n" ); PickNewDest( ROACH_BORED ); - SetActivity ( ACT_WALK ); + SetActivity( ACT_WALK ); - if ( m_iMode == ROACH_EAT ) + 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) ) ); + Eat( 30 + ( RANDOM_LONG( 0, 14 ) ) ); } } } - + // don't do this stuff if eating! - if ( m_iMode == ROACH_IDLE ) + if( m_iMode == ROACH_IDLE ) { - if ( FShouldEat() ) + if( FShouldEat() ) { Listen(); } - if ( GETENTITYILLUM( ENT(pev) ) > m_flLastLightLevel ) + if( GETENTITYILLUM( ENT( pev ) ) > m_flLastLightLevel ) { // someone turned on lights! - //ALERT ( at_console, "Lights!\n" ); + //ALERT( at_console, "Lights!\n" ); PickNewDest( ROACH_SCARED_BY_LIGHT ); - SetActivity ( ACT_WALK ); + SetActivity( ACT_WALK ); } - else if ( HasConditions(bits_COND_SMELL_FOOD) ) + 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 && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) + if( pSound && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) { PickNewDest( ROACH_SMELL_FOOD ); - SetActivity ( ACT_WALK ); + SetActivity( ACT_WALK ); } } } break; } - case ROACH_SCARED_BY_LIGHT: + 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 ) + if( GETENTITYILLUM( ENT( pev ) ) <= m_flLastLightLevel ) { - SetActivity ( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// make this our new light level. + SetActivity( ACT_IDLE ); + m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) );// make this our new light level. } break; } } - - if ( m_flGroundSpeed != 0 ) + + if( m_flGroundSpeed != 0 ) { Move( flInterval ); } @@ -293,93 +293,93 @@ void CRoach :: MonsterThink( void ) //========================================================= // Picks a new spot for roach to run to.( //========================================================= -void CRoach :: PickNewDest ( int iCondition ) +void CRoach::PickNewDest( int iCondition ) { - Vector vecNewDir; - Vector vecDest; - float flDist; + Vector vecNewDir; + Vector vecDest; + float flDist; m_iMode = iCondition; - if ( m_iMode == ROACH_SMELL_FOOD ) + if( m_iMode == ROACH_SMELL_FOOD ) { // find the food and go there. CSound *pSound; pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - if ( pSound ) + 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 ); + 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 + 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) ); + flDist = 256 + ( RANDOM_LONG( 0, 255 ) ); vecDest = pev->origin + vecNewDir * flDist; - } while ( ( vecDest - pev->origin ).Length2D() < 128 ); + } 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 ); + 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 ) + 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) ); + 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 ) +void CRoach::Move( float flInterval ) { - float flWaypointDist; - Vector vecApex; + float flWaypointDist; + Vector vecApex; // local move to waypoint. - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); - MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); + flWaypointDist = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Length2D(); + MakeIdealYaw( m_Route[m_iRouteIndex].vecLocation ); - ChangeYaw ( pev->yaw_speed ); + ChangeYaw( pev->yaw_speed ); UTIL_MakeVectors( pev->angles ); - if ( RANDOM_LONG(0,7) == 1 ) + 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 ) ) + 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 ); + 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 ) + 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 + SetActivity( ACT_IDLE ); + m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) );// this is roach's new comfortable light level - if ( m_iMode == ROACH_SMELL_FOOD ) + if( m_iMode == ROACH_SMELL_FOOD ) { m_iMode = ROACH_EAT; } @@ -389,7 +389,7 @@ void CRoach :: Move ( float flInterval ) } } - if ( RANDOM_LONG(0,149) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD ) + 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 ); @@ -400,18 +400,18 @@ void CRoach :: Move ( float flInterval ) // Look - overriden for the roach, which can virtually see // 360 degrees. //========================================================= -void CRoach :: Look ( int iDistance ) +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; + 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 ); + 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() ) ) ) + if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { return; } @@ -422,12 +422,12 @@ void CRoach :: Look ( int iDistance ) // 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) + 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( pSightEnt->IsPlayer() || FBitSet( pSightEnt->pev->flags, FL_MONSTER ) ) { - if ( /*FVisible( pSightEnt ) &&*/ !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && pSightEnt->pev->health > 0 ) + 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. @@ -437,15 +437,15 @@ void CRoach :: Look ( int iDistance ) // 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 ) ) + switch( IRelationship( pSightEnt ) ) { - case R_FR: + case R_FR: iSighted |= bits_COND_SEE_FEAR; break; - case R_NO: + case R_NO: break; default: - ALERT ( at_console, "%s can't asses %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); + ALERT( at_console, "%s can't asses %s\n", STRING( pev->classname ), STRING( pSightEnt->pev->classname ) ); break; } } @@ -457,4 +457,3 @@ void CRoach :: Look ( int iDistance ) //========================================================= // AI Schedules Specific to this monster //========================================================= - diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 093faf38..1fec5cf1 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -23,10 +23,8 @@ #include "player.h" #include "gamerules.h" - - - -enum rpg_e { +enum rpg_e +{ RPG_IDLE = 0, RPG_FIDGET, RPG_RELOAD, // to reload @@ -52,7 +50,7 @@ CLaserSpot *CLaserSpot::CreateSpot( void ) CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); pSpot->Spawn(); - pSpot->pev->classname = MAKE_STRING("laser_spot"); + pSpot->pev->classname = MAKE_STRING( "laser_spot" ); return pSpot; } @@ -61,7 +59,7 @@ CLaserSpot *CLaserSpot::CreateSpot( void ) //========================================================= void CLaserSpot::Spawn( void ) { - Precache( ); + Precache(); pev->movetype = MOVETYPE_NONE; pev->solid = SOLID_NOT; @@ -69,7 +67,7 @@ void CLaserSpot::Spawn( void ) pev->renderfx = kRenderFxNoDissipation; pev->renderamt = 255; - SET_MODEL(ENT(pev), "sprites/laserdot.spr"); + SET_MODEL( ENT( pev ), "sprites/laserdot.spr" ); UTIL_SetOrigin( pev, pev->origin ); } @@ -79,7 +77,7 @@ void CLaserSpot::Spawn( void ) void CLaserSpot::Suspend( float flSuspendTime ) { pev->effects |= EF_NODRAW; - + SetThink( &CLaserSpot::Revive ); pev->nextthink = gpGlobals->time + flSuspendTime; } @@ -96,7 +94,7 @@ void CLaserSpot::Revive( void ) void CLaserSpot::Precache( void ) { - PRECACHE_MODEL("sprites/laserdot.spr"); + PRECACHE_MODEL( "sprites/laserdot.spr" ); } LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ) @@ -120,25 +118,25 @@ CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBa //========================================================= //========================================================= -void CRpgRocket :: Spawn( void ) +void CRpgRocket::Spawn( void ) { - Precache( ); + 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)); + 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"); + pev->classname = MAKE_STRING( "rpg_rocket" ); SetThink( &CRpgRocket::IgniteThink ); SetTouch( &CGrenade::ExplodeTouch ); pev->angles.x -= 30; UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x + 30); + pev->angles.x = -( pev->angles.x + 30 ); pev->velocity = gpGlobals->v_forward * 250; pev->gravity = 0.5; @@ -150,9 +148,9 @@ void CRpgRocket :: Spawn( void ) //========================================================= //========================================================= -void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) +void CRpgRocket::RocketTouch( CBaseEntity *pOther ) { - if ( m_pLauncher ) + if( m_pLauncher ) { // my launcher is still around, tell it I'm dead. m_pLauncher->m_cActiveRockets--; @@ -164,15 +162,14 @@ void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) //========================================================= //========================================================= -void CRpgRocket :: Precache( void ) +void CRpgRocket::Precache( void ) { - PRECACHE_MODEL("models/rpgrocket.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); + PRECACHE_MODEL( "models/rpgrocket.mdl" ); + m_iTrail = PRECACHE_MODEL( "sprites/smoke.spr" ); + PRECACHE_SOUND( "weapons/rocket1.wav" ); } - -void CRpgRocket :: IgniteThink( void ) +void CRpgRocket::IgniteThink( void ) { // pev->movetype = MOVETYPE_TOSS; @@ -180,21 +177,19 @@ void CRpgRocket :: IgniteThink( void ) pev->effects |= EF_LIGHT; // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); + 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_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; @@ -204,7 +199,7 @@ void CRpgRocket :: IgniteThink( void ) pev->nextthink = gpGlobals->time + 0.1; } -void CRpgRocket :: FollowThink( void ) +void CRpgRocket::FollowThink( void ) { CBaseEntity *pOther = NULL; Vector vecTarget; @@ -218,19 +213,19 @@ void CRpgRocket :: FollowThink( void ) flMax = 4096; // Examine all entities within a reasonable radius - while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL) + while( ( pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" ) ) != NULL ) { - UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); + 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) + if( tr.flFraction >= 0.90 ) { vecDir = pOther->pev->origin - pev->origin; - flDist = vecDir.Length( ); - vecDir = vecDir.Normalize( ); + flDist = vecDir.Length(); + vecDir = vecDir.Normalize(); flDot = DotProduct( gpGlobals->v_forward, vecDir ); - if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) + if( ( flDot > 0 ) && ( flDist * ( 1 - flDot ) < flMax ) ) { - flMax = flDist * (1 - flDot); + flMax = flDist * ( 1 - flDot ); vecTarget = vecDir; } } @@ -240,13 +235,13 @@ void CRpgRocket :: FollowThink( void ) // 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) + if( gpGlobals->time - m_flIgniteTime < 1.0 ) { - pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); - if (pev->waterlevel == 3) + pev->velocity = pev->velocity * 0.2 + vecTarget * ( flSpeed * 0.8 + 400 ); + if( pev->waterlevel == 3 ) { // go slow underwater - if (pev->velocity.Length() > 300) + if( pev->velocity.Length() > 300 ) { pev->velocity = pev->velocity.Normalize() * 300; } @@ -254,7 +249,7 @@ void CRpgRocket :: FollowThink( void ) } else { - if (pev->velocity.Length() > 2000) + if( pev->velocity.Length() > 2000 ) { pev->velocity = pev->velocity.Normalize() * 2000; } @@ -262,15 +257,15 @@ void CRpgRocket :: FollowThink( void ) } else { - if (pev->effects & EF_LIGHT) + if( pev->effects & EF_LIGHT ) { pev->effects = 0; - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav" ); + 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) + if( pev->waterlevel == 0 && pev->velocity.Length() < 1500 ) { - Detonate( ); + Detonate(); } } // ALERT( at_console, "%.0f\n", flSpeed ); @@ -283,13 +278,13 @@ void CRpg::Reload( void ) { int iResult = 0; - if ( m_iClip == 1 ) + if( m_iClip == 1 ) { // don't bother with any of this if don't need to reload. return; } - if ( m_pPlayer->ammo_rockets <= 0 ) + if( m_pPlayer->ammo_rockets <= 0 ) return; // because the RPG waits to autoreload when no missiles are active while the LTD is on, the @@ -304,7 +299,7 @@ void CRpg::Reload( void ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - if ( m_cActiveRockets && m_fSpotActive ) + 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. @@ -312,33 +307,32 @@ void CRpg::Reload( void ) } #ifndef CLIENT_DLL - if ( m_pSpot && m_fSpotActive ) + if( m_pSpot && m_fSpotActive ) { m_pSpot->Suspend( 2.1 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; } #endif - if ( m_iClip == 0 ) + if( m_iClip == 0 ) iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); - - if ( iResult ) + + if( iResult ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } -void CRpg::Spawn( ) +void CRpg::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_RPG; - SET_MODEL(ENT(pev), "models/w_rpg.mdl"); + SET_MODEL( ENT( pev ), "models/w_rpg.mdl" ); m_fSpotActive = 1; #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { // more default ammo in multiplay. @@ -354,25 +348,24 @@ void CRpg::Spawn( ) void CRpg::Precache( void ) { - PRECACHE_MODEL("models/w_rpg.mdl"); - PRECACHE_MODEL("models/v_rpg.mdl"); - PRECACHE_MODEL("models/p_rpg.mdl"); + PRECACHE_MODEL( "models/w_rpg.mdl" ); + PRECACHE_MODEL( "models/v_rpg.mdl" ); + PRECACHE_MODEL( "models/p_rpg.mdl" ); - PRECACHE_SOUND("items/9mmclip1.wav"); + 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 + PRECACHE_SOUND( "weapons/rocketfire1.wav" ); + PRECACHE_SOUND( "weapons/glauncher.wav" ); // alternative fire sound - m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); + m_usRpg = PRECACHE_EVENT( 1, "events/rpg.sc" ); } - -int CRpg::GetItemInfo(ItemInfo *p) +int CRpg::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "rockets"; p->iMaxAmmo1 = ROCKET_MAX_CARRY; p->pszAmmo2 = NULL; @@ -389,7 +382,7 @@ int CRpg::GetItemInfo(ItemInfo *p) int CRpg::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -399,9 +392,9 @@ int CRpg::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -BOOL CRpg::Deploy( ) +BOOL CRpg::Deploy() { - if ( m_iClip == 0 ) + if( m_iClip == 0 ) { return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" ); } @@ -411,7 +404,7 @@ BOOL CRpg::Deploy( ) BOOL CRpg::CanHolster( void ) { - if ( m_fSpotActive && m_cActiveRockets ) + if( m_fSpotActive && m_cActiveRockets ) { // can't put away while guiding a missile. return FALSE; @@ -425,11 +418,11 @@ 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) + if( m_pSpot ) { m_pSpot->Killed( NULL, GIB_NEVER ); m_pSpot = NULL; @@ -439,7 +432,7 @@ void CRpg::Holster( int skiplocal /* = 0 */ ) void CRpg::PrimaryAttack() { - if ( m_iClip ) + if( m_iClip ) { m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; @@ -449,8 +442,8 @@ void CRpg::PrimaryAttack() 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; - + 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. @@ -466,28 +459,27 @@ void CRpg::PrimaryAttack() #else flags = 0; #endif - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); m_iClip--; - + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } else { - PlayEmptySound( ); + PlayEmptySound(); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; } - UpdateSpot( ); + UpdateSpot(); } void CRpg::SecondaryAttack() { - m_fSpotActive = ! m_fSpotActive; + m_fSpotActive = !m_fSpotActive; #ifndef CLIENT_DLL - if (!m_fSpotActive && m_pSpot) + if( !m_fSpotActive && m_pSpot ) { m_pSpot->Killed( NULL, GIB_NORMAL ); m_pSpot = NULL; @@ -498,20 +490,20 @@ void CRpg::SecondaryAttack() void CRpg::WeaponIdle( void ) { - UpdateSpot( ); + UpdateSpot(); - ResetEmptySound( ); + ResetEmptySound(); - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + 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( flRand <= 0.75 || m_fSpotActive ) { - if ( m_iClip == 0 ) + if( m_iClip == 0 ) iAnim = RPG_IDLE_UL; else iAnim = RPG_IDLE; @@ -520,7 +512,7 @@ void CRpg::WeaponIdle( void ) } else { - if ( m_iClip == 0 ) + if( m_iClip == 0 ) iAnim = RPG_FIDGET_UL; else iAnim = RPG_FIDGET; @@ -539,20 +531,20 @@ void CRpg::WeaponIdle( void ) void CRpg::UpdateSpot( void ) { #ifndef CLIENT_DLL - if (m_fSpotActive) + if( m_fSpotActive ) { - if (!m_pSpot) + if( !m_pSpot ) { m_pSpot = CLaserSpot::CreateSpot(); } UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( );; + 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_TraceLine( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); + UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); } #endif @@ -561,24 +553,23 @@ void CRpg::UpdateSpot( void ) class CRpgAmmo : public CBasePlayerAmmo { void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_rpgammo.mdl"); - CBasePlayerAmmo::Spawn( ); + { + 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"); + PRECACHE_MODEL( "models/w_rpgammo.mdl" ); + PRECACHE_SOUND( "items/9mmclip1.wav" ); } BOOL AddAmmo( CBaseEntity *pOther ) { int iGive; - #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { // hand out more ammo per rocket in multiplayer. @@ -589,9 +580,9 @@ class CRpgAmmo : public CBasePlayerAmmo iGive = AMMO_RPGCLIP_GIVE; } - if (pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1) + if( pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1 ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index ed1f8216..48ec5b9a 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -23,14 +23,16 @@ #include "player.h" #include "gamerules.h" -enum satchel_e { +enum satchel_e +{ SATCHEL_IDLE1 = 0, SATCHEL_FIDGET1, SATCHEL_DRAW, SATCHEL_DROP }; -enum satchel_radio_e { +enum satchel_radio_e +{ SATCHEL_RADIO_IDLE1 = 0, SATCHEL_RADIO_FIDGET1, SATCHEL_RADIO_DRAW, @@ -63,16 +65,16 @@ void CSatchelCharge::Deactivate( void ) UTIL_Remove( this ); } -void CSatchelCharge :: Spawn( void ) +void CSatchelCharge::Spawn( void ) { - Precache( ); + 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 + 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 ); @@ -84,58 +86,58 @@ void CSatchelCharge :: Spawn( void ) pev->friction = 0.8; pev->dmg = gSkillData.plrDmgSatchel; - // ResetSequenceInfo( ); + // ResetSequenceInfo(); pev->sequence = 1; } void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + entvars_t *pevOther = pOther->pev; // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) + if( pOther->edict() == pev->owner ) return; - // pev->avelocity = Vector (300, 300, 300); + // 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 ); + UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 10 ), ignore_monsters, edict(), &tr ); - if ( tr.flFraction < 1.0 ) + 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 ) + if( !( pev->flags & FL_ONGROUND ) && pev->velocity.Length2D() > 10 ) { BounceSound(); } - StudioFrameAdvance( ); + StudioFrameAdvance(); } -void CSatchelCharge :: SatchelThink( void ) +void CSatchelCharge::SatchelThink( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if (!IsInWorld()) + if( !IsInWorld() ) { UTIL_Remove( this ); return; } - if (pev->waterlevel == 3) + 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) + else if( pev->waterlevel == 0 ) { pev->movetype = MOVETYPE_BOUNCE; } @@ -145,21 +147,27 @@ void CSatchelCharge :: SatchelThink( void ) } } -void CSatchelCharge :: Precache( void ) +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"); + 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 ) +void CSatchelCharge::BounceSound( void ) { - switch ( RANDOM_LONG( 0, 2 ) ) + 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; + 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; } } @@ -173,21 +181,21 @@ int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) CSatchel *pSatchel; #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { pSatchel = (CSatchel *)pOriginal; - if ( pSatchel->m_chargeReady != 0 ) + if( pSatchel->m_chargeReady != 0 ) { // player has some satchels deployed. Refuse to add more. return FALSE; } } - return CBasePlayerWeapon::AddDuplicate ( pOriginal ); + return CBasePlayerWeapon::AddDuplicate( pOriginal ); } //========================================================= @@ -196,21 +204,21 @@ int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) { int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - pPlayer->pev->weapons |= (1<pev->weapons |= ( 1 << m_iId ); m_chargeReady = 0;// this satchel charge weapon now forgets that any satchels are deployed by it. - if ( bResult ) + if( bResult ) { - return AddWeapon( ); + return AddWeapon(); } return FALSE; } -void CSatchel::Spawn( ) +void CSatchel::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_SATCHEL; - SET_MODEL(ENT(pev), "models/w_satchel.mdl"); + SET_MODEL( ENT( pev ), "models/w_satchel.mdl" ); m_iDefaultAmmo = SATCHEL_DEFAULT_GIVE; @@ -219,18 +227,18 @@ void CSatchel::Spawn( ) void CSatchel::Precache( void ) { - PRECACHE_MODEL("models/v_satchel.mdl"); - PRECACHE_MODEL("models/v_satchel_radio.mdl"); - PRECACHE_MODEL("models/w_satchel.mdl"); - PRECACHE_MODEL("models/p_satchel.mdl"); - PRECACHE_MODEL("models/p_satchel_radio.mdl"); + PRECACHE_MODEL( "models/v_satchel.mdl" ); + PRECACHE_MODEL( "models/v_satchel_radio.mdl" ); + PRECACHE_MODEL( "models/w_satchel.mdl" ); + PRECACHE_MODEL( "models/p_satchel.mdl" ); + PRECACHE_MODEL( "models/p_satchel_radio.mdl" ); UTIL_PrecacheOther( "monster_satchel" ); } -int CSatchel::GetItemInfo(ItemInfo *p) +int CSatchel::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "Satchel Charge"; p->iMaxAmmo1 = SATCHEL_MAX_CARRY; p->pszAmmo2 = NULL; @@ -249,13 +257,13 @@ int CSatchel::GetItemInfo(ItemInfo *p) //========================================================= BOOL CSatchel::IsUseable( void ) { - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) + if( m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] > 0 ) { // player is carrying some satchels return TRUE; } - if ( m_chargeReady != 0 ) + if( m_chargeReady != 0 ) { // player isn't carrying any satchels, but has some out return TRUE; @@ -266,13 +274,13 @@ BOOL CSatchel::IsUseable( void ) BOOL CSatchel::CanDeploy( void ) { - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) + if( m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] > 0 ) { // player is carrying some satchels return TRUE; } - if ( m_chargeReady != 0 ) + if( m_chargeReady != 0 ) { // player isn't carrying any satchels, but has some out return TRUE; @@ -281,17 +289,15 @@ BOOL CSatchel::CanDeploy( void ) return FALSE; } -BOOL CSatchel::Deploy( ) +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 ) + 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; } @@ -299,8 +305,8 @@ BOOL CSatchel::Deploy( ) void CSatchel::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_chargeReady ) + + if( m_chargeReady ) { SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); } @@ -308,11 +314,11 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) { SendWeaponAnim( SATCHEL_DROP ); } - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) + if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) { - m_pPlayer->pev->weapons &= ~(1<pev->weapons &= ~( 1 << WEAPON_SATCHEL ); SetThink( &CBasePlayerItem::DestroyItem ); pev->nextthink = gpGlobals->time + 0.1; } @@ -320,26 +326,26 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) void CSatchel::PrimaryAttack() { - switch (m_chargeReady) + switch( m_chargeReady ) { case 0: { - Throw( ); + Throw(); } break; case 1: { SendWeaponAnim( SATCHEL_RADIO_FIRE ); - edict_t *pPlayer = m_pPlayer->edict( ); + edict_t *pPlayer = m_pPlayer->edict(); CBaseEntity *pSatchel = NULL; - while ((pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL) + while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 ) ) != NULL ) { - if (FClassnameIs( pSatchel->pev, "monster_satchel")) + if( FClassnameIs( pSatchel->pev, "monster_satchel" ) ) { - if (pSatchel->pev->owner == pPlayer) + if( pSatchel->pev->owner == pPlayer ) { pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); m_chargeReady = 2; @@ -355,37 +361,35 @@ void CSatchel::PrimaryAttack() } case 2: // we're reloading, don't allow fire - { - } break; } } void CSatchel::SecondaryAttack( void ) { - if ( m_chargeReady != 2 ) + if( m_chargeReady != 2 ) { - Throw( ); + Throw(); } } void CSatchel::Throw( void ) { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { Vector vecSrc = m_pPlayer->pev->origin; Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; #ifndef CLIENT_DLL - CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), m_pPlayer->edict() ); + 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"); + 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 ); + LoadVModel( "models/v_satchel_radio.mdl", m_pPlayer ); #endif SendWeaponAnim( SATCHEL_RADIO_DRAW ); @@ -404,7 +408,7 @@ void CSatchel::Throw( void ) void CSatchel::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; switch( m_chargeReady ) @@ -420,7 +424,7 @@ void CSatchel::WeaponIdle( void ) strcpy( m_pPlayer->m_szAnimExtention, "hive" ); break; case 2: - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { m_chargeReady = 0; RetireWeapon(); @@ -428,10 +432,10 @@ void CSatchel::WeaponIdle( void ) } #ifndef CLIENT_DLL - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel.mdl"); + 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 ); + LoadVModel( "models/v_satchel.mdl", m_pPlayer ); #endif SendWeaponAnim( SATCHEL_DRAW ); @@ -458,14 +462,14 @@ void DeactivateSatchels( CBasePlayer *pOwner ) pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" ); - while ( !FNullEnt( pFind ) ) + while( !FNullEnt( pFind ) ) { CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); CSatchelCharge *pSatchel = (CSatchelCharge *)pEnt; - if ( pSatchel ) + if( pSatchel ) { - if ( pSatchel->pev->owner == pOwner->edict() ) + if( pSatchel->pev->owner == pOwner->edict() ) { pSatchel->Deactivate(); } diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index c0911c94..c28a88fa 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -33,9 +33,9 @@ extern CGraph WorldGraph; // FHaveSchedule - Returns TRUE if monster's m_pSchedule // is anything other than NULL. //========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) +BOOL CBaseMonster::FHaveSchedule( void ) { - if ( m_pSchedule == NULL ) + if( m_pSchedule == NULL ) { return FALSE; } @@ -47,7 +47,7 @@ BOOL CBaseMonster :: FHaveSchedule( void ) // ClearSchedule - blanks out the caller's schedule pointer // and index. //========================================================= -void CBaseMonster :: ClearSchedule( void ) +void CBaseMonster::ClearSchedule( void ) { m_iTaskStatus = TASKSTATUS_NEW; m_pSchedule = NULL; @@ -58,11 +58,11 @@ void CBaseMonster :: ClearSchedule( void ) // FScheduleDone - Returns TRUE if the caller is on the // last task in the schedule //========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) +BOOL CBaseMonster::FScheduleDone( void ) { ASSERT( m_pSchedule != NULL ); - if ( m_iScheduleIndex == m_pSchedule->cTasks ) + if( m_iScheduleIndex == m_pSchedule->cTasks ) { return TRUE; } @@ -75,27 +75,27 @@ BOOL CBaseMonster :: FScheduleDone ( void ) // with the passed pointer, and sets the ScheduleIndex back // to 0 //========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) +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; + 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) ) + if( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); + ALERT( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) + else if( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); + ALERT( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); } #if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) + if( !ScheduleFromName( pNewSchedule->pName ) ) { ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); } @@ -104,15 +104,15 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) // 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" ) ) + if( FClassnameIs( pev, "monster_human_grunt" ) ) { Task_t *pTask = GetTask(); - if ( pTask ) + if( pTask ) { const char *pName = NULL; - if ( m_pSchedule ) + if( m_pSchedule ) { pName = m_pSchedule->pName; } @@ -121,7 +121,7 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) pName = "No Schedule"; } - if ( !pName ) + if( !pName ) { pName = "Unknown"; } @@ -135,14 +135,14 @@ void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) //========================================================= // NextScheduledTask - increments the ScheduleIndex //========================================================= -void CBaseMonster :: NextScheduledTask ( void ) +void CBaseMonster::NextScheduledTask( void ) { ASSERT( m_pSchedule != NULL ); m_iTaskStatus = TASKSTATUS_NEW; m_iScheduleIndex++; - if ( FScheduleDone() ) + if( FScheduleDone() ) { // just completed last task in schedule, so make it invalid by clearing it. SetConditions( bits_COND_SCHEDULE_DONE ); @@ -155,7 +155,7 @@ void CBaseMonster :: NextScheduledTask ( void ) // bits that are currently set and also set in the current // schedule's Interrupt mask. //========================================================= -int CBaseMonster :: IScheduleFlags ( void ) +int CBaseMonster::IScheduleFlags( void ) { if( !m_pSchedule ) { @@ -171,21 +171,21 @@ int CBaseMonster :: IScheduleFlags ( void ) // schedule is still the proper schedule to be executing, // taking into account all conditions //========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) +BOOL CBaseMonster::FScheduleValid( void ) { - if ( m_pSchedule == NULL ) + 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 ) ) + 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 ) + 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 ); + ALERT( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); Vector tmp = pev->origin; tmp.z = pev->absmax.z + 16; @@ -204,21 +204,21 @@ BOOL CBaseMonster :: FScheduleValid ( void ) // ensures that the monster leaves this function with a valid // schedule! //========================================================= -void CBaseMonster :: MaintainSchedule ( void ) +void CBaseMonster::MaintainSchedule( void ) { - Schedule_t *pNewSchedule; - int i; + 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++ ) + for( i = 0; i < 10; i++ ) { - if ( m_pSchedule != NULL && TaskIsComplete() ) + if( m_pSchedule != NULL && TaskIsComplete() ) { NextScheduledTask(); } // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) + 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 @@ -233,31 +233,31 @@ void CBaseMonster :: MaintainSchedule ( void ) // - 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_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)) ) + 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( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) { - if ( m_failSchedule != SCHED_NONE ) + 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 ); + 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 ) + if( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) pNewSchedule = CBaseMonster::GetSchedule(); else pNewSchedule = GetSchedule(); @@ -265,7 +265,7 @@ void CBaseMonster :: MaintainSchedule ( void ) } } - if ( m_iTaskStatus == TASKSTATUS_NEW ) + if( m_iTaskStatus == TASKSTATUS_NEW ) { Task_t *pTask = GetTask(); ASSERT( pTask != NULL ); @@ -274,16 +274,16 @@ void CBaseMonster :: MaintainSchedule ( void ) } // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) + if( m_Activity != m_IdealActivity ) { - SetActivity ( m_IdealActivity ); + SetActivity( m_IdealActivity ); } - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) + if( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) break; } - if ( TaskIsRunning() ) + if( TaskIsRunning() ) { Task_t *pTask = GetTask(); ASSERT( pTask != NULL ); @@ -293,25 +293,25 @@ void CBaseMonster :: MaintainSchedule ( void ) // 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 ) + if( m_Activity != m_IdealActivity ) { - SetActivity ( m_IdealActivity ); + SetActivity( m_IdealActivity ); } } //========================================================= // RunTask //========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) +void CBaseMonster::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_TURN_RIGHT: case TASK_TURN_LEFT: { ChangeYaw( pev->yaw_speed ); - if ( FacingIdeal() ) + if( FacingIdeal() ) { TaskComplete(); } @@ -322,23 +322,23 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { CBaseEntity *pTarget; - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) + if( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) pTarget = m_hTargetEnt; else pTarget = m_hEnemy; - if ( pTarget ) + if( pTarget ) { pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); ChangeYaw( pev->yaw_speed ); } - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) TaskComplete(); } break; case TASK_PLAY_SEQUENCE: case TASK_PLAY_ACTIVE_IDLE: { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); } @@ -350,7 +350,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) ChangeYaw( pev->yaw_speed ); - if ( FacingIdeal() ) + if( FacingIdeal() ) { TaskComplete(); } @@ -364,7 +364,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { ChangeYaw( pev->yaw_speed ); - if ( FacingIdeal() ) + if( FacingIdeal() ) { TaskComplete(); } @@ -372,7 +372,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } case TASK_WAIT_PVS: { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) + if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { TaskComplete(); } @@ -386,7 +386,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) case TASK_WAIT: case TASK_WAIT_RANDOM: { - if ( gpGlobals->time >= m_flWaitFinished ) + if( gpGlobals->time >= m_flWaitFinished ) { TaskComplete(); } @@ -394,10 +394,10 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } case TASK_WAIT_FACE_ENEMY: { - MakeIdealYaw ( m_vecEnemyLKP ); + MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); - if ( gpGlobals->time >= m_flWaitFinished ) + if( gpGlobals->time >= m_flWaitFinished ) { TaskComplete(); } @@ -407,14 +407,14 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) { float distance; - if ( m_hTargetEnt == NULL ) + 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 ) + 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(); @@ -423,21 +423,21 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) // Set the appropriate activity based on an overlapping range // overlap the range to prevent oscillation - if ( distance < pTask->flData ) + if( distance < pTask->flData ) { TaskComplete(); RouteClear(); // Stop moving } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) + else if( distance < 190 && m_movementActivity != ACT_WALK ) m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) + else if( distance >= 270 && m_movementActivity != ACT_RUN ) m_movementActivity = ACT_RUN; } break; } case TASK_WAIT_FOR_MOVEMENT: { - if (MovementIsComplete()) + if( MovementIsComplete() ) { TaskComplete(); RouteClear(); // Stop moving @@ -446,24 +446,24 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } case TASK_DIE: { - if ( m_fSequenceFinished && pev->frame >= 255 ) + if( m_fSequenceFinished && pev->frame >= 255 ) { pev->deadflag = DEAD_DEAD; SetThink( NULL ); StopAnimation(); - if ( !BBoxFlat() ) + 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 ) ); + 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 ) ); + 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() ) + if( ShouldFadeOnDeath() ) { // this monster was created by a monstermaker... fade the corpse out. SUB_StartFadeOut(); @@ -471,7 +471,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) 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 ); + CSoundEnt::InsertSound( bits_SOUND_CARCASS, pev->origin, 384, 30 ); } } break; @@ -482,7 +482,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) case TASK_RANGE_ATTACK2_NOTURN: case TASK_RELOAD_NOTURN: { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); @@ -497,10 +497,10 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) case TASK_SPECIAL_ATTACK2: case TASK_RELOAD: { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); + MakeIdealYaw( m_vecEnemyLKP ); + ChangeYaw( pev->yaw_speed ); - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); @@ -509,7 +509,7 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) } case TASK_SMALL_FLINCH: { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); } @@ -517,20 +517,20 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) break; case TASK_WAIT_FOR_SCRIPT: { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) + 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 ) + 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) ); + //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) + if( m_fSequenceFinished ) { m_pCine->SequenceDone( this ); } @@ -544,17 +544,17 @@ void CBaseMonster :: RunTask ( Task_t *pTask ) // the monster is facing and determines whether or not to // select one of the 180 turn animations. //========================================================= -void CBaseMonster :: SetTurnActivity ( void ) +void CBaseMonster::SetTurnActivity( void ) { float flYD; flYD = FlYawDiff(); - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) + 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 ) + else if( flYD > 45 && LookupActivity( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) { // big left turn m_IdealActivity = ACT_TURN_LEFT; @@ -566,9 +566,9 @@ void CBaseMonster :: SetTurnActivity ( void ) // any necessary calculations to start the next task on the // schedule. //========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) +void CBaseMonster::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_TURN_RIGHT: { @@ -590,13 +590,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_REMEMBER: { - Remember ( (int)pTask->flData ); + Remember( (int)pTask->flData ); TaskComplete(); break; } case TASK_FORGET: { - Forget ( (int)pTask->flData ); + Forget( (int)pTask->flData ); TaskComplete(); break; } @@ -604,7 +604,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { m_iHintNode = FindHintNode(); - if ( m_iHintNode != NO_NODE ) + if( m_iHintNode != NO_NODE ) { TaskComplete(); } @@ -634,7 +634,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_STOP_MOVING: { - if ( m_IdealActivity == m_movementActivity ) + if( m_IdealActivity == m_movementActivity ) { m_IdealActivity = GetStoppedActivity(); } @@ -647,14 +647,14 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_PLAY_SEQUENCE_FACE_TARGET: case TASK_PLAY_SEQUENCE: { - m_IdealActivity = ( Activity )( int )pTask->flData; + 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; + m_IdealActivity = (Activity)WorldGraph.m_pNodes[m_iHintNode].m_sHintActivity; break; } case TASK_SET_SCHEDULE: @@ -662,8 +662,8 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) Schedule_t *pNewSchedule; pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) + + if( pNewSchedule ) { ChangeSchedule( pNewSchedule ); } @@ -675,13 +675,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: { - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { TaskFail(); return; } - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) + 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(); @@ -695,13 +695,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: { - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { TaskFail(); return; } - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) + 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(); @@ -715,13 +715,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FIND_NODE_COVER_FROM_ENEMY: { - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { TaskFail(); return; } - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) + if( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); @@ -737,7 +737,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { entvars_t *pevCover; - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { // Find cover from self if no enemy available pevCover = pev; @@ -747,13 +747,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) else pevCover = m_hEnemy->pev; - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) + 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() ) ) + else if( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; @@ -768,7 +768,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FIND_COVER_FROM_ORIGIN: { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) + if( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; @@ -789,7 +789,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) ASSERT( pBestSound != NULL ); /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) + if( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; @@ -797,7 +797,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } */ - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) + if( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; @@ -812,18 +812,18 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FACE_HINTNODE: { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; + pev->ideal_yaw = WorldGraph.m_pNodes[m_iHintNode].m_flHintYaw; SetTurnActivity(); break; } case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); + MakeIdealYaw( m_vecLastPosition ); SetTurnActivity(); break; case TASK_FACE_TARGET: - if ( m_hTargetEnt != NULL ) + if( m_hTargetEnt != NULL ) { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); + MakeIdealYaw( m_hTargetEnt->pev->origin ); SetTurnActivity(); } else @@ -831,7 +831,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) break; case TASK_FACE_ENEMY: { - MakeIdealYaw ( m_vecEnemyLKP ); + MakeIdealYaw( m_vecEnemyLKP ); SetTurnActivity(); break; } @@ -842,14 +842,14 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FACE_ROUTE: { - if (FRouteClear()) + if( FRouteClear() ) { - ALERT(at_aiconsole, "No route to face!\n"); + ALERT( at_aiconsole, "No route to face!\n" ); TaskFail(); } else { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); + MakeIdealYaw( m_Route[m_iRouteIndex].vecLocation ); SetTurnActivity(); } break; @@ -875,12 +875,12 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_MOVE_TO_TARGET_RANGE: { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + if( ( m_hTargetEnt->pev->origin - pev->origin ).Length() < 1 ) TaskComplete(); else { m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) + if( !MoveToTarget( ACT_WALK, 2 ) ) TaskFail(); } break; @@ -890,24 +890,24 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { Activity newActivity; - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + if( ( m_hTargetEnt->pev->origin - pev->origin ).Length() < 1 ) TaskComplete(); else { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) + 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 ) + if( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) TaskComplete(); else { - if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) + if( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) { TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); + ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING( pev->classname ) ); RouteClear(); } } @@ -969,18 +969,18 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_GET_PATH_TO_ENEMY_LKP: { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) + if( BuildRoute( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) + 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" ); + ALERT( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; @@ -989,24 +989,24 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy == NULL ) + if( pEnemy == NULL ) { TaskFail(); return; } - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) + 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() )) + 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" ); + ALERT( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; @@ -1014,13 +1014,13 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_GET_PATH_TO_ENEMY_CORPSE: { UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) + if( BuildRoute( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); + ALERT( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); TaskFail(); } } @@ -1028,14 +1028,14 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) 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 ) ) + if( BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) { TaskComplete(); } else { // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + ALERT( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; @@ -1043,28 +1043,29 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_GET_PATH_TO_TARGET: { RouteClear(); - if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) + if( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) { TaskComplete(); } else { // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); + ALERT( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! + case TASK_GET_PATH_TO_HINTNODE: + // for active idles! { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) + 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" ); + ALERT( at_aiconsole, "GetPathToHintNode failed!!\n" ); TaskFail(); } break; @@ -1073,7 +1074,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) { m_vecMoveGoal = m_vecLastPosition; - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) + if( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) { TaskComplete(); } @@ -1091,7 +1092,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) pSound = PBestSound(); - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) + if( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) { TaskComplete(); } @@ -1109,7 +1110,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) pScent = PBestScent(); - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) + if( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) { TaskComplete(); } @@ -1125,7 +1126,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) 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 ) + if( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_RUN; } @@ -1138,11 +1139,11 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_WALK_PATH: { - if ( pev->movetype == MOVETYPE_FLY ) + if( pev->movetype == MOVETYPE_FLY ) { m_movementActivity = ACT_FLY; } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) + if( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_WALK; } @@ -1155,16 +1156,16 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_STRAFE_PATH: { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; + 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 ); + UTIL_MakeVectors( pev->angles ); - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); + vec2DirToPoint = ( m_Route[0].vecLocation - pev->origin ).Make2D().Normalize(); vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) + if( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) { // strafe right m_movementActivity = ACT_STRAFE_RIGHT; @@ -1179,7 +1180,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_WAIT_FOR_MOVEMENT: { - if (FRouteClear()) + if( FRouteClear() ) { TaskComplete(); } @@ -1198,7 +1199,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_DIE: { - RouteClear(); + RouteClear(); m_IdealActivity = GetDeathActivity(); @@ -1238,16 +1239,16 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_SOUND_ANGRY: { // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); + ALERT( at_aiconsole, "SOUND\n" ); TaskComplete(); break; } case TASK_WAIT_FOR_SCRIPT: { - if (m_pCine->m_iszIdle) + 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))) + if( FStrEq( STRING( m_pCine->m_iszIdle ), STRING( m_pCine->m_iszPlay ) ) ) { pev->framerate = 0; } @@ -1259,7 +1260,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) case TASK_PLAY_SCRIPT: { pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); + ClearBits( pev->flags, FL_ONGROUND ); m_scriptState = SCRIPT_PLAYING; break; } @@ -1271,7 +1272,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_PLANT_ON_SCRIPT: { - if ( m_hTargetEnt != NULL ) + if( m_hTargetEnt != NULL ) { pev->origin = m_hTargetEnt->pev->origin; // Plant on target } @@ -1281,7 +1282,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) } case TASK_FACE_SCRIPT: { - if ( m_hTargetEnt != NULL ) + if( m_hTargetEnt != NULL ) { pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); } @@ -1307,7 +1308,7 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) break; default: { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); + ALERT( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); break; } } @@ -1317,16 +1318,16 @@ void CBaseMonster :: StartTask ( Task_t *pTask ) // GetTask - returns a pointer to the current // scheduled task. NULL if there's a problem. //========================================================= -Task_t *CBaseMonster :: GetTask ( void ) +Task_t *CBaseMonster::GetTask( void ) { - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) + 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 ]; + return &m_pSchedule->pTasklist[m_iScheduleIndex]; } } @@ -1336,9 +1337,9 @@ Task_t *CBaseMonster :: GetTask ( void ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CBaseMonster :: GetSchedule ( void ) +Schedule_t *CBaseMonster::GetSchedule( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_PRONE: { @@ -1347,16 +1348,16 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) } case MONSTERSTATE_NONE: { - ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); + ALERT( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); break; } case MONSTERSTATE_IDLE: { - if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } - else if ( FRouteClear() ) + else if( FRouteClear() ) { // no valid route! return GetScheduleOfType( SCHED_IDLE_STAND ); @@ -1370,14 +1371,14 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) } case MONSTERSTATE_ALERT: { - if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) + if( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) { - return GetScheduleOfType ( SCHED_VICTORY_DANCE ); + return GetScheduleOfType( SCHED_VICTORY_DANCE ); } - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) + if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { - if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction + if( fabs( FlYawDiff() ) < ( 1.0 - m_flFieldOfView ) * 60 ) // roughly in the correct direction { return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); } @@ -1386,7 +1387,7 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); } } - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) + else if( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } @@ -1398,12 +1399,12 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) } case MONSTERSTATE_COMBAT: { - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) + if( HasConditions( bits_COND_ENEMY_DEAD ) ) { // clear the current (dead) enemy and try to find another. m_hEnemy = NULL; - if ( GetEnemy() ) + if( GetEnemy() ) { ClearConditions( bits_COND_ENEMY_DEAD ); return GetSchedule(); @@ -1415,18 +1416,18 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) } } - if ( HasConditions(bits_COND_NEW_ENEMY) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); + return GetScheduleOfType( SCHED_WAKE_ANGRY ); } - else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) + else if( HasConditions( bits_COND_LIGHT_DAMAGE ) && !HasMemory( bits_MEMORY_FLINCHED ) ) { return GetScheduleOfType( SCHED_SMALL_FLINCH ); } - else if ( !HasConditions(bits_COND_SEE_ENEMY) ) + else if( !HasConditions( bits_COND_SEE_ENEMY ) ) { // we can't see the enemy - if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) + if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) ) { // enemy is unseen, but not occluded! // turn to face enemy @@ -1441,35 +1442,35 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) else { // we can see the enemy - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) + 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( !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() ) + else if( !FacingIdeal() ) { //turn return GetScheduleOfType( SCHED_COMBAT_FACE ); } else { - ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); + ALERT( at_aiconsole, "No suitable combat schedule!\n" ); } } break; @@ -1482,9 +1483,9 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) case MONSTERSTATE_SCRIPT: { ASSERT( m_pCine != NULL ); - if ( !m_pCine ) + if( !m_pCine ) { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); + ALERT( at_aiconsole, "Script failed for %s\n", STRING( pev->classname ) ); CineCleanup(); return GetScheduleOfType( SCHED_IDLE_STAND ); } @@ -1493,10 +1494,10 @@ Schedule_t *CBaseMonster :: GetSchedule ( void ) } default: { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); + ALERT( at_aiconsole, "Invalid State for GetSchedule!\n" ); break; } } - return &slError[ 0 ]; + return &slError[0]; } diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index b2f2b784..4e60c58e 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -27,8 +27,15 @@ #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 }; +#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 { @@ -54,14 +61,13 @@ enum //========================================================= // Monster's Anim Events Go Here //========================================================= -#define SCIENTIST_AE_HEAL ( 1 ) +#define SCIENTIST_AE_HEAL ( 1 ) #define SCIENTIST_AE_NEEDLEON ( 2 ) #define SCIENTIST_AE_NEEDLEOFF ( 3 ) //======================================================= // Scientist //======================================================= - class CScientist : public CTalkMonster { public: @@ -69,40 +75,40 @@ public: void Precache( void ); void SetYawSpeed( void ); - int Classify ( 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); + 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 ); + 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; } + 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 ); + 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 ); + 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[]; + void Killed( entvars_t *pevAttacker, int iGib ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; CUSTOM_SCHEDULES @@ -128,16 +134,16 @@ IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ) //========================================================= 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 }, + { 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[] = +Schedule_t slFollow[] = { { tlFollow, - ARRAYSIZE ( tlFollow ), + ARRAYSIZE( tlFollow ), bits_COND_NEW_ENEMY | bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE | @@ -148,18 +154,18 @@ Schedule_t slFollow[] = }, }; -Task_t tlFollowScared[] = +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 }, + { 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[] = +Schedule_t slFollowScared[] = { { tlFollowScared, - ARRAYSIZE ( tlFollowScared ), + ARRAYSIZE( tlFollowScared ), bits_COND_NEW_ENEMY | bits_COND_HEAR_SOUND | bits_COND_LIGHT_DAMAGE | @@ -169,18 +175,18 @@ Schedule_t slFollowScared[] = }, }; -Task_t tlFaceTargetScared[] = +Task_t tlFaceTargetScared[] = { - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, + { TASK_FACE_TARGET, (float)0 }, + { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, + { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, }; -Schedule_t slFaceTargetScared[] = +Schedule_t slFaceTargetScared[] = { { tlFaceTargetScared, - ARRAYSIZE ( tlFaceTargetScared ), + ARRAYSIZE( tlFaceTargetScared ), bits_COND_HEAR_SOUND | bits_COND_NEW_ENEMY, bits_SOUND_DANGER, @@ -188,57 +194,57 @@ Schedule_t slFaceTargetScared[] = }, }; -Task_t tlStopFollowing[] = +Task_t tlStopFollowing[] = { - { TASK_CANT_FOLLOW, (float)0 }, + { TASK_CANT_FOLLOW, (float)0 }, }; -Schedule_t slStopFollowing[] = +Schedule_t slStopFollowing[] = { { tlStopFollowing, - ARRAYSIZE ( tlStopFollowing ), + ARRAYSIZE( tlStopFollowing ), 0, 0, "StopFollowing" }, }; -Task_t tlHeal[] = +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 + { 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[] = +Schedule_t slHeal[] = { { tlHeal, - ARRAYSIZE ( 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_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 }, + { 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[] = +Schedule_t slFaceTarget[] = { { tlFaceTarget, - ARRAYSIZE ( tlFaceTarget ), + ARRAYSIZE( tlFaceTarget ), bits_COND_CLIENT_PUSH | bits_COND_NEW_ENEMY | bits_COND_HEAR_SOUND, @@ -248,94 +254,93 @@ Schedule_t slFaceTarget[] = }, }; -Task_t tlSciPanic[] = +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 }, + { 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[] = +Schedule_t slSciPanic[] = { { tlSciPanic, - ARRAYSIZE ( tlSciPanic ), + ARRAYSIZE( tlSciPanic ), 0, 0, "SciPanic" }, }; -Task_t tlIdleSciStand[] = +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 + { 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[] = +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 | + 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_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_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 }, + { 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[] = +Schedule_t slScientistCover[] = { - { + { tlScientistCover, - ARRAYSIZE ( tlScientistCover ), + ARRAYSIZE( tlScientistCover ), bits_COND_NEW_ENEMY, 0, "ScientistCover" }, }; -Task_t tlScientistHide[] = +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 }, + { 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[] = +Schedule_t slScientistHide[] = { - { + { tlScientistHide, - ARRAYSIZE ( tlScientistHide ), + ARRAYSIZE( tlScientistHide ), bits_COND_NEW_ENEMY | bits_COND_HEAR_SOUND | bits_COND_SEE_ENEMY | @@ -347,22 +352,22 @@ Schedule_t slScientistHide[] = }, }; -Task_t tlScientistStartle[] = +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 }, + { 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[] = +Schedule_t slScientistStartle[] = { - { + { tlScientistStartle, - ARRAYSIZE ( tlScientistStartle ), + ARRAYSIZE( tlScientistStartle ), bits_COND_NEW_ENEMY | bits_COND_SEE_ENEMY | bits_COND_SEE_HATE | @@ -373,19 +378,19 @@ Schedule_t slScientistStartle[] = }, }; -Task_t tlFear[] = +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 }, + { 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[] = +Schedule_t slFear[] = { - { + { tlFear, - ARRAYSIZE ( tlFear ), + ARRAYSIZE( tlFear ), bits_COND_NEW_ENEMY, 0, "Fear" @@ -417,33 +422,32 @@ void CScientist::DeclineFollowing( void ) PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); } -void CScientist :: Scream( void ) +void CScientist::Scream( void ) { - if ( FOkToSpeak() ) + if( FOkToSpeak() ) { Talk( 10 ); m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); + PlaySentence( "SC_SCREAM", RANDOM_FLOAT( 3, 6 ), VOL_NORM, ATTN_NORM ); } } Activity CScientist::GetStoppedActivity( void ) { - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) return ACT_EXCITED; return CTalkMonster::GetStoppedActivity(); } -void CScientist :: StartTask( Task_t *pTask ) +void CScientist::StartTask( Task_t *pTask ) { switch( pTask->iTask ) { case TASK_SAY_HEAL: -// if ( FOkToSpeak() ) + //if( FOkToSpeak() ) Talk( 2 ); m_hTalkTarget = m_hTargetEnt; PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); - TaskComplete(); break; case TASK_SCREAM: @@ -451,16 +455,16 @@ void CScientist :: StartTask( Task_t *pTask ) TaskComplete(); break; case TASK_RANDOM_SCREAM: - if ( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) + if( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) Scream(); TaskComplete(); break; case TASK_SAY_FEAR: - if ( FOkToSpeak() ) + if( FOkToSpeak() ) { Talk( 2 ); m_hTalkTarget = m_hEnemy; - if ( m_hEnemy->IsPlayer() ) + if( m_hEnemy->IsPlayer() ) PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); else PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); @@ -475,12 +479,12 @@ void CScientist :: StartTask( Task_t *pTask ) break; case TASK_MOVE_TO_TARGET_RANGE_SCARED: { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) + if( ( m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) + if( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) TaskFail(); } } @@ -491,22 +495,22 @@ void CScientist :: StartTask( Task_t *pTask ) } } -void CScientist :: RunTask( Task_t *pTask ) +void CScientist::RunTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_RUN_PATH_SCARED: - if ( MovementIsComplete() ) + if( MovementIsComplete() ) TaskComplete(); - if ( RANDOM_LONG(0,31) < 8 ) + if( RANDOM_LONG( 0, 31 ) < 8 ) Scream(); break; case TASK_MOVE_TO_TARGET_RANGE_SCARED: { - if ( RANDOM_LONG(0,63)< 8 ) + if( RANDOM_LONG( 0, 63 ) < 8 ) Scream(); - if ( m_hEnemy == NULL ) + if( m_hEnemy == NULL ) { TaskFail(); } @@ -516,7 +520,7 @@ void CScientist :: RunTask( Task_t *pTask ) 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 ) + 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(); @@ -525,26 +529,26 @@ void CScientist :: RunTask( Task_t *pTask ) // Set the appropriate activity based on an overlapping range // overlap the range to prevent oscillation - if ( distance < pTask->flData ) + if( distance < pTask->flData ) { TaskComplete(); RouteClear(); // Stop moving } - else if ( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) + else if( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) m_movementActivity = ACT_WALK_SCARED; - else if ( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) + else if( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) m_movementActivity = ACT_RUN_SCARED; } } break; case TASK_HEAL: - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { TaskComplete(); } else { - if ( TargetDistance() > 90 ) + if( TargetDistance() > 90 ) TaskComplete(); pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin ); ChangeYaw( pev->yaw_speed ); @@ -560,22 +564,22 @@ void CScientist :: RunTask( Task_t *pTask ) // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CScientist :: Classify ( void ) +int CScientist::Classify( void ) { - return CLASS_HUMAN_PASSIVE; + return CLASS_HUMAN_PASSIVE; } //========================================================= // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CScientist :: SetYawSpeed ( void ) +void CScientist::SetYawSpeed( void ) { int ys; ys = 90; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: ys = 120; @@ -601,7 +605,7 @@ void CScientist :: SetYawSpeed ( void ) // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CScientist::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -610,14 +614,14 @@ void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; case SCIENTIST_AE_NEEDLEON: { - int oldBody = pev->body; - pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 1; + 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; + int oldBody = pev->body; + pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 0; } break; default: @@ -628,36 +632,36 @@ void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CScientist :: Spawn( void ) +void CScientist::Spawn( void ) { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); + 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; + 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_flDistTooFar = 256.0; - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; + 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 ) + if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any 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 ) + if( pev->body == HEAD_LUTHER ) pev->skin = 1; MonsterInit(); @@ -667,14 +671,14 @@ void CScientist :: Spawn( void ) //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CScientist :: Precache( void ) +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"); + 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) @@ -684,7 +688,7 @@ void CScientist :: Precache( void ) } // Init talk data -void CScientist :: TalkInit() +void CScientist::TalkInit() { CTalkMonster::TalkInit(); @@ -696,49 +700,57 @@ void CScientist :: TalkInit() // 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_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_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_PHELLO] = "SC_PHELLO"; + m_szGrp[TLK_PIDLE] = "SC_PIDLE"; m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; - m_szGrp[TLK_SMELL] = "SC_SMELL"; + m_szGrp[TLK_SMELL] = "SC_SMELL"; - m_szGrp[TLK_WOUND] = "SC_WOUND"; - m_szGrp[TLK_MORTAL] = "SC_MORTAL"; + m_szGrp[TLK_WOUND] = "SC_WOUND"; + m_szGrp[TLK_MORTAL] = "SC_MORTAL"; // get voice for head - switch (pev->body % 3) + 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 + 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) +int CScientist::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) + 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); + return CTalkMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } //========================================================= @@ -746,38 +758,48 @@ int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f // of sounds this monster regards. In the base class implementation, // monsters care about all sounds, but no scents. //========================================================= -int CScientist :: ISoundMask ( void ) +int CScientist::ISoundMask( void ) { - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | + return bits_SOUND_WORLD | + bits_SOUND_COMBAT | + bits_SOUND_DANGER | bits_SOUND_PLAYER; } //========================================================= // PainSound //========================================================= -void CScientist :: PainSound ( void ) +void CScientist::PainSound( void ) { - if (gpGlobals->time < m_painTime ) + if( gpGlobals->time < m_painTime ) return; - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); + m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 ); - switch (RANDOM_LONG(0,4)) + 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; + 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 ) +void CScientist::DeathSound( void ) { PainSound(); } @@ -788,19 +810,19 @@ void CScientist::Killed( entvars_t *pevAttacker, int iGib ) CTalkMonster::Killed( pevAttacker, iGib ); } -void CScientist :: SetActivity ( Activity newActivity ) +void CScientist::SetActivity( Activity newActivity ) { - int iSequence; + int iSequence; - iSequence = LookupActivity ( newActivity ); + iSequence = LookupActivity( newActivity ); // Set to the desired anim, or default anim if the desired is not present - if ( iSequence == ACTIVITY_NOT_AVAILABLE ) + if( iSequence == ACTIVITY_NOT_AVAILABLE ) newActivity = ACT_IDLE; CTalkMonster::SetActivity( newActivity ); } -Schedule_t* CScientist :: GetScheduleOfType ( int Type ) +Schedule_t *CScientist::GetScheduleOfType( int Type ) { Schedule_t *psched; @@ -809,10 +831,10 @@ Schedule_t* CScientist :: GetScheduleOfType ( int 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); + // when 'used' + psched = CTalkMonster::GetScheduleOfType( Type ); - if (psched == slIdleStand) + if( psched == slIdleStand ) return slFaceTarget; // override this for different target face behavior else return psched; @@ -829,9 +851,9 @@ Schedule_t* CScientist :: GetScheduleOfType ( int Type ) case SCHED_IDLE_STAND: // call base class default so that scientist will talk // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); + psched = CTalkMonster::GetScheduleOfType( Type ); - if (psched == slIdleStand) + if( psched == slIdleStand ) return slIdleSciStand; else return psched; @@ -846,18 +868,18 @@ Schedule_t* CScientist :: GetScheduleOfType ( int Type ) return CTalkMonster::GetScheduleOfType( Type ); } -Schedule_t *CScientist :: GetSchedule ( void ) +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 ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) + if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } @@ -865,35 +887,35 @@ Schedule_t *CScientist :: GetSchedule ( void ) { case MONSTERSTATE_ALERT: case MONSTERSTATE_IDLE: - if ( pEnemy ) + if( pEnemy ) { - if ( HasConditions( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) m_fearTime = gpGlobals->time; - else if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert + 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)) + 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 ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); - if ( pSound ) + if( pSound ) { - if ( pSound->m_iType & (bits_SOUND_DANGER | bits_SOUND_COMBAT) ) + if( pSound->m_iType & ( bits_SOUND_DANGER | bits_SOUND_COMBAT ) ) { - if ( gpGlobals->time - m_fearTime > 3 ) // Only cower every 3 seconds or so + 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 @@ -903,9 +925,9 @@ Schedule_t *CScientist :: GetSchedule ( void ) } // Behavior for following the player - if ( IsFollowing() ) + if( IsFollowing() ) { - if ( !m_hTargetEnt->IsAlive() ) + if( !m_hTargetEnt->IsAlive() ) { // UNDONE: Comment about the recently dead player here? StopFollowing( FALSE ); @@ -915,43 +937,43 @@ Schedule_t *CScientist :: GetSchedule ( void ) int relationship = R_NO; // Nothing scary, just me and the player - if ( pEnemy != NULL ) + 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( relationship != R_DL && relationship != R_HT ) { // If I'm already close enough to my target - if ( TargetDistance() <= 128 ) + if( TargetDistance() <= 128 ) { - if ( CanHeal() ) // Heal opportunistically + if( CanHeal() ) // Heal opportunistically return slHeal; - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move + 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 + 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 + 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 ) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) return slFear; // Point and scream! - if ( HasConditions( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) return slScientistCover; // Take Cover - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) + + if( HasConditions( bits_COND_HEAR_SOUND ) ) return slTakeCoverFromBestSound; // Cower and panic from the scary sound! return slScientistCover; // Run & Cower @@ -963,18 +985,18 @@ Schedule_t *CScientist :: GetSchedule ( void ) return CTalkMonster::GetSchedule(); } -MONSTERSTATE CScientist :: GetIdealState ( void ) +MONSTERSTATE CScientist::GetIdealState( void ) { - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_ALERT: case MONSTERSTATE_IDLE: - if ( HasConditions( bits_COND_NEW_ENEMY ) ) + if( HasConditions( bits_COND_NEW_ENEMY ) ) { - if ( IsFollowing() ) + if( IsFollowing() ) { int relationship = IRelationship( m_hEnemy ); - if ( relationship != R_FR || ( relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) ) + 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; @@ -983,19 +1005,19 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) StopFollowing( TRUE ); } } - else if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) + else if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) { // Stop following if you take damage - if ( IsFollowing() ) + if( IsFollowing() ) StopFollowing( TRUE ); } break; case MONSTERSTATE_COMBAT: { CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy != NULL ) + if( pEnemy != NULL ) { - if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert + if( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert { // Strip enemy when going to alert m_IdealMonsterState = MONSTERSTATE_ALERT; @@ -1004,13 +1026,13 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) } // Follow if only scared a little - if ( m_hTargetEnt != NULL ) + if( m_hTargetEnt != NULL ) { m_IdealMonsterState = MONSTERSTATE_ALERT; return m_IdealMonsterState; } - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) + if( HasConditions( bits_COND_SEE_ENEMY ) ) { m_fearTime = gpGlobals->time; m_IdealMonsterState = MONSTERSTATE_COMBAT; @@ -1028,7 +1050,7 @@ MONSTERSTATE CScientist :: GetIdealState ( void ) BOOL CScientist::CanHeal( void ) { - if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == NULL) || (m_hTargetEnt->pev->health > (m_hTargetEnt->pev->max_health * 0.5)) ) + if( ( m_healTime > gpGlobals->time ) || ( m_hTargetEnt == NULL ) || ( m_hTargetEnt->pev->health > ( m_hTargetEnt->pev->max_health * 0.5 ) ) ) return FALSE; return TRUE; @@ -1036,11 +1058,11 @@ BOOL CScientist::CanHeal( void ) void CScientist::Heal( void ) { - if ( !CanHeal() ) + if( !CanHeal() ) return; Vector target = m_hTargetEnt->pev->origin - pev->origin; - if ( target.Length() > 100 ) + if( target.Length() > 100 ) return; m_hTargetEnt->TakeHealth( gSkillData.scientistHeal, DMG_GENERIC ); @@ -1051,8 +1073,8 @@ void CScientist::Heal( void ) int CScientist::FriendNumber( int arrayNumber ) { static int array[3] = { 1, 2, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; + if( arrayNumber < 3 ) + return array[arrayNumber]; return arrayNumber; } @@ -1064,19 +1086,32 @@ class CDeadScientist : public CBaseMonster { public: void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_PASSIVE; } + int Classify( void ) + { + return CLASS_HUMAN_PASSIVE; + } void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display + int m_iPose;// which sequence to display static char *m_szPoses[7]; }; -char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" }; + +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")) + if( FStrEq( pkvd->szKeyName, "pose" ) ) { - m_iPose = atoi(pkvd->szValue); + m_iPose = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1087,33 +1122,33 @@ LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ) // // ********** DeadScientist SPAWN ********** // -void CDeadScientist :: Spawn( ) +void CDeadScientist::Spawn() { - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - - pev->effects = 0; - pev->sequence = 0; + 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; + pev->health = 8;//gSkillData.scientistHealth; m_bloodColor = BLOOD_COLOR_RED; - if ( pev->body == -1 ) + if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any 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 ) + if( pev->body == HEAD_LUTHER ) pev->skin = 1; else pev->skin = 0; pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) + if( pev->sequence == -1 ) { ALERT ( at_console, "Dead scientist with bad pose\n" ); } @@ -1125,29 +1160,29 @@ void CDeadScientist :: Spawn( ) //========================================================= // Sitting Scientist PROP //========================================================= - class CSittingScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak { public: void Spawn( void ); - void Precache( 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[]; + 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; + 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) @@ -1170,48 +1205,48 @@ SITTING_ANIM_sitting3 // // ********** Scientist SPAWN ********** // -void CSittingScientist :: Spawn( ) +void CSittingScientist::Spawn() { - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); + 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)); + 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; + 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_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; + m_afCapability= bits_CAP_HEAR | bits_CAP_TURN_HEAD; - SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! + SetBits( pev->spawnflags, SF_MONSTER_PREDISASTER ); // predisaster only! - if ( pev->body == -1 ) + if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any 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 ) + 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->sequence = m_baseSequence + RANDOM_LONG( 0, 4 ); + ResetSequenceInfo(); + + SetThink( &CSittingScientist::SittingThink ); pev->nextthink = gpGlobals->time + 0.1; - DROP_TO_FLOOR ( ENT(pev) ); + DROP_TO_FLOOR( ENT( pev ) ); } -void CSittingScientist :: Precache( void ) +void CSittingScientist::Precache( void ) { m_baseSequence = LookupSequence( "sitlookleft" ); TalkInit(); @@ -1220,108 +1255,112 @@ void CSittingScientist :: Precache( void ) //========================================================= // ID as a passive human //========================================================= -int CSittingScientist :: Classify ( void ) +int CSittingScientist::Classify( void ) { - return CLASS_HUMAN_PASSIVE; + return CLASS_HUMAN_PASSIVE; } int CSittingScientist::FriendNumber( int arrayNumber ) { static int array[3] = { 2, 1, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; + if( arrayNumber < 3 ) + return array[arrayNumber]; return arrayNumber; } //========================================================= // sit, do stuff //========================================================= -void CSittingScientist :: SittingThink( void ) +void CSittingScientist::SittingThink( void ) { - CBaseEntity *pent; + CBaseEntity *pent; - StudioFrameAdvance( ); + StudioFrameAdvance(); // try to greet player - if (FIdleHello()) + if( FIdleHello() ) { - pent = FindNearestFriend(TRUE); - if (pent) + pent = FindNearestFriend( TRUE ); + if( pent ) { - float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; + float yaw = VecToYaw( pent->pev->origin - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) + 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( ); + + ResetSequenceInfo(); pev->frame = 0; SetBoneController( 0, 0 ); } } - else if (m_fSequenceFinished) + else if( m_fSequenceFinished ) { - int i = RANDOM_LONG(0,99); + int i = RANDOM_LONG( 0, 99 ); m_headTurn = 0; - if (m_flResponseDelay && gpGlobals->time > m_flResponseDelay) + 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) + 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); + if( !FBitSet( m_bitsSaid, bit_saidHelloPlayer ) ) + pent = FindNearestFriend( TRUE ); else - pent = FindNearestFriend(FALSE); + pent = FindNearestFriend( FALSE ); - if (!FIdleSpeak() || !pent) - { - m_headTurn = RANDOM_LONG(0,8) * 10 - 40; + 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; + float yaw = VecToYaw( pent->pev->origin - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) + 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"); + //ALERT( at_console, "sitting speak\n" ); } } - else if (i < 60) + 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) + m_headTurn = RANDOM_LONG( 0, 8 ) * 10 - 40; + if( RANDOM_LONG( 0, 99 ) < 5 ) { - //ALERT(at_console, "sitting speak2\n"); + //ALERT( at_console, "sitting speak2\n" ); FIdleSpeak(); } } - else if (i < 80) + else if( i < 80 ) { pev->sequence = m_baseSequence + SITTING_ANIM_sitting2; } - else if (i < 100) + else if( i < 100 ) { pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; } @@ -1334,9 +1373,9 @@ void CSittingScientist :: SittingThink( void ) } // prepare sitting scientist to answer a question -void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) +void CSittingScientist::SetAnswerQuestion( CTalkMonster *pSpeaker ) { - m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT(3, 4); + m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); m_hTalkTarget = (CBaseMonster *)pSpeaker; } @@ -1344,42 +1383,42 @@ void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) // FIdleSpeak // ask question of nearby friend, or make statement //========================================================= -int CSittingScientist :: FIdleSpeak ( void ) +int CSittingScientist::FIdleSpeak( void ) { // try to start a conversation, or make statement int pitch; - - if (!FOkToSpeak()) + + if( !FOkToSpeak() ) return FALSE; // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); + 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); + CBaseEntity *pentFriend = FindNearestFriend( FALSE ); - if (pentFriend && RANDOM_LONG(0,1)) + if( pentFriend && RANDOM_LONG( 0, 1 ) ) { - CTalkMonster *pTalkMonster = GetClassPtr((CTalkMonster *)pentFriend->pev); + 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 ); + + 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); + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 4.8, 5.2 ); return TRUE; } // otherwise, play an idle statement - if (RANDOM_LONG(0,1)) + if( RANDOM_LONG( 0, 1 ) ) { - SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PIDLE], 1.0, ATTN_IDLE, 0, pitch ); + 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); + CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 4.8, 5.2 ); return TRUE; } diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index aa3701d8..f3cf37c5 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -51,40 +51,39 @@ spawnflags - (stop if blocked, stop if player seen) // // Cache user-entity-field values until spawn is called. // - -void CCineMonster :: KeyValue( KeyValueData *pkvd ) +void CCineMonster::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "m_iszIdle")) + if( FStrEq( pkvd->szKeyName, "m_iszIdle" ) ) { m_iszIdle = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_iszPlay")) + else if( FStrEq( pkvd->szKeyName, "m_iszPlay" ) ) { m_iszPlay = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_iszEntity")) + else if( FStrEq( pkvd->szKeyName, "m_iszEntity" ) ) { m_iszEntity = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_fMoveTo")) + else if( FStrEq( pkvd->szKeyName, "m_fMoveTo" ) ) { m_fMoveTo = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flRepeat")) + else if( FStrEq( pkvd->szKeyName, "m_flRepeat" ) ) { m_flRepeat = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_flRadius")) + else if( FStrEq( pkvd->szKeyName, "m_flRadius" ) ) { m_flRadius = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) + else if( FStrEq( pkvd->szKeyName, "m_iFinishSchedule" ) ) { m_iFinishSchedule = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -107,8 +106,8 @@ TYPEDESCRIPTION CCineMonster::m_SaveData[] = 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_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 ), @@ -122,27 +121,27 @@ LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ) LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ) -void CCineMonster :: Spawn( void ) +void CCineMonster::Spawn( void ) { // pev->solid = SOLID_TRIGGER; - // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); + // 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 ) + if( m_iszIdle ) m_fMoveTo = 4; #endif // if no targetname, start now - if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) + if( FStringNull( pev->targetname ) || !FStringNull( m_iszIdle ) ) { SetThink( &CCineMonster::CineThink ); pev->nextthink = gpGlobals->time + 1.0; // Wait to be used? - if ( pev->targetname ) + if( pev->targetname ) m_startTime = gpGlobals->time + 1E6; } - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) + if( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) m_interruptable = FALSE; else m_interruptable = TRUE; @@ -152,9 +151,9 @@ void CCineMonster :: Spawn( void ) // FCanOverrideState - returns FALSE, scripted sequences // cannot possess entities regardless of state. //========================================================= -BOOL CCineMonster :: FCanOverrideState( void ) +BOOL CCineMonster::FCanOverrideState( void ) { - if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) + if( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) return TRUE; return FALSE; } @@ -163,7 +162,7 @@ BOOL CCineMonster :: FCanOverrideState( void ) // FCanOverrideState - returns true because scripted AI can // possess entities regardless of their state. //========================================================= -BOOL CCineAI :: FCanOverrideState( void ) +BOOL CCineAI::FCanOverrideState( void ) { return TRUE; } @@ -171,19 +170,19 @@ BOOL CCineAI :: FCanOverrideState( void ) // // CineStart // -void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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; + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; - if ( pEntity ) + if( pEntity ) pTarget = pEntity->MyMonsterPointer(); - if ( pTarget ) + if( pTarget ) { // am I already playing the script? - if ( pTarget->m_scriptState == SCRIPT_PLAYING ) + if( pTarget->m_scriptState == SCRIPT_PLAYING ) return; m_startTime = gpGlobals->time + 0.05; @@ -197,18 +196,18 @@ void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP } // This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events -void CCineMonster :: Blocked( CBaseEntity *pOther ) +void CCineMonster::Blocked( CBaseEntity *pOther ) { } -void CCineMonster :: Touch( CBaseEntity *pOther ) +void CCineMonster::Touch( CBaseEntity *pOther ) { /* ALERT( at_aiconsole, "Cine Touch\n" ); - if (m_pentTarget && OFFSET(pOther->pev) == OFFSET(m_pentTarget)) + if( m_pentTarget && OFFSET( pOther->pev ) == OFFSET( m_pentTarget ) ) { - CBaseMonster *pTarget = GetClassPtr((CBaseMonster *)VARS(m_pentTarget)); + CBaseMonster *pTarget = GetClassPtr( (CBaseMonster *)VARS( m_pentTarget ) ); pTarget->m_monsterState == MONSTERSTATE_SCRIPT; } */ @@ -217,7 +216,7 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) /* entvars_t *pevOther = VARS( gpGlobals->other ); - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) + if( !FBitSet( pevOther->flags, FL_MONSTER ) ) { // touched by a non-monster. return; @@ -225,7 +224,7 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) pevOther->origin.z += 1; - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) + if( FBitSet( pevOther->flags, FL_ONGROUND ) ) { // clear the onground so physics don't bitch pevOther->flags -= FL_ONGROUND; @@ -243,7 +242,7 @@ void CCineMonster :: Touch( CBaseEntity *pOther ) // // ********** Cinematic DIE ********** // -void CCineMonster :: Die( void ) +void CCineMonster::Die( void ) { SetThink( &CBaseEntity::SUB_Remove ); } @@ -251,7 +250,7 @@ void CCineMonster :: Die( void ) // // ********** Cinematic PAIN ********** // -void CCineMonster :: Pain( void ) +void CCineMonster::Pain( void ) { } @@ -261,41 +260,41 @@ void CCineMonster :: Pain( void ) // // find a viable entity -int CCineMonster :: FindEntity( void ) +int CCineMonster::FindEntity( void ) { edict_t *pentTarget; - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_iszEntity ) ); m_hTargetEnt = NULL; - CBaseMonster *pTarget = NULL; + CBaseMonster *pTarget = NULL; - while (!FNullEnt(pentTarget)) + while( !FNullEnt( pentTarget ) ) { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) + if( FBitSet( VARS( pentTarget )->flags, FL_MONSTER ) ) { pTarget = GetMonsterPointer( pentTarget ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_BY_NAME ) ) + 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) ); + ALERT( at_console, "Found %s, but can't play!\n", STRING( m_iszEntity ) ); } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( m_iszEntity ) ); pTarget = NULL; } - if ( !pTarget ) + if( !pTarget ) { CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius ) ) != NULL ) { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) + if( FClassnameIs( pEntity->pev, STRING( m_iszEntity ) ) ) { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) + if( FBitSet( pEntity->pev->flags, FL_MONSTER ) ) { - pTarget = pEntity->MyMonsterPointer( ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) + pTarget = pEntity->MyMonsterPointer(); + if( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) { m_hTargetEnt = pTarget; return TRUE; @@ -310,21 +309,20 @@ int CCineMonster :: FindEntity( void ) } // make the entity enter a scripted sequence -void CCineMonster :: PossessEntity( void ) +void CCineMonster::PossessEntity( void ) { - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if( pEntity ) pTarget = pEntity->MyMonsterPointer(); - if ( pTarget ) + if( pTarget ) { - // FindEntity() just checked this! #if 0 - if ( !pTarget->CanPlaySequence( FCanOverrideState() ) ) + if( !pTarget->CanPlaySequence( FCanOverrideState() ) ) { - ALERT( at_aiconsole, "Can't possess entity %s\n", STRING(pTarget->pev->classname) ); + ALERT( at_aiconsole, "Can't possess entity %s\n", STRING( pTarget->pev->classname ) ); return; } #endif @@ -337,7 +335,7 @@ void CCineMonster :: PossessEntity( void ) m_saved_effects = pTarget->pev->effects; pTarget->pev->effects |= pev->effects; - switch (m_fMoveTo) + switch( m_fMoveTo ) { case 0: pTarget->m_scriptState = SCRIPT_WAIT; @@ -363,13 +361,13 @@ void CCineMonster :: PossessEntity( void ) // 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" ); + //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) + if( m_iszIdle ) { StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) + if( FStrEq( STRING( m_iszIdle ), STRING( m_iszPlay ) ) ) { pTarget->pev->framerate = 0; } @@ -379,20 +377,20 @@ void CCineMonster :: PossessEntity( void ) // make the entity carry out the scripted sequence instructions, but without // destroying the monster's state. -void CCineAI :: PossessEntity( void ) +void CCineAI::PossessEntity( void ) { Schedule_t *pNewSchedule; - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) + CBaseEntity *pEntity = m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if( pEntity ) pTarget = pEntity->MyMonsterPointer(); - if ( pTarget ) + if( pTarget ) { - if ( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) + if( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) { - ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING(pTarget->pev->classname) ); + ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING( pTarget->pev->classname ) ); return; } @@ -405,7 +403,7 @@ void CCineAI :: PossessEntity( void ) m_saved_effects = pTarget->pev->effects; pTarget->pev->effects |= pev->effects; - switch (m_fMoveTo) + switch( m_fMoveTo ) { case 0: case 5: @@ -431,7 +429,7 @@ void CCineAI :: PossessEntity( void ) pTarget->pev->flags &= ~FL_ONGROUND; break; default: - ALERT ( at_aiconsole, "aiscript: invalid Move To Position value!" ); + ALERT( at_aiconsole, "aiscript: invalid Move To Position value!" ); break; } @@ -439,17 +437,17 @@ void CCineAI :: PossessEntity( void ) pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; /* - if (m_iszIdle) + if( m_iszIdle ) { StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) + if( FStrEq( STRING( m_iszIdle ), STRING( m_iszPlay ) ) ) { pTarget->pev->framerate = 0; } } */ // Already in a scripted state? - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) + if( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) { pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); pTarget->ChangeSchedule( pNewSchedule ); @@ -457,45 +455,45 @@ void CCineAI :: PossessEntity( void ) } } -void CCineMonster :: CineThink( void ) +void CCineMonster::CineThink( void ) { - if (FindEntity()) + if( FindEntity() ) { - PossessEntity( ); + PossessEntity(); ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); } else { - CancelScript( ); + 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 ) +BOOL CCineMonster::StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) { - if ( !iszSeq && completeOnEmpty ) + if( !iszSeq && completeOnEmpty ) { SequenceDone( pTarget ); return FALSE; } pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - if (pTarget->pev->sequence == -1) + if( pTarget->pev->sequence == -1 ) { - ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); + 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 ) + 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 ); + 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( ); @@ -505,9 +503,9 @@ BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL comp // 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 ) +BOOL CCineAI::StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) { - if ( iszSeq == 0 && 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 @@ -520,15 +518,15 @@ BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeO pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - if (pTarget->pev->sequence == -1) + if( pTarget->pev->sequence == -1 ) { - ALERT( at_error, "%s: unknown aiscripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); + 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( ); + pTarget->ResetSequenceInfo(); return TRUE; } @@ -539,11 +537,11 @@ BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeO // the CBaseMonster pointer to the monster that the sequence // possesses. //========================================================= -void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) +void CCineMonster::SequenceDone( CBaseMonster *pMonster ) { //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); - if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) + if( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) { SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; @@ -568,9 +566,9 @@ void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) // Scripted sequences just dirty the Schedule and drop the // monster in Idle State. //========================================================= -void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) +void CCineMonster::FixScriptMonsterSchedule( CBaseMonster *pMonster ) { - if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) + if( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; pMonster->ClearSchedule(); } @@ -588,7 +586,7 @@ void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) // // -Select a specific AMBUSH schedule, regardless of state. //========================================================= -void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) +void CCineAI::FixScriptMonsterSchedule( CBaseMonster *pMonster ) { switch ( m_iFinishSchedule ) { @@ -599,15 +597,15 @@ void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) pMonster->ChangeSchedule( pMonster->GetScheduleOfType( SCHED_AMBUSH ) ); break; default: - ALERT ( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); + ALERT( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); pMonster->ClearSchedule(); break; } } -BOOL CBaseMonster :: ExitScriptedSequence( ) +BOOL CBaseMonster::ExitScriptedSequence() { - if ( pev->deadflag == DEAD_DYING ) + if( pev->deadflag == DEAD_DYING ) { // is this legal? // BUGBUG -- This doesn't call Killed() @@ -615,9 +613,9 @@ BOOL CBaseMonster :: ExitScriptedSequence( ) return FALSE; } - if (m_pCine) + if( m_pCine ) { - m_pCine->CancelScript( ); + m_pCine->CancelScript(); } return TRUE; @@ -625,19 +623,19 @@ BOOL CBaseMonster :: ExitScriptedSequence( ) void CCineMonster::AllowInterrupt( BOOL fAllow ) { - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) + if( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) return; m_interruptable = fAllow; } BOOL CCineMonster::CanInterrupt( void ) { - if ( !m_interruptable ) + if( !m_interruptable ) return FALSE; CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) + if( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) return TRUE; return FALSE; @@ -645,7 +643,7 @@ BOOL CCineMonster::CanInterrupt( void ) int CCineMonster::IgnoreConditions( void ) { - if ( CanInterrupt() ) + if( CanInterrupt() ) return 0; return SCRIPT_BREAK_CONDITIONS; } @@ -653,61 +651,61 @@ int CCineMonster::IgnoreConditions( void ) void ScriptEntityCancel( edict_t *pentCine ) { // make sure they are a scripted_sequence - if (FClassnameIs( pentCine, CLASSNAME )) + if( FClassnameIs( pentCine, CLASSNAME ) ) { - CCineMonster *pCineTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); + 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 ) + CBaseEntity *pEntity = pCineTarget->m_hTargetEnt; + CBaseMonster *pTarget = NULL; + if( pEntity ) pTarget = pEntity->MyMonsterPointer(); - if (pTarget) + if( pTarget ) { // make sure their monster is actually playing a script - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) + if( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) { // tell them do die pTarget->m_scriptState = CCineMonster::SCRIPT_CLEANUP; // do it now - pTarget->CineCleanup( ); + pTarget->CineCleanup(); } } } } // find all the cinematic entities with my targetname and stop them from playing -void CCineMonster :: CancelScript( void ) +void CCineMonster::CancelScript( void ) { - ALERT( at_aiconsole, "Cancelling script: %s\n", STRING(m_iszPlay) ); + ALERT( at_aiconsole, "Cancelling script: %s\n", STRING( m_iszPlay ) ); - if ( !pev->targetname ) + if( !pev->targetname ) { ScriptEntityCancel( edict() ); return; } - edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); + edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->targetname ) ); - while (!FNullEnt(pentCineTarget)) + while( !FNullEnt( pentCineTarget ) ) { ScriptEntityCancel( pentCineTarget ); - pentCineTarget = FIND_ENTITY_BY_TARGETNAME(pentCineTarget, STRING(pev->targetname)); + 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 ) +void CCineMonster::DelayStart( int state ) { - edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); + edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->targetname ) ); - while (!FNullEnt(pentCine)) + while( !FNullEnt( pentCine ) ) { - if (FClassnameIs( pentCine, "scripted_sequence" )) + if( FClassnameIs( pentCine, "scripted_sequence" ) ) { - CCineMonster *pTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - if (state) + CCineMonster *pTarget = GetClassPtr( ( CCineMonster *)VARS( pentCine ) ); + if( state ) { pTarget->m_iDelay++; } @@ -718,38 +716,38 @@ void CCineMonster :: DelayStart( int state ) pTarget->m_startTime = gpGlobals->time + 0.05; } } - pentCine = FIND_ENTITY_BY_TARGETNAME(pentCine, STRING(pev->targetname)); + 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 ) +void CCineMonster::Activate( void ) { - edict_t *pentTarget; - CBaseMonster *pTarget; + 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)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_iszEntity ) ); pTarget = NULL; - while (!pTarget && !FNullEnt(pentTarget)) + while( !pTarget && !FNullEnt( pentTarget ) ) { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) + if( FBitSet( VARS( pentTarget )->flags, FL_MONSTER ) ) { pTarget = GetMonsterPointer( pentTarget ); } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); + 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)) + 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)); + pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING( m_iszEntity ) ); } } @@ -758,7 +756,7 @@ void CCineMonster :: Activate( void ) { void *pmodel; pmodel = GET_MODEL_PTR( pTarget->edict() ); - if ( pmodel ) + if( pmodel ) { // Look through the event list for stuff to precache SequencePrecache( pmodel, STRING( m_iszIdle ) ); @@ -767,12 +765,12 @@ void CCineMonster :: Activate( void ) } } -BOOL CBaseMonster :: CineCleanup( ) +BOOL CBaseMonster::CineCleanup() { CCineMonster *pOldCine = m_pCine; // am I linked to a cinematic? - if (m_pCine) + if( m_pCine ) { // okay, reset me to what it thought I was before m_pCine->m_hTargetEnt = NULL; @@ -789,17 +787,17 @@ BOOL CBaseMonster :: CineCleanup( ) m_pCine = NULL; m_hTargetEnt = NULL; m_pGoalEnt = NULL; - if (pev->deadflag == DEAD_DYING) + if( pev->deadflag == DEAD_DYING ) { // last frame of death animation? - pev->health = 0; - pev->framerate = 0.0; - pev->solid = SOLID_NOT; + 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) ); + 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 ) ) + 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 @@ -815,9 +813,9 @@ BOOL CBaseMonster :: CineCleanup( ) } // If we actually played a sequence - if ( pOldCine && pOldCine->m_iszPlay ) + if( pOldCine && pOldCine->m_iszPlay ) { - if ( !(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT) ) + if( !( pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT ) ) { // reset position Vector new_origin, new_angle; @@ -838,7 +836,7 @@ BOOL CBaseMonster :: CineCleanup( ) // 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) + if( ( oldOrigin - new_origin).Length2D() < 8.0 ) new_origin = oldOrigin; pev->origin.x = new_origin.x; @@ -846,12 +844,12 @@ BOOL CBaseMonster :: CineCleanup( ) pev->origin.z += 1; pev->flags |= FL_ONGROUND; - int drop = DROP_TO_FLOOR( ENT(pev) ); + int drop = DROP_TO_FLOOR( ENT( pev ) ); // Origin in solid? Set to org at the end of the sequence - if ( drop < 0 ) + if( drop < 0 ) pev->origin = oldOrigin; - else if ( drop == 0 ) // Hanging in air? + else if( drop == 0 ) // Hanging in air? { pev->origin.z = new_origin.z; pev->flags &= ~FL_ONGROUND; @@ -870,7 +868,7 @@ BOOL CBaseMonster :: CineCleanup( ) } // set them back into a normal state pev->enemy = NULL; - if ( pev->health > 0 ) + if( pev->health > 0 ) m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; else { @@ -884,7 +882,7 @@ BOOL CBaseMonster :: CineCleanup( ) } // SetAnimation( m_MonsterState ); - ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); + ClearBits( pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); return TRUE; } @@ -897,30 +895,30 @@ public: 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); } + int ObjectCaps( void ) { return ( CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ); } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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 + 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_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 @@ -942,44 +940,44 @@ IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ) LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ) -void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) +void CScriptedSentence::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "sentence")) + if( FStrEq( pkvd->szKeyName, "sentence" ) ) { m_iszSentence = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "entity")) + else if( FStrEq( pkvd->szKeyName, "entity" ) ) { m_iszEntity = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "duration")) + else if( FStrEq( pkvd->szKeyName, "duration" ) ) { m_flDuration = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "radius")) + else if( FStrEq( pkvd->szKeyName, "radius" ) ) { m_flRadius = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "refire")) + else if( FStrEq( pkvd->szKeyName, "refire") ) { m_flRepeat = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if(FStrEq(pkvd->szKeyName, "attenuation")) + else if( FStrEq( pkvd->szKeyName, "attenuation" ) ) { pev->impulse = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if(FStrEq(pkvd->szKeyName, "volume")) + else if( FStrEq( pkvd->szKeyName, "volume" ) ) { m_flVolume = atof( pkvd->szValue ) * 0.1; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "listener")) + else if( FStrEq( pkvd->szKeyName, "listener" ) ) { m_iszListener = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -988,22 +986,22 @@ void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) CBaseToggle::KeyValue( pkvd ); } -void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CScriptedSentence::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !m_active ) + if( !m_active ) return; - //ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); + //ALERT( at_console, "Firing sentence: %s\n", STRING( m_iszSentence ) ); SetThink( &CScriptedSentence::FindThink ); pev->nextthink = gpGlobals->time; } -void CScriptedSentence :: Spawn( void ) +void CScriptedSentence::Spawn( void ) { pev->solid = SOLID_NOT; m_active = TRUE; // if no targetname, start now - if ( !pev->targetname ) + if( !pev->targetname ) { SetThink( &CScriptedSentence::FindThink ); pev->nextthink = gpGlobals->time + 1.0; @@ -1011,104 +1009,108 @@ void CScriptedSentence :: Spawn( void ) switch( pev->impulse ) { - case 1: // Medium radius + case 1: + // Medium radius m_flAttenuation = ATTN_STATIC; break; - case 2: // Large radius + case 2: + // Large radius m_flAttenuation = ATTN_NORM; break; - case 3: //EVERYWHERE + case 3: + //EVERYWHERE m_flAttenuation = ATTN_NONE; break; default: - case 0: // Small radius + case 0: + // Small radius m_flAttenuation = ATTN_IDLE; break; } pev->impulse = 0; // No volume, use normal - if ( m_flVolume <= 0 ) + if( m_flVolume <= 0 ) m_flVolume = 1.0; } -void CScriptedSentence :: FindThink( void ) +void CScriptedSentence::FindThink( void ) { CBaseMonster *pMonster = FindEntity(); - if ( pMonster ) + if( pMonster ) { StartSentence( pMonster ); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) + 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) ); + //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) ); + //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 ) +void CScriptedSentence::DelayThink( void ) { m_active = TRUE; - if ( !pev->targetname ) + if( !pev->targetname ) pev->nextthink = gpGlobals->time + 0.1; SetThink( &CScriptedSentence::FindThink ); } -BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) +BOOL CScriptedSentence::AcceptableSpeaker( CBaseMonster *pMonster ) { - if ( pMonster ) + if( pMonster ) { - if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) + if( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) { - if ( pMonster->m_hTargetEnt == NULL || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) + if( pMonster->m_hTargetEnt == NULL || !FClassnameIs( pMonster->m_hTargetEnt->pev, "player" ) ) return FALSE; } BOOL override; - if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) + if( pev->spawnflags & SF_SENTENCE_INTERRUPT ) override = TRUE; else override = FALSE; - if ( pMonster->CanPlaySentence( override ) ) + if( pMonster->CanPlaySentence( override ) ) return TRUE; } return FALSE; } -CBaseMonster *CScriptedSentence :: FindEntity( void ) +CBaseMonster *CScriptedSentence::FindEntity( void ) { edict_t *pentTarget; CBaseMonster *pMonster; - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_iszEntity ) ); pMonster = NULL; - while (!FNullEnt(pentTarget)) + while( !FNullEnt( pentTarget ) ) { pMonster = GetMonsterPointer( pentTarget ); - if ( pMonster != NULL ) + if( pMonster != NULL ) { - if ( AcceptableSpeaker( pMonster ) ) + if( AcceptableSpeaker( pMonster ) ) return pMonster; - //ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); + //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)); + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( m_iszEntity ) ); } - + CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius ) ) != NULL ) { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) + if( FClassnameIs( pEntity->pev, STRING( m_iszEntity ) ) ) { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) + if( FBitSet( pEntity->pev->flags, FL_MONSTER ) ) { - pMonster = pEntity->MyMonsterPointer( ); - if ( AcceptableSpeaker( pMonster ) ) + pMonster = pEntity->MyMonsterPointer(); + if( AcceptableSpeaker( pMonster ) ) return pMonster; } } @@ -1117,31 +1119,31 @@ CBaseMonster *CScriptedSentence :: FindEntity( void ) return NULL; } -BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) +BOOL CScriptedSentence::StartSentence( CBaseMonster *pTarget ) { - if ( !pTarget ) + if( !pTarget ) { - ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING(m_iszSentence) ); + ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING( m_iszSentence ) ); return NULL; } BOOL bConcurrent = FALSE; - if ( !(pev->spawnflags & SF_SENTENCE_CONCURRENT) ) + if( !( pev->spawnflags & SF_SENTENCE_CONCURRENT ) ) bConcurrent = TRUE; CBaseEntity *pListener = NULL; - if (!FStringNull(m_iszListener)) + if( !FStringNull( m_iszListener ) ) { float radius = m_flRadius; - if ( FStrEq( STRING(m_iszListener ), "player" ) ) + 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 ); + 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; } @@ -1152,10 +1154,10 @@ BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) class CFurniture : public CBaseMonster { public: - void Spawn ( void ); + void Spawn( void ); void Die( void ); - int Classify ( void ); - virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + int Classify( void ); + virtual int ObjectCaps( void ) { return (CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } }; LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ) @@ -1163,7 +1165,7 @@ LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ) //========================================================= // Furniture is killed //========================================================= -void CFurniture :: Die ( void ) +void CFurniture::Die( void ) { SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; @@ -1173,24 +1175,24 @@ void CFurniture :: Die ( void ) // This used to have something to do with bees flying, but // now it only initializes moving furniture in scripted sequences //========================================================= -void CFurniture :: Spawn( ) +void CFurniture::Spawn() { - PRECACHE_MODEL((char *)STRING(pev->model)); - SET_MODEL(ENT(pev), STRING(pev->model)); + 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->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->effects = 0; + pev->yaw_speed = 0; + pev->sequence = 0; + pev->frame = 0; //pev->nextthink += 1.0; - //SetThink( &WalkMonsterDelay); + //SetThink( &WalkMonsterDelay ); - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->frame = 0; MonsterInit(); } @@ -1198,7 +1200,7 @@ void CFurniture :: Spawn( ) //========================================================= // ID's Furniture as neutral (noone will attack it) //========================================================= -int CFurniture::Classify ( void ) +int CFurniture::Classify( void ) { - return CLASS_NONE; + return CLASS_NONE; } diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 6fe2c74e..8c96e99c 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -23,10 +23,11 @@ #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_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 { +enum shotgun_e +{ SHOTGUN_IDLE = 0, SHOTGUN_FIRE, SHOTGUN_FIRE2, @@ -41,11 +42,11 @@ enum shotgun_e { LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ) -void CShotgun::Spawn( ) +void CShotgun::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_SHOTGUN; - SET_MODEL(ENT(pev), "models/w_shotgun.mdl"); + SET_MODEL( ENT( pev ), "models/w_shotgun.mdl" ); m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; @@ -54,25 +55,25 @@ void CShotgun::Spawn( ) void CShotgun::Precache( void ) { - PRECACHE_MODEL("models/v_shotgun.mdl"); - PRECACHE_MODEL("models/w_shotgun.mdl"); - PRECACHE_MODEL("models/p_shotgun.mdl"); + 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 + m_iShell = PRECACHE_MODEL( "models/shotgunshell.mdl" );// shotgun shell - PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_SOUND( "items/9mmclip1.wav" ); - PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun - PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun + 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/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/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 + 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" ); @@ -80,7 +81,7 @@ void CShotgun::Precache( void ) int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -90,9 +91,9 @@ int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -int CShotgun::GetItemInfo(ItemInfo *p) +int CShotgun::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "buckshot"; p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; p->pszAmmo2 = NULL; @@ -107,7 +108,7 @@ int CShotgun::GetItemInfo(ItemInfo *p) return 1; } -BOOL CShotgun::Deploy( ) +BOOL CShotgun::Deploy() { return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); } @@ -115,18 +116,18 @@ BOOL CShotgun::Deploy( ) void CShotgun::PrimaryAttack() { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { - PlayEmptySound( ); + PlayEmptySound(); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } - if (m_iClip <= 0) + if( m_iClip <= 0 ) { - Reload( ); - if (m_iClip == 0) - PlayEmptySound( ); + Reload(); + if( m_iClip == 0 ) + PlayEmptySound(); return; } @@ -141,18 +142,17 @@ void CShotgun::PrimaryAttack() #else flags = 0; #endif + m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + 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 ); @@ -165,16 +165,16 @@ void CShotgun::PrimaryAttack() 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) + 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_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - if (m_iClip != 0) + if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.5; m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip != 0) + if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; else m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; @@ -184,17 +184,17 @@ void CShotgun::PrimaryAttack() void CShotgun::SecondaryAttack( void ) { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { - PlayEmptySound( ); + PlayEmptySound(); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } - if (m_iClip <= 1) + if( m_iClip <= 1 ) { - Reload( ); - PlayEmptySound( ); + Reload(); + PlayEmptySound(); return; } @@ -209,20 +209,20 @@ void CShotgun::SecondaryAttack( void ) #else flags = 0; #endif - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + 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 vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; - + #ifdef CLIENT_DLL - if ( bIsMultiplayer() ) + if( bIsMultiplayer() ) #else - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) #endif { // tuned for deathmatch @@ -233,19 +233,19 @@ void CShotgun::SecondaryAttack( void ) // 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) + 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_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - if (m_iClip != 0) + if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.95; m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; - if (m_iClip != 0) + if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; else m_flTimeWeaponIdle = 1.5; @@ -255,15 +255,15 @@ void CShotgun::SecondaryAttack( void ) void CShotgun::Reload( void ) { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) + 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()) + if( m_flNextPrimaryAttack > UTIL_WeaponTimeBase() ) return; // check to see if we're ready to reload - if (m_fInSpecialReload == 0) + if( m_fInSpecialReload == 0 ) { SendWeaponAnim( SHOTGUN_START_RELOAD ); m_fInSpecialReload = 1; @@ -273,17 +273,17 @@ void CShotgun::Reload( void ) m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; return; } - else if (m_fInSpecialReload == 1) + else if( m_fInSpecialReload == 1 ) { - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + 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)); + 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)); + EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG( 0, 0x1f ) ); SendWeaponAnim( SHOTGUN_RELOAD ); @@ -301,28 +301,28 @@ void CShotgun::Reload( void ) void CShotgun::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - if ( m_flPumpTime && m_flPumpTime < gpGlobals->time ) + 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)); + 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_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { - if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if( m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { - Reload( ); + Reload(); } - else if (m_fInSpecialReload != 0) + else if( m_fInSpecialReload != 0 ) { - if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if( m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { - Reload( ); + Reload(); } else { @@ -330,7 +330,7 @@ void CShotgun::WeaponIdle( void ) 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)); + 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; } @@ -339,20 +339,20 @@ void CShotgun::WeaponIdle( void ) { int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.8) + if( flRand <= 0.8 ) { iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 60.0 / 12.0 );// * RANDOM_LONG( 2, 5 ); } - else if (flRand <= 0.95) + else if( flRand <= 0.95 ) { iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 20.0 / 9.0 ); } else { iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 20.0 / 9.0 ); } SendWeaponAnim( iAnim ); } @@ -363,20 +363,20 @@ class CShotgunAmmo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + 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) + if( pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1 ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); return TRUE; } return FALSE; diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index e6358eed..9a46e722 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -40,7 +40,7 @@ CHalfLifeRules::CHalfLifeRules( void ) //========================================================= //========================================================= -void CHalfLifeRules::Think ( void ) +void CHalfLifeRules::Think( void ) { } @@ -53,7 +53,7 @@ BOOL CHalfLifeRules::IsMultiplayer( void ) //========================================================= //========================================================= -BOOL CHalfLifeRules::IsDeathmatch ( void ) +BOOL CHalfLifeRules::IsDeathmatch( void ) { return FALSE; } @@ -65,18 +65,17 @@ BOOL CHalfLifeRules::IsCoOp( void ) return FALSE; } - //========================================================= //========================================================= BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { - if ( !pPlayer->m_pActiveItem ) + if( !pPlayer->m_pActiveItem ) { // player doesn't have an active item! return TRUE; } - if ( !pPlayer->m_pActiveItem->CanHolster() ) + if( !pPlayer->m_pActiveItem->CanHolster() ) { return FALSE; } @@ -86,25 +85,25 @@ BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem //========================================================= //========================================================= -BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +BOOL CHalfLifeRules::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return FALSE; } //========================================================= //========================================================= -BOOL CHalfLifeRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +BOOL CHalfLifeRules::ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) { return TRUE; } -void CHalfLifeRules :: InitHUD( CBasePlayer *pl ) +void CHalfLifeRules::InitHUD( CBasePlayer *pl ) { } //========================================================= //========================================================= -void CHalfLifeRules :: ClientDisconnected( edict_t *pClient ) +void CHalfLifeRules::ClientDisconnected( edict_t *pClient ) { } @@ -120,33 +119,33 @@ float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) //========================================================= //========================================================= -void CHalfLifeRules :: PlayerSpawn( CBasePlayer *pPlayer ) +void CHalfLifeRules::PlayerSpawn( CBasePlayer *pPlayer ) { } //========================================================= //========================================================= -BOOL CHalfLifeRules :: AllowAutoTargetCrosshair( void ) +BOOL CHalfLifeRules::AllowAutoTargetCrosshair( void ) { return ( g_iSkillLevel == SKILL_EASY ); } //========================================================= //========================================================= -void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) +void CHalfLifeRules::PlayerThink( CBasePlayer *pPlayer ) { } //========================================================= //========================================================= -BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) +BOOL CHalfLifeRules::FPlayerCanRespawn( CBasePlayer *pPlayer ) { return TRUE; } //========================================================= //========================================================= -float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) +float CHalfLifeRules::FlPlayerSpawnTime( CBasePlayer *pPlayer ) { return gpGlobals->time;//now! } @@ -155,7 +154,7 @@ float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) // IPointsForKill - how many points awarded to anyone // that kills this player? //========================================================= -int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +int CHalfLifeRules::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) { return 1; } @@ -163,7 +162,7 @@ int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKill //========================================================= // PlayerKilled - someone/something killed this player //========================================================= -void CHalfLifeRules :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +void CHalfLifeRules::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) { } @@ -178,7 +177,7 @@ void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entv // PlayerGotWeapon - player has grabbed a weapon that was // sitting in the world //========================================================= -void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +void CHalfLifeRules::PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { } @@ -186,7 +185,7 @@ void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *p // FlWeaponRespawnTime - what is the time in the future // at which this weapon may spawn? //========================================================= -float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) +float CHalfLifeRules::FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) { return -1; } @@ -196,7 +195,7 @@ float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) // now, otherwise it returns the time at which it can try // to spawn again. //========================================================= -float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) +float CHalfLifeRules::FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) { return 0; } @@ -205,7 +204,7 @@ float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) // VecWeaponRespawnSpot - where should this weapon spawn? // Some game variations may choose to randomize spawn locations //========================================================= -Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) +Vector CHalfLifeRules::VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) { return pWeapon->pev->origin; } @@ -214,7 +213,7 @@ Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) // WeaponShouldRespawn - any conditions inhibiting the // respawning of this weapon? //========================================================= -int CHalfLifeRules :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) +int CHalfLifeRules::WeaponShouldRespawn( CBasePlayerItem *pWeapon ) { return GR_WEAPON_RESPAWN_NO; } @@ -321,7 +320,7 @@ int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarg //========================================================= //========================================================= -BOOL CHalfLifeRules :: FAllowMonsters( void ) +BOOL CHalfLifeRules::FAllowMonsters( void ) { return TRUE; } diff --git a/dlls/skill.cpp b/dlls/skill.cpp index e73b1b38..2a68e1a5 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -19,7 +19,7 @@ #include "util.h" #include "skill.h" -skilldata_t gSkillData; +skilldata_t gSkillData; //========================================================= // take the name of a cvar, tack a digit for the skill level @@ -27,17 +27,17 @@ skilldata_t gSkillData; //========================================================= float GetSkillCvar( char *pName ) { - int iCount; - float flValue; - char szBuffer[ 64 ]; + int iCount; + float flValue; + char szBuffer[64]; iCount = sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); - flValue = CVAR_GET_FLOAT ( szBuffer ); + flValue = CVAR_GET_FLOAT( szBuffer ); - if ( flValue <= 0 ) + if( flValue <= 0 ) { - ALERT ( at_console, "\n\n** GetSkillCVar Got a zero for %s **\n\n", szBuffer ); + ALERT( at_console, "\n\n** GetSkillCVar Got a zero for %s **\n\n", szBuffer ); } return flValue; diff --git a/dlls/sound.cpp b/dlls/sound.cpp index b45299e8..7ca01410 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -48,15 +48,15 @@ typedef struct dynpitchvol 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 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 cspincount; int pitch; int spinupsav; @@ -68,9 +68,8 @@ typedef struct dynpitchvol int fadeoutsav; int volfrac; - int lfofrac; - int lfomult; - + int lfofrac; + int lfomult; } dynpitchvol_t; #define CDPVPRESETMAX 27 @@ -112,23 +111,23 @@ dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = class CAmbientGeneric : public CBaseEntity { public: - void KeyValue( KeyValueData* pkvd); + void KeyValue( KeyValueData* pkvd ); void Spawn( void ); void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT RampThink( void ); - void InitModulationParms(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); } + 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; + 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 + 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 ) @@ -152,7 +151,7 @@ IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ) // // ambient_generic - general-purpose user-defined static sound // -void CAmbientGeneric :: Spawn( void ) +void CAmbientGeneric::Spawn( void ) { /* -1 : "Default" @@ -161,19 +160,19 @@ void CAmbientGeneric :: Spawn( void ) 125 : "Medium Radius" 80 : "Large Radius" */ - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) + if( FBitSet( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE ) ) { m_flAttenuation = ATTN_NONE; } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) + else if( FBitSet( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS ) ) { m_flAttenuation = ATTN_IDLE; } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) + else if( FBitSet( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS ) ) { m_flAttenuation = ATTN_STATIC; } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) + else if( FBitSet( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS ) ) { m_flAttenuation = ATTN_NORM; } @@ -183,23 +182,23 @@ void CAmbientGeneric :: Spawn( void ) m_flAttenuation = ATTN_STATIC; } - char* szSoundFile = (char*) STRING(pev->message); + char* szSoundFile = (char*)STRING( pev->message ); - if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) + 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( &CBaseEntity::SUB_Remove ); return; } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; + 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); + SetThink( &CAmbientGeneric::RampThink ); pev->nextthink = 0; // allow on/off switching via 'use' function. @@ -208,36 +207,36 @@ void CAmbientGeneric :: Spawn( void ) m_fActive = FALSE; - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) + if( FBitSet( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) m_fLooping = FALSE; else m_fLooping = TRUE; - Precache( ); + Precache(); } -void CAmbientGeneric :: Precache( void ) +void CAmbientGeneric::Precache( void ) { - char* szSoundFile = (char*) STRING(pev->message); + char* szSoundFile = (char*)STRING( pev->message ); - if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) + if( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) { - if (*szSoundFile != '!') - PRECACHE_SOUND(szSoundFile); + if( *szSoundFile != '!' ) + PRECACHE_SOUND( szSoundFile ); } // init all dynamic modulation parms InitModulationParms(); - if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) + if( !FBitSet( pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) { // start the sound ASAP - if (m_fLooping) + if( m_fLooping ) m_fActive = TRUE; } - if ( m_fActive ) + if( m_fActive ) { - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); + 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; } @@ -247,141 +246,144 @@ void CAmbientGeneric :: Precache( void ) // 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 ) +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; + int prev; - if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) + 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) + if( m_dpv.spinup || m_dpv.spindown ) { prev = m_dpv.pitchfrac >> 8; - if (m_dpv.spinup > 0) + if( m_dpv.spinup > 0 ) m_dpv.pitchfrac += m_dpv.spinup; - else if (m_dpv.spindown > 0) + else if( m_dpv.spindown > 0 ) m_dpv.pitchfrac -= m_dpv.spindown; pitch = m_dpv.pitchfrac >> 8; - - if (pitch > m_dpv.pitchrun) + + if( pitch > m_dpv.pitchrun ) { pitch = m_dpv.pitchrun; m_dpv.spinup = 0; // done with ramp up } - if (pitch < m_dpv.pitchstart) + 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); + 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; + if( pitch > 255 ) + pitch = 255; + if( pitch < 1 ) + pitch = 1; m_dpv.pitch = pitch; - fChanged |= (prev != pitch); + fChanged |= ( prev != pitch ); flags |= SND_CHANGE_PITCH; } // ================== // amplitude envelope // ================== - if (m_dpv.fadein || m_dpv.fadeout) + if( m_dpv.fadein || m_dpv.fadeout ) { prev = m_dpv.volfrac >> 8; - if (m_dpv.fadein > 0) + if( m_dpv.fadein > 0 ) m_dpv.volfrac += m_dpv.fadein; - else if (m_dpv.fadeout > 0) + else if( m_dpv.fadeout > 0 ) m_dpv.volfrac -= m_dpv.fadeout; vol = m_dpv.volfrac >> 8; - if (vol > m_dpv.volrun) + if( vol > m_dpv.volrun ) { vol = m_dpv.volrun; m_dpv.fadein = 0; // done with ramp up } - if (vol < m_dpv.volstart) + 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); + 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; + if( vol > 100 ) + vol = 100; + if( vol < 1 ) + vol = 1; m_dpv.vol = vol; - fChanged |= (prev != vol); + fChanged |= ( prev != vol ); flags |= SND_CHANGE_VOL; } // =================== // pitch/amplitude LFO // =================== - if (m_dpv.lfotype) + if( m_dpv.lfotype ) { int pos; - if (m_dpv.lfofrac > 0x6fffffff) + 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) + if( m_dpv.lfofrac < 0 ) { m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); + m_dpv.lforate = abs( m_dpv.lforate ); pos = 0; } - else if (pos > 255) + else if( pos > 255 ) { pos = 255; - m_dpv.lfofrac = (255 << 8); - m_dpv.lforate = -abs(m_dpv.lforate); + m_dpv.lfofrac = ( 255 << 8 ); + m_dpv.lforate = -abs( m_dpv.lforate ); } - switch(m_dpv.lfotype) + switch( m_dpv.lfotype ) { case LFO_SQUARE: - if (pos < 128) + 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); + if( pos == 255 ) + m_dpv.lfomult = RANDOM_LONG( 0, 255 ); break; case LFO_TRIANGLE: default: @@ -389,31 +391,35 @@ void CAmbientGeneric :: RampThink( void ) break; } - if (m_dpv.lfomodpitch) + if( m_dpv.lfomodpitch ) { prev = pitch; // pitch 0-255 - pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; + pitch += ( ( m_dpv.lfomult - 128 ) * m_dpv.lfomodpitch ) / 100; - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; + if( pitch > 255 ) + pitch = 255; + if( pitch < 1 ) + pitch = 1; - fChanged |= (prev != pitch); + fChanged |= ( prev != pitch ); flags |= SND_CHANGE_PITCH; } - if (m_dpv.lfomodvol) + if( m_dpv.lfomodvol ) { // vol 0-100 prev = vol; - vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; + vol += ( ( m_dpv.lfomult - 128 ) * m_dpv.lfomodvol ) / 100; - if (vol > 100) vol = 100; - if (vol < 0) vol = 0; + if( vol > 100 ) + vol = 100; + if( vol < 0 ) + vol = 0; - fChanged |= (prev != vol); + fChanged |= ( prev != vol ); flags |= SND_CHANGE_VOL; } } @@ -421,13 +427,13 @@ void CAmbientGeneric :: RampThink( void ) // Send update to playing sound only if we actually changed // pitch or volume in this routine. - if (flags && fChanged) + if( flags && fChanged ) { - if (pitch == PITCH_NORM) + 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); + UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, + ( vol * 0.01 ), m_flAttenuation, flags, pitch ); } // update ramps at 5hz @@ -438,34 +444,36 @@ void CAmbientGeneric :: RampThink( void ) // Init all ramp params in preparation to // play a new sound -void CAmbientGeneric :: InitModulationParms(void) +void CAmbientGeneric::InitModulationParms( void ) { int pitchinc; m_dpv.volrun = pev->health * 10; // 0 - 100 - if (m_dpv.volrun > 100) m_dpv.volrun = 100; - if (m_dpv.volrun < 0) m_dpv.volrun = 0; + 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) + 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; + 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; + 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; @@ -477,8 +485,8 @@ void CAmbientGeneric :: InitModulationParms(void) m_dpv.fadein = m_dpv.fadeinsav; m_dpv.fadeout = 0; - - if (m_dpv.fadein) + + if( m_dpv.fadein ) m_dpv.vol = m_dpv.volstart; else m_dpv.vol = m_dpv.volrun; @@ -486,32 +494,33 @@ void CAmbientGeneric :: InitModulationParms(void) m_dpv.spinup = m_dpv.spinupsav; m_dpv.spindown = 0; - if (m_dpv.spinup) + if( m_dpv.spinup ) m_dpv.pitch = m_dpv.pitchstart; else m_dpv.pitch = m_dpv.pitchrun; - if (m_dpv.pitch == 0) + 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.lforate = abs( m_dpv.lforate ); m_dpv.cspincount = 1; - if (m_dpv.cspinup) + if( m_dpv.cspinup ) { - pitchinc = (255 - m_dpv.pitchstart) / 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.pitchrun > 255 ) + m_dpv.pitchrun = 255; } - if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) - && (m_dpv.pitch == PITCH_NORM)) + 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! } @@ -522,58 +531,58 @@ void CAmbientGeneric :: InitModulationParms(void) // 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 ) +void CAmbientGeneric::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - char* szSoundFile = (char*) STRING(pev->message); + char* szSoundFile = (char*)STRING( pev->message ); float fraction; - if ( useType != USE_TOGGLE ) + if( useType != USE_TOGGLE ) { - if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) + 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 + if( useType == USE_SET && m_fActive ) // Momentary buttons will pass down a float in here { fraction = value; - - if ( fraction > 1.0 ) + + if( fraction > 1.0 ) fraction = 1.0; - if (fraction < 0.0) + if( fraction < 0.0 ) fraction = 0.01; m_dpv.pitch = fraction * 255; - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); + 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 ) + if( m_fActive ) { // turn sound off - if (m_dpv.cspinup) + if( m_dpv.cspinup ) { // Don't actually shut off. Each toggle causes // incremental spinup to max pitch - if (m_dpv.cspincount <= m_dpv.cspinup) - { + if( m_dpv.cspincount <= m_dpv.cspinup ) + { int pitchinc; // start a new spinup m_dpv.cspincount++; - - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; + + 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; + if( m_dpv.pitchrun > 255 ) + m_dpv.pitchrun = 255; pev->nextthink = gpGlobals->time + 0.1; } @@ -585,7 +594,7 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle // 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) + 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; @@ -596,8 +605,7 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle pev->nextthink = gpGlobals->time + 0.1; } else - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); + UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, 0, 0, SND_STOP, 0 ); } } else @@ -608,18 +616,16 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle // 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) + 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); + 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); + UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, ( m_dpv.vol * 0.01 ), m_flAttenuation, 0, m_dpv.pitch ); pev->nextthink = gpGlobals->time + 0.1; } @@ -627,143 +633,165 @@ void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCalle // KeyValue - load keyvalue pairs into member data of the // ambient generic. NOTE: called BEFORE spawn! - -void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) +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")) + if( FStrEq( pkvd->szKeyName, "preset" ) ) { - m_dpv.preset = atoi(pkvd->szValue); + m_dpv.preset = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } // pitchrun - else if (FStrEq(pkvd->szKeyName, "pitch")) + else if( FStrEq( pkvd->szKeyName, "pitch" ) ) { - m_dpv.pitchrun = atoi(pkvd->szValue); + 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; + 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")) + else if( FStrEq( pkvd->szKeyName, "pitchstart" ) ) { - m_dpv.pitchstart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; + 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; + 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")) + 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; + m_dpv.spinup = atoi( pkvd->szValue ); - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; + 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")) + 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; + m_dpv.spindown = atoi( pkvd->szValue ); - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; + 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")) + else if( FStrEq( pkvd->szKeyName, "volstart" ) ) { - m_dpv.volstart = atoi(pkvd->szValue); + m_dpv.volstart = atoi( pkvd->szValue ); - if (m_dpv.volstart > 10) m_dpv.volstart = 10; - if (m_dpv.volstart < 0) m_dpv.volstart = 0; + 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")) + else if( FStrEq( pkvd->szKeyName, "fadein" ) ) { - m_dpv.fadein = atoi(pkvd->szValue); + 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 > 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; + 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")) + else if( FStrEq( pkvd->szKeyName, "fadeout" ) ) { - m_dpv.fadeout = atoi(pkvd->szValue); + 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 > 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; + 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")) + else if( FStrEq( pkvd->szKeyName, "lfotype" ) ) { - m_dpv.lfotype = atoi(pkvd->szValue); - if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; + 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")) + else if( FStrEq( pkvd->szKeyName, "lforate" ) ) { - m_dpv.lforate = atoi(pkvd->szValue); + m_dpv.lforate = atoi( pkvd->szValue ); - if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; - if (m_dpv.lforate < 0) m_dpv.lforate = 0; + 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")) + 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; + 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")) + 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; + 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")) + 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; + 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; } @@ -781,9 +809,9 @@ public: void Think( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; float m_flRadius; float m_flRoomtype; @@ -799,16 +827,16 @@ TYPEDESCRIPTION CEnvSound::m_SaveData[] = IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ) -void CEnvSound :: KeyValue( KeyValueData *pkvd ) +void CEnvSound::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "radius")) + if( FStrEq( pkvd->szKeyName, "radius" ) ) { - m_flRadius = atof(pkvd->szValue); + m_flRadius = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - if (FStrEq(pkvd->szKeyName, "roomtype")) + if( FStrEq( pkvd->szKeyName, "roomtype" ) ) { - m_flRoomtype = atof(pkvd->szValue); + m_flRoomtype = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } } @@ -816,7 +844,7 @@ void CEnvSound :: KeyValue( KeyValueData *pkvd ) // 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) +BOOL FEnvSoundInRange( entvars_t *pev, entvars_t *pevTarget, float *pflRange ) { CEnvSound *pSound = GetClassPtr( (CEnvSound *)pev ); Vector vecSpot1 = pev->origin + pev->view_ofs; @@ -825,20 +853,20 @@ BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) float flRange; TraceResult tr; - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &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) + 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) + if( pSound->m_flRadius < flRange ) return FALSE; - - if (pflRange) + + if( pflRange ) *pflRange = flRange; return TRUE; @@ -855,30 +883,30 @@ BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) // CONSIDER: if player in water state, autoset roomtype to 14,15 or 16. -void CEnvSound :: Think( void ) +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()); + edict_t *pentPlayer = FIND_CLIENT_IN_PVS( edict() ); CBasePlayer *pPlayer = NULL; - if (FNullEnt(pentPlayer)) + if( FNullEnt( pentPlayer ) ) goto env_sound_Think_slow; // no player in pvs of sound entity, slow it down - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); + 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))) + 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) + 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)) + if( FEnvSoundInRange( pev, VARS( pentPlayer ), &flRange ) ) { pPlayer->m_flSndRange = flRange; goto env_sound_Think_fast; @@ -904,12 +932,12 @@ void CEnvSound :: Think( void ) // 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( FEnvSoundInRange( pev, VARS(pentPlayer), &flRange ) ) { - if (flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0) + 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_pentSndLast = ENT( pev ); pPlayer->m_flSndRoomtype = m_flRoomtype; pPlayer->m_flSndRange = flRange; @@ -917,7 +945,7 @@ void CEnvSound :: Think( void ) // this should be a rare event - once per change of room_type // only! - //CLIENT_COMMAND(pentPlayer, "room_type %f", m_flRoomtype); + //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 @@ -946,10 +974,10 @@ env_sound_Think_slow: // when player moves in range and sight. // // -void CEnvSound :: Spawn( ) +void CEnvSound::Spawn() { // spread think times - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.0, 0.5 ); } // ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== @@ -976,25 +1004,25 @@ int gcallsentences = 0; // randomize list of sentence name indices -void USENTENCEG_InitLRU(unsigned char *plru, int count) +void USENTENCEG_InitLRU( unsigned char *plru, int count ) { int i, j, k; unsigned char temp; - if (!fSentencesInit) + if( !fSentencesInit ) return; - if (count > CSENTENCE_LRU_MAX) + if( count > CSENTENCE_LRU_MAX ) count = CSENTENCE_LRU_MAX; - for (i = 0; i < count; i++) - plru[i] = (unsigned char) i; + for( i = 0; i < count; i++ ) + plru[i] = (unsigned char)i; // randomize array - for (i = 0; i < (count * 4); i++) + for( i = 0; i < ( count * 4 ); i++ ) { - j = RANDOM_LONG(0,count-1); - k = RANDOM_LONG(0,count-1); + j = RANDOM_LONG( 0, count - 1 ); + k = RANDOM_LONG( 0, count -1 ); temp = plru[j]; plru[j] = plru[k]; plru[k] = temp; @@ -1007,35 +1035,35 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count) // ipick 'next' is returned. // return of -1 indicates an error. -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) +int USENTENCEG_PickSequential( int isentenceg, char *szfound, int ipick, int freset ) { char *szgroupname; unsigned char count; char sznum[8]; - if (!fSentencesInit) + if( !fSentencesInit ) return -1; - if (isentenceg < 0) + if( isentenceg < 0 ) return -1; szgroupname = rgsentenceg[isentenceg].szgroupname; count = rgsentenceg[isentenceg].count; - if (count == 0) + if( count == 0 ) return -1; - if (ipick >= count) - ipick = count-1; + if( ipick >= count ) + ipick = count - 1; - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); + strcpy( szfound, "!" ); + strcat( szfound, szgroupname ); + sprintf( sznum, "%d", ipick ); + strcat( szfound, sznum ); - if (ipick >= count) + if( ipick >= count ) { - if (freset) + if( freset ) // reset at end of list return 0; else @@ -1053,7 +1081,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres // actually the size of the list. Returns ipick, the ordinal // of the picked sentence within the group. -int USENTENCEG_Pick(int isentenceg, char *szfound) +int USENTENCEG_Pick( int isentenceg, char *szfound ) { char *szgroupname; unsigned char *plru; @@ -1063,20 +1091,20 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) unsigned char ipick; int ffound = FALSE; - if (!fSentencesInit) + if( !fSentencesInit ) return -1; - if (isentenceg < 0) + if( isentenceg < 0 ) return -1; szgroupname = rgsentenceg[isentenceg].szgroupname; count = rgsentenceg[isentenceg].count; plru = rgsentenceg[isentenceg].rgblru; - while (!ffound) + while( !ffound ) { - for (i = 0; i < count; i++) - if (plru[i] != 0xFF) + for(i = 0; i < count; i++ ) + if( plru[i] != 0xFF ) { ipick = plru[i]; plru[i] = 0xFF; @@ -1084,14 +1112,14 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) break; } - if (!ffound) - USENTENCEG_InitLRU(plru, count); + if( !ffound ) + USENTENCEG_InitLRU( plru, count ); else { - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); + strcpy( szfound, "!" ); + strcat( szfound, szgroupname ); + sprintf( sznum, "%d", ipick ); + strcat( szfound, sznum ); return ipick; } } @@ -1103,18 +1131,18 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) // 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 SENTENCEG_GetIndex( const char *szgroupname ) { int i; - if (!fSentencesInit || !szgroupname) + if( !fSentencesInit || !szgroupname ) return -1; // search rgsentenceg for match on szgroupname i = 0; - while (rgsentenceg[i].count) + while( rgsentenceg[i].count ) { - if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) + if( !strcmp( szgroupname, rgsentenceg[i].szgroupname ) ) return i; i++; } @@ -1127,95 +1155,92 @@ int SENTENCEG_GetIndex(const char *szgroupname) // 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) +int SENTENCEG_PlayRndI( edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch ) { char name[64]; int ipick; - if (!fSentencesInit) + if( !fSentencesInit ) return -1; name[0] = 0; - ipick = USENTENCEG_Pick(isentenceg, name); + ipick = USENTENCEG_Pick( isentenceg, name ); if( ipick > 0 ) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); + 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) +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) + if( !fSentencesInit ) return -1; name[0] = 0; - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 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); + 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) +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) + if( !fSentencesInit ) return -1; name[0] = 0; isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) + 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); + 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) +void SENTENCEG_Stop( edict_t *entity, int isentenceg, int ipick ) { char buffer[64]; char sznum[8]; - if (!fSentencesInit) + if( !fSentencesInit ) return; - if (isentenceg < 0 || ipick < 0) + if( isentenceg < 0 || ipick < 0 ) return; - strcpy(buffer, "!"); - strcat(buffer, rgsentenceg[isentenceg].szgroupname); - sprintf(sznum, "%d", ipick); - strcat(buffer, sznum); + strcpy( buffer, "!" ); + strcat( buffer, rgsentenceg[isentenceg].szgroupname ); + sprintf( sznum, "%d", ipick ); + strcat( buffer, sznum ); - STOP_SOUND(entity, CHAN_VOICE, buffer); + STOP_SOUND( entity, CHAN_VOICE, buffer ); } // open sentences.txt, scan for groups, build rgsentenceg @@ -1229,47 +1254,47 @@ void SENTENCEG_Init() int i, j; int isentencegs; - if (fSentencesInit) + if( fSentencesInit ) return; - memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); + memset( gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX ); gcallsentences = 0; - memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); - memset(buffer, 0, 512); - memset(szgroup, 0, 64); + 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 ) + if( !pMemFile ) return; // for each line in the file... - while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) + while( memfgets( pMemFile, fileSize, filePos, buffer, 511 ) != NULL ) { // skip whitespace i = 0; - while(buffer[i] && buffer[i] == ' ') + while( buffer[i] && buffer[i] == ' ' ) i++; - if (!buffer[i]) + if( !buffer[i] ) continue; - if (buffer[i] == '/' || !isalpha(buffer[i])) + if( buffer[i] == '/' || !isalpha( buffer[i] ) ) continue; // get sentence name j = i; - while (buffer[j] && buffer[j] != ' ') + while( buffer[j] && buffer[j] != ' ' ) j++; - if (!buffer[j]) + if( !buffer[j] ) continue; - if (gcallsentences > CVOXFILESENTENCEMAX) + if( gcallsentences > CVOXFILESENTENCEMAX ) { - ALERT (at_error, "Too many sentences in sentences.txt!\n"); + ALERT( at_error, "Too many sentences in sentences.txt!\n" ); break; } @@ -1277,51 +1302,50 @@ void SENTENCEG_Init() 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 ); + 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) + if( j <= i ) continue; - if (!isdigit(buffer[j])) + if( !isdigit( buffer[j] ) ) continue; // cut out suffix numbers - while (j > i && isdigit(buffer[j])) + while( j > i && isdigit( buffer[j] ) ) j--; - if (j <= i) + if( j <= i ) continue; - buffer[j+1] = 0; + buffer[j + 1] = 0; // if new name doesn't match previous group name, // make a new group. - - if (strcmp(szgroup, &(buffer[i]))) + 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) + if( isentencegs >= CSENTENCEG_MAX ) { - ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); + ALERT( at_error, "Too many sentence groups in sentences.txt!\n" ); break; } - strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); + strcpy( rgsentenceg[isentencegs].szgroupname, &( buffer[i] ) ); rgsentenceg[isentencegs].count = 1; - strcpy(szgroup, &(buffer[i])); + strcpy( szgroup, &( buffer[i] ) ); continue; } else { //name matches with previous, increment group count - if (isentencegs >= 0) + if( isentencegs >= 0 ) rgsentenceg[isentencegs].count++; } } @@ -1334,30 +1358,30 @@ void SENTENCEG_Init() i = 0; - while (rgsentenceg[i].count && i < CSENTENCEG_MAX) + while( rgsentenceg[i].count && i < CSENTENCEG_MAX ) { - USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); + 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) +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)) + for( i = 0; i < gcallsentences; i++ ) + if( !stricmp( gszallsentencenames[i], sample + 1 ) ) { - if (sentencenum) + if( sentencenum ) { - strcpy(sentencenum, "!"); - sprintf(sznum, "%d", i); - strcat(sentencenum, sznum); + strcpy( sentencenum, "!" ); + sprintf( sznum, "%d", i ); + strcat( sentencenum, sznum ); } return i; } @@ -1365,64 +1389,63 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum) return -1; } -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch) +void EMIT_SOUND_DYN( edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch ) { - if (sample && *sample == '!') + if( sample && *sample == '!' ) { char name[32]; - if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); + 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); + 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) +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; + 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); + 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) +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; + 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); + 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) +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; + 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); + if( fvol > 0.05 ) + SENTENCEG_PlayRndSz( entity, groupname, fvol, ATTN_NORM, 0, pitch ); } // ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== @@ -1446,39 +1469,39 @@ char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) { // Bullet-proofing - if ( !pMemFile || !pBuffer ) + if( !pMemFile || !pBuffer ) return NULL; - if ( filePos >= fileSize ) + 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); + 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 ) + while( i < last && !stop ) { - if ( pMemFile[i] == '\n' ) + if( pMemFile[i] == '\n' ) stop = 1; i++; } // If we actually advanced the pointer, copy it over - if ( i != filePos ) + if( i != filePos ) { // We read in size bytes int size = i - filePos; // copy it out - memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); + memcpy( pBuffer, pMemFile + filePos, sizeof(byte) * size ); // If the buffer isn't full, terminate (this is always true) - if ( size < bufferSize ) + if( size < bufferSize ) pBuffer[size] = 0; // Update file pointer @@ -1497,56 +1520,56 @@ void TEXTURETYPE_Init() byte *pMemFile; int fileSize, filePos = 0; - if (fTextureTypeInit) + if( fTextureTypeInit ) return; - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); + memset( &( grgszTextureName[0][0] ), 0, CTEXTURESMAX * CBTEXTURENAMEMAX ); + memset( grgchTextureType, 0, CTEXTURESMAX ); gcTextures = 0; - memset(buffer, 0, 512); + memset( buffer, 0, 512 ); pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); - if ( !pMemFile ) + if( !pMemFile ) return; // for each line in the file... - while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) + while( memfgets( pMemFile, fileSize, filePos, buffer, 511 ) != NULL && ( gcTextures < CTEXTURESMAX) ) { // skip whitespace i = 0; - while(buffer[i] && isspace(buffer[i])) + while( buffer[i] && isspace( buffer[i] ) ) i++; - if (!buffer[i]) + if( !buffer[i] ) continue; // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) + if( buffer[i] == '/' || !isalpha( buffer[i] ) ) continue; // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); + grgchTextureType[gcTextures] = toupper( buffer[i++] ); // skip whitespace - while(buffer[i] && isspace(buffer[i])) + while( buffer[i] && isspace( buffer[i] ) ) i++; - if (!buffer[i]) + if( !buffer[i] ) continue; // get sentence name j = i; - while (buffer[j] && !isspace(buffer[j])) + while( buffer[j] && !isspace( buffer[j] ) ) j++; - if (!buffer[j]) + if( !buffer[j] ) continue; // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); + j = min( j, CBTEXTURENAMEMAX - 1 + i ); buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); + strcpy( &( grgszTextureName[gcTextures++][0] ), &( buffer[i] ) ); } g_engfuncs.pfnFreeFile( pMemFile ); @@ -1560,14 +1583,14 @@ void TEXTURETYPE_Init() // NOTE: this routine should ONLY be called if the // current texture under the player changes! -char TEXTURETYPE_Find(char *name) +char TEXTURETYPE_Find( char *name ) { // CONSIDER: pre-sort texture names and perform faster binary search here - for (int i = 0; i < gcTextures; i++) + for( int i = 0; i < gcTextures; i++ ) { - if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) - return (grgchTextureType[i]); + if( !strnicmp( name, &( grgszTextureName[i][0] ), CBTEXTURENAMEMAX - 1 ) ) + return grgchTextureType[i]; } return CHAR_TEX_CONCRETE; @@ -1577,7 +1600,7 @@ char TEXTURETYPE_Find(char *name) // 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) +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; @@ -1591,14 +1614,14 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int int cnt; float fattn = ATTN_NORM; - if ( !g_pGameRules->PlayTextureSounds() ) + if( !g_pGameRules->PlayTextureSounds() ) return 0.0; - CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); + CBaseEntity *pEntity = CBaseEntity::Instance( ptr->pHit ); chTextureType = 0; - if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) + if( pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) // hit body chTextureType = CHAR_TEX_FLESH; else @@ -1609,78 +1632,94 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int // copy trace vector into array for trace_texture - vecSrc.CopyToArray(rgfl1); - vecEnd.CopyToArray(rgfl2); + 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 ); + if( pEntity ) + pTextureName = TRACE_TEXTURE( ENT( pEntity->pev ), rgfl1, rgfl2 ); else - pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); + pTextureName = TRACE_TEXTURE( ENT( 0 ), rgfl1, rgfl2 ); - if ( pTextureName ) + if( pTextureName ) { // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') + if( *pTextureName == '-' || *pTextureName == '+' ) pTextureName += 2; - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + if( *pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ' ) pTextureName++; // '}}' - strcpy(szbuffer, pTextureName); + strcpy( szbuffer, pTextureName ); szbuffer[CBTEXTURENAMEMAX - 1] = 0; - // ALERT ( at_console, "texture hit: %s\n", szbuffer); + // ALERT( at_console, "texture hit: %s\n", szbuffer ); // get texture type - chTextureType = TEXTURETYPE_Find(szbuffer); + chTextureType = TEXTURETYPE_Find( szbuffer ); } } - switch (chTextureType) + switch( chTextureType ) { default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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"; @@ -1688,16 +1727,18 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int break; case CHAR_TEX_GLASS: case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; + 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) + if( iBulletType == BULLET_PLAYER_CROWBAR ) return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; + fvol = 1.0; + fvolbar = 0.2; rgsz[0] = "weapons/bullet_hit1.wav"; rgsz[1] = "weapons/bullet_hit2.wav"; fattn = 1.0; @@ -1706,34 +1747,42 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int } // did we hit a breakable? - if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) + if( pEntity && FClassnameIs( pEntity->pev, "func_breakable" ) ) { // drop volumes, the object will already play a damaged sound fvol /= 1.5; - fvolbar /= 2.0; + fvolbar /= 2.0; } - else if (chTextureType == CHAR_TEX_COMPUTER) + else if( chTextureType == CHAR_TEX_COMPUTER ) { // play random spark if computer - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) + 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) ) + 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; + 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)); - + 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; } @@ -1741,26 +1790,26 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int // // Speaker class. Used for announcements per level, for door lock/unlock spoken voice. // - class CSpeaker : public CBaseEntity { public: - void KeyValue( KeyValueData* pkvd); + void KeyValue( KeyValueData *pkvd ); void Spawn( void ); void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + 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 Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual int ObjectCaps( void ) { return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ); } - int m_preset; // preset number + int m_preset; // preset number }; LINK_ENTITY_TO_CLASS( speaker, CSpeaker ) + TYPEDESCRIPTION CSpeaker::m_SaveData[] = { DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), @@ -1771,39 +1820,39 @@ IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ) // // ambient_generic - general-purpose user-defined static sound // -void CSpeaker :: Spawn( void ) +void CSpeaker::Spawn( void ) { - char* szSoundFile = (char*) STRING(pev->message); + char *szSoundFile = (char*) STRING( pev->message ); - if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) + 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( &CBaseEntity::SUB_Remove ); return; } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; - SetThink( &CSpeaker::SpeakerThink); + SetThink( &CSpeaker::SpeakerThink ); pev->nextthink = 0.0; // allow on/off switching via 'use' function. SetUse( &CSpeaker::ToggleUse ); - Precache( ); + Precache(); } #define ANNOUNCE_MINUTES_MIN 0.25 #define ANNOUNCE_MINUTES_MAX 2.25 -void CSpeaker :: Precache( void ) +void CSpeaker::Precache( void ) { - if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) + 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); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 5.0, 15.0 ); } -void CSpeaker :: SpeakerThink( void ) +void CSpeaker::SpeakerThink( void ) { char* szSoundFile; float flvolume = pev->health * 0.1; @@ -1812,39 +1861,63 @@ void CSpeaker :: SpeakerThink( void ) int pitch = 100; // Wait for the talkmonster to finish first. - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) { pev->nextthink = CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ); return; } - if (m_preset) + if( m_preset ) { // go lookup preset text, assign szSoundFile - switch (m_preset) + 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; + 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); + szSoundFile = (char*)STRING( pev->message ); - if (szSoundFile[0] == '!') + if( szSoundFile[0] == '!' ) { // play single sentence, one shot - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - flvolume, flattenuation, flags, pitch); + UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, + flvolume, flattenuation, flags, pitch ); // shut off and reset pev->nextthink = 0.0; @@ -1852,11 +1925,11 @@ void CSpeaker :: SpeakerThink( void ) 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); + 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); + 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 } @@ -1867,28 +1940,28 @@ void CSpeaker :: SpeakerThink( void ) // // 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 ) +void CSpeaker::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - int fActive = (pev->nextthink > 0.0); + int fActive = ( pev->nextthink > 0.0 ); // fActive is TRUE only if an announcement is pending - if ( useType != USE_TOGGLE ) + 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) ) + if( ( fActive && useType == USE_ON ) || ( !fActive && useType == USE_OFF ) ) return; } - if ( useType == USE_ON ) + if( useType == USE_ON ) { // turn on announcements pev->nextthink = gpGlobals->time + 0.1; return; } - if ( useType == USE_OFF ) + if( useType == USE_OFF ) { // turn off announcements pev->nextthink = 0.0; @@ -1896,7 +1969,7 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ } // Toggle announcements - if ( fActive ) + if( fActive ) { // turn off announcements pev->nextthink = 0.0; @@ -1911,12 +1984,12 @@ void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ // KeyValue - load keyvalue pairs into member data // NOTE: called BEFORE spawn! -void CSpeaker :: KeyValue( KeyValueData *pkvd ) +void CSpeaker::KeyValue( KeyValueData *pkvd ) { // preset - if (FStrEq(pkvd->szKeyName, "preset")) + if( FStrEq( pkvd->szKeyName, "preset" ) ) { - m_preset = atoi(pkvd->szValue); + m_preset = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else diff --git a/dlls/spectator.cpp b/dlls/spectator.cpp index e4174a31..0ac09640 100644 --- a/dlls/spectator.cpp +++ b/dlls/spectator.cpp @@ -32,7 +32,7 @@ SpectatorConnect called when a spectator connects to a server ============ */ -void CBaseSpectator::SpectatorConnect(void) +void CBaseSpectator::SpectatorConnect( void ) { pev->flags = FL_SPECTATOR; pev->solid = SOLID_NOT; @@ -48,7 +48,7 @@ SpectatorDisconnect called when a spectator disconnects from a server ============ */ -void CBaseSpectator::SpectatorDisconnect(void) +void CBaseSpectator::SpectatorDisconnect( void ) { } @@ -59,14 +59,14 @@ SpectatorImpulseCommand Called by SpectatorThink if the spectator entered an impulse ================ */ -void CBaseSpectator::SpectatorImpulseCommand(void) +void CBaseSpectator::SpectatorImpulseCommand( void ) { - static edict_t *pGoal = NULL; - edict_t *pPreviousGoal; - edict_t *pCurrentGoal; - BOOL bFound; + static edict_t *pGoal = NULL; + edict_t *pPreviousGoal; + edict_t *pCurrentGoal; + BOOL bFound; - switch (pev->impulse) + switch( pev->impulse ) { case 1: // teleport the spectator to the next spawn point @@ -78,24 +78,24 @@ void CBaseSpectator::SpectatorImpulseCommand(void) // back around bFound = FALSE; - while (1) + while( 1 ) { - pCurrentGoal = FIND_ENTITY_BY_CLASSNAME(pCurrentGoal, "info_player_deathmatch"); + pCurrentGoal = FIND_ENTITY_BY_CLASSNAME( pCurrentGoal, "info_player_deathmatch" ); // Looped around, failure - if (pCurrentGoal == pPreviousGoal) + if( pCurrentGoal == pPreviousGoal ) { - ALERT(at_console, "Could not find a spawn spot.\n"); + 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)) + if( !FNullEnt( pCurrentGoal ) ) { bFound = TRUE; break; } } - if (!bFound) // Didn't find a good spot. + if( !bFound ) // Didn't find a good spot. break; pGoal = pCurrentGoal; @@ -104,7 +104,7 @@ void CBaseSpectator::SpectatorImpulseCommand(void) pev->fixangle = FALSE; break; default: - ALERT(at_console, "Unknown spectator impulse\n"); + ALERT( at_console, "Unknown spectator impulse\n" ); break; } @@ -118,17 +118,17 @@ SpectatorThink Called every frame after physics are run ================ */ -void CBaseSpectator::SpectatorThink(void) +void CBaseSpectator::SpectatorThink( void ) { - if (!(pev->flags & FL_SPECTATOR)) + if( !( pev->flags & FL_SPECTATOR ) ) { pev->flags = FL_SPECTATOR; } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NOCLIP; - if (pev->impulse) + if( pev->impulse ) SpectatorImpulseCommand(); } diff --git a/dlls/spectator.h b/dlls/spectator.h index d459a384..90f8678f 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -18,10 +18,10 @@ class CBaseSpectator : public CBaseEntity { public: void Spawn(); - void SpectatorConnect(void); - void SpectatorDisconnect(void); - void SpectatorThink(void); + void SpectatorConnect( void ); + void SpectatorDisconnect( void ); + void SpectatorThink( void ); private: - void SpectatorImpulseCommand(void); -}; \ No newline at end of file + void SpectatorImpulseCommand( void ); +}; diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp index 6785018c..a89f39f9 100644 --- a/dlls/squadmonster.cpp +++ b/dlls/squadmonster.cpp @@ -47,18 +47,18 @@ 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 ) +BOOL CSquadMonster::OccupySlot( int iDesiredSlots ) { int i; int iMask; int iSquadSlots; - if ( !InSquad() ) + if( !InSquad() ) { return TRUE; } - if ( SquadEnemySplit() ) + 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 @@ -69,7 +69,7 @@ BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) CSquadMonster *pSquadLeader = MySquadLeader(); - if ( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) ) + if( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) ) { // none of the desired slots are available. return FALSE; @@ -77,17 +77,17 @@ BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) iSquadSlots = pSquadLeader->m_afSquadSlots; - for ( i = 0; i < NUM_SLOTS; i++ ) + 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 ); + //ALERT( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); return TRUE; } } @@ -97,13 +97,13 @@ BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) } //========================================================= -// VacateSlot +// VacateSlot //========================================================= -void CSquadMonster :: VacateSlot() +void CSquadMonster::VacateSlot() { - if ( m_iMySlot != bits_NO_SLOT && InSquad() ) + if( m_iMySlot != bits_NO_SLOT && InSquad() ) { - //ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); + //ALERT( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); MySquadLeader()->m_afSquadSlots &= ~m_iMySlot; m_iMySlot = bits_NO_SLOT; } @@ -112,7 +112,7 @@ void CSquadMonster :: VacateSlot() //========================================================= // ScheduleChange //========================================================= -void CSquadMonster :: ScheduleChange ( void ) +void CSquadMonster::ScheduleChange ( void ) { VacateSlot(); } @@ -120,16 +120,16 @@ void CSquadMonster :: ScheduleChange ( void ) //========================================================= // Killed //========================================================= -void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib ) +void CSquadMonster::Killed( entvars_t *pevAttacker, int iGib ) { VacateSlot(); - if ( InSquad() ) + if( InSquad() ) { MySquadLeader()->SquadRemove( this ); } - CBaseMonster :: Killed ( pevAttacker, iGib ); + CBaseMonster::Killed( pevAttacker, iGib ); } // These functions are still awaiting conversion to CSquadMonster @@ -141,19 +141,19 @@ void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib ) // If I am pRemove, promote m_pSquadNext to leader // //========================================================= -void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) +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()) + if( pRemove == MySquadLeader() ) { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS - 1; i++ ) { - CSquadMonster *pMember = MySquadMember(i); - if (pMember) + CSquadMonster *pMember = MySquadMember( i ); + if( pMember ) { pMember->m_hSquadLeader = NULL; m_hSquadMember[i] = NULL; @@ -163,11 +163,11 @@ void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) else { CSquadMonster *pSquadLeader = MySquadLeader(); - if (pSquadLeader) + if( pSquadLeader ) { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS - 1; i++ ) { - if (pSquadLeader->m_hSquadMember[i] == this) + if( pSquadLeader->m_hSquadMember[i] == this ) { pSquadLeader->m_hSquadMember[i] = NULL; break; @@ -184,15 +184,15 @@ void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) // SquadAdd(), add pAdd to my squad // //========================================================= -BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) +BOOL CSquadMonster::SquadAdd( CSquadMonster *pAdd ) { - ASSERT( pAdd!=NULL ); + ASSERT( pAdd != NULL ); ASSERT( !pAdd->InSquad() ); ASSERT( this->IsLeader() ); - for (int i = 0; i < MAX_SQUAD_MEMBERS-1; i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS - 1; i++ ) { - if (m_hSquadMember[i] == NULL) + if( m_hSquadMember[i] == NULL ) { m_hSquadMember[i] = pAdd; pAdd->m_hSquadLeader = this; @@ -210,10 +210,10 @@ BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) // members who don't have current info. // //========================================================= -void CSquadMonster :: SquadPasteEnemyInfo ( void ) +void CSquadMonster::SquadPasteEnemyInfo( void ) { - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) + CSquadMonster *pSquadLeader = MySquadLeader(); + if( pSquadLeader ) pSquadLeader->m_vecEnemyLKP = m_vecEnemyLKP; } @@ -225,10 +225,10 @@ void CSquadMonster :: SquadPasteEnemyInfo ( void ) // so the most recent data is always available here. // //========================================================= -void CSquadMonster :: SquadCopyEnemyInfo ( void ) +void CSquadMonster::SquadCopyEnemyInfo( void ) { - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) + CSquadMonster *pSquadLeader = MySquadLeader(); + if( pSquadLeader ) m_vecEnemyLKP = pSquadLeader->m_vecEnemyLKP; } @@ -238,27 +238,27 @@ void CSquadMonster :: SquadCopyEnemyInfo ( void ) // the same entity. // //========================================================= -void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) +void CSquadMonster::SquadMakeEnemy( CBaseEntity *pEnemy ) { - if (!InSquad()) + if( !InSquad() ) return; - if ( !pEnemy ) + if( !pEnemy ) { - ALERT ( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" ); + ALERT( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" ); return; } - CSquadMonster *pSquadLeader = MySquadLeader( ); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + CSquadMonster *pSquadLeader = MySquadLeader(); + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember) + 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 != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY ) ) { - if ( pMember->m_hEnemy != NULL) + if( pMember->m_hEnemy != NULL ) { // remember their current enemy pMember->PushEnemy( pMember->m_hEnemy, pMember->m_vecEnemyLKP ); @@ -266,7 +266,7 @@ void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) // give them a new enemy pMember->m_hEnemy = pEnemy; pMember->m_vecEnemyLKP = pEnemy->pev->origin; - pMember->SetConditions ( bits_COND_NEW_ENEMY ); + pMember->SetConditions( bits_COND_NEW_ENEMY ); } } } @@ -278,16 +278,16 @@ void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) // callable from leaders & followers // //========================================================= -int CSquadMonster :: SquadCount( void ) +int CSquadMonster::SquadCount( void ) { - if (!InSquad()) + if( !InSquad() ) return 0; CSquadMonster *pSquadLeader = MySquadLeader(); int squadCount = 0; - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - if (pSquadLeader->MySquadMember(i) != NULL) + if( pSquadLeader->MySquadMember( i ) != NULL ) squadCount++; } @@ -300,16 +300,16 @@ int CSquadMonster :: SquadCount( void ) // link them as a group. returns the group size // //========================================================= -int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) +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() ) + if( InSquad() ) return 0; - if ( maxMembers < 2 ) + if( maxMembers < 2 ) return 0; // I am my own leader @@ -318,20 +318,20 @@ int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) CBaseEntity *pEntity = NULL; - if ( !FStringNull( pev->netname ) ) + 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 ) + while( pEntity ) { CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); - if ( pRecruit ) + if( pRecruit ) { - if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) + if( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) { // minimum protection here against user error.in worldcraft. - if (!SquadAdd( pRecruit )) + if( !SquadAdd( pRecruit ) ) break; squadCount++; } @@ -342,22 +342,22 @@ int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) } else { - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius )) != NULL) + while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius ) ) != NULL ) { - CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( ); + CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); - if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) + 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))) && + 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( tr.flFraction == 1.0 ) { - if (!SquadAdd( pRecruit )) + if( !SquadAdd( pRecruit ) ) break; squadCount++; @@ -368,7 +368,7 @@ int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) } // no single member squads - if (squadCount == 1) + if( squadCount == 1 ) { m_hSquadLeader = NULL; } @@ -379,16 +379,16 @@ int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) //========================================================= // CheckEnemy //========================================================= -int CSquadMonster :: CheckEnemy ( CBaseEntity *pEnemy ) +int CSquadMonster::CheckEnemy( CBaseEntity *pEnemy ) { int iUpdatedLKP; - iUpdatedLKP = CBaseMonster :: CheckEnemy ( m_hEnemy ); - + 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( InSquad() && (CBaseEntity *)m_hEnemy == MySquadLeader()->m_hEnemy ) { - if ( iUpdatedLKP ) + if( iUpdatedLKP ) { // have new enemy information, so paste to the squad. SquadPasteEnemyInfo(); @@ -406,16 +406,16 @@ int CSquadMonster :: CheckEnemy ( CBaseEntity *pEnemy ) //========================================================= // StartMonster //========================================================= -void CSquadMonster :: StartMonster( void ) +void CSquadMonster::StartMonster( void ) { - CBaseMonster :: StartMonster(); + CBaseMonster::StartMonster(); - if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) + if( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) { - if ( !FStringNull( pev->netname ) ) + 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 ) ) + if( !( pev->spawnflags & SF_SQUADMONSTER_LEADER ) ) { return; } @@ -424,12 +424,12 @@ void CSquadMonster :: StartMonster( void ) // try to form squads now. int iSquadSize = SquadRecruit( 1024, 4 ); - if ( iSquadSize ) + if( iSquadSize ) { - ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); + ALERT( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); } - if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) ) + if( IsLeader() && FClassnameIs( pev, "monster_human_grunt" ) ) { SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack pev->skin = 0; @@ -443,26 +443,25 @@ void CSquadMonster :: StartMonster( void ) // 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 ) +BOOL CSquadMonster::NoFriendlyFire( void ) { - if ( !InSquad() ) + if( !InSquad() ) { return TRUE; } - CPlane backPlane; - CPlane leftPlane; - CPlane rightPlane; + CPlane backPlane; + CPlane leftPlane; + CPlane rightPlane; - Vector vecLeftSide; - Vector vecRightSide; - Vector v_left; + 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 != NULL ) + if( m_hEnemy != NULL ) { - UTIL_MakeVectors ( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); + UTIL_MakeVectors( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); } else { @@ -470,30 +469,29 @@ BOOL CSquadMonster :: NoFriendlyFire( void ) return FALSE; } - //UTIL_MakeVectors ( pev->angles ); - + //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 ); + 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 ); + 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++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember && pMember != this) + 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) ) + 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; @@ -508,27 +506,27 @@ BOOL CSquadMonster :: NoFriendlyFire( void ) // GetIdealState - surveys the Conditions information available // and finds the best new state for a monster. //========================================================= -MONSTERSTATE CSquadMonster :: GetIdealState ( void ) +MONSTERSTATE CSquadMonster::GetIdealState ( void ) { - int iConditions; + int iConditions; iConditions = IScheduleFlags(); // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) + switch( m_MonsterState ) { case MONSTERSTATE_IDLE: case MONSTERSTATE_ALERT: - if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) + if( HasConditions( bits_COND_NEW_ENEMY ) && InSquad() ) { - SquadMakeEnemy ( m_hEnemy ); + SquadMakeEnemy( m_hEnemy ); } break; default: break; } - return CBaseMonster :: GetIdealState(); + return CBaseMonster::GetIdealState(); } //========================================================= @@ -536,14 +534,14 @@ MONSTERSTATE CSquadMonster :: GetIdealState ( void ) // cover location is a good one to move to. (currently based // on proximity to others in the squad) //========================================================= -BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation ) +BOOL CSquadMonster::FValidateCover( const Vector &vecCoverLocation ) { - if ( !InSquad() ) + if( !InSquad() ) { return TRUE; } - if (SquadMemberInRange( vecCoverLocation, 128 )) + if( SquadMemberInRange( vecCoverLocation, 128 ) ) { // another squad member is too close to this piece of cover. return FALSE; @@ -556,18 +554,18 @@ BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation ) // SquadEnemySplit- returns TRUE if not all squad members // are fighting the same enemy. //========================================================= -BOOL CSquadMonster :: SquadEnemySplit ( void ) +BOOL CSquadMonster::SquadEnemySplit( void ) { - if (!InSquad()) + if( !InSquad() ) return FALSE; - CSquadMonster *pSquadLeader = MySquadLeader(); - CBaseEntity *pEnemy = pSquadLeader->m_hEnemy; + CSquadMonster *pSquadLeader = MySquadLeader(); + CBaseEntity *pEnemy = pSquadLeader->m_hEnemy; - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy) + CSquadMonster *pMember = pSquadLeader->MySquadMember( i ); + if( pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy ) { return TRUE; } @@ -580,31 +578,31 @@ BOOL CSquadMonster :: SquadEnemySplit ( void ) // 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 ) +BOOL CSquadMonster::SquadMemberInRange( const Vector &vecLocation, float flDist ) { - if (!InSquad()) + if( !InSquad() ) return FALSE; CSquadMonster *pSquadLeader = MySquadLeader(); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) + for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { - CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i); - if (pSquadMember && (vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist) + CSquadMonster *pSquadMember = pSquadLeader->MySquadMember( i ); + if( pSquadMember && ( vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist ) return TRUE; } return FALSE; } -extern Schedule_t slChaseEnemyFailed[]; +extern Schedule_t slChaseEnemyFailed[]; Schedule_t *CSquadMonster::GetScheduleOfType( int iType ) { - switch ( iType ) + switch( iType ) { case SCHED_CHASE_ENEMY_FAILED: { - return &slChaseEnemyFailed[ 0 ]; + return &slChaseEnemyFailed[0]; } default: return CBaseMonster::GetScheduleOfType( iType ); diff --git a/dlls/squadmonster.h b/dlls/squadmonster.h index 43363b98..ecd75ee5 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -57,16 +57,16 @@ 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; + 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 m_iMySlot;// this is the behaviour slot that the monster currently holds in the squad. - int CheckEnemy ( CBaseEntity *pEnemy ); - void StartMonster ( void ); + int CheckEnemy( CBaseEntity *pEnemy ); + void StartMonster( void ); void VacateSlot( void ); void ScheduleChange( void ); void Killed( entvars_t *pevAttacker, int iGib ); @@ -74,45 +74,45 @@ public: BOOL NoFriendlyFire( void ); // squad functions still left in base class - CSquadMonster *MySquadLeader( ) - { - CSquadMonster *pSquadLeader = (CSquadMonster *)((CBaseEntity *)m_hSquadLeader); - if (pSquadLeader != NULL) + 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) + CSquadMonster *MySquadMember( int i ) + { + if( i >= MAX_SQUAD_MEMBERS - 1 ) return this; else - return (CSquadMonster *)((CBaseEntity *)m_hSquadMember[i]); + return (CSquadMonster *)( (CBaseEntity *)m_hSquadMember[i] ); } - int InSquad ( void ) { return m_hSquadLeader != NULL; } - int IsLeader ( void ) { return m_hSquadLeader == this; } - int SquadJoin ( int searchRadius ); - int SquadRecruit ( int searchRadius, int maxMembers ); - int SquadCount( void ); + int InSquad( void ) { return m_hSquadLeader != NULL; } + 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 ); + 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 Save( CSave &save ); int Restore( CRestore &restore ); - BOOL FValidateCover ( const Vector &vecCoverLocation ); + BOOL FValidateCover( const Vector &vecCoverLocation ); - MONSTERSTATE GetIdealState ( void ); - Schedule_t *GetScheduleOfType ( int iType ); + MONSTERSTATE GetIdealState( void ); + Schedule_t *GetScheduleOfType( int iType ); }; diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index ab79638e..22200b74 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -24,14 +24,16 @@ #include "soundent.h" #include "gamerules.h" -enum w_squeak_e { +enum w_squeak_e +{ WSQUEAK_IDLE1 = 0, WSQUEAK_FIDGET, WSQUEAK_JUMP, WSQUEAK_RUN }; -enum squeak_e { +enum squeak_e +{ SQUEAK_IDLE1 = 0, SQUEAK_FIDGETFIT, SQUEAK_FIDGETNIP, @@ -41,22 +43,21 @@ enum squeak_e { }; #ifndef CLIENT_DLL - class CSqueakGrenade : public CGrenade { void Spawn( void ); void Precache( void ); - int Classify( void ); + int Classify( void ); void EXPORT SuperBounceTouch( CBaseEntity *pOther ); void EXPORT HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } + 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; static float m_flNextBounceSoundTime; @@ -67,7 +68,7 @@ class CSqueakGrenade : public CGrenade float m_flNextHit; Vector m_posPrev; EHANDLE m_hOwner; - int m_iMyClass; + int m_iMyClass; }; float CSqueakGrenade::m_flNextBounceSoundTime = 0; @@ -88,15 +89,15 @@ IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ) #define SQUEEK_DETONATE_DELAY 15.0 -int CSqueakGrenade :: Classify ( void ) +int CSqueakGrenade::Classify( void ) { - if (m_iMyClass != 0) + if( m_iMyClass != 0 ) return m_iMyClass; // protect against recursion - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { m_iMyClass = CLASS_INSECT; // no one cares about it - switch( m_hEnemy->Classify( ) ) + switch( m_hEnemy->Classify() ) { case CLASS_PLAYER: case CLASS_HUMAN_PASSIVE: @@ -110,16 +111,16 @@ int CSqueakGrenade :: Classify ( void ) return CLASS_ALIEN_BIOWEAPON; } -void CSqueakGrenade :: Spawn( void ) +void CSqueakGrenade::Spawn( void ) { - Precache( ); + 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)); + 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 ); @@ -128,10 +129,10 @@ void CSqueakGrenade :: Spawn( void ) 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->takedamage = DAMAGE_AIM; + pev->health = gSkillData.snarkHealth; + pev->gravity = 0.5; + pev->friction = 0.5; pev->dmg = gSkillData.snarkDmgPop; @@ -139,28 +140,28 @@ void CSqueakGrenade :: Spawn( void ) m_flFieldOfView = 0; // 180 degrees - if ( pev->owner ) + if( pev->owner ) m_hOwner = Instance( pev->owner ); m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. pev->sequence = WSQUEAK_RUN; - ResetSequenceInfo( ); + 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"); + 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 ) +void CSqueakGrenade::Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible SetThink( &CBaseEntity::SUB_Remove ); @@ -173,69 +174,69 @@ void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) pev->takedamage = DAMAGE_NO; // play squeek blast - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); + 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 ); + CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); - if (m_hOwner != NULL) - RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); + if( m_hOwner != NULL ) + RadiusDamage( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); else - RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); + RadiusDamage( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); // reset owner so death message happens - if (m_hOwner != NULL) + if( m_hOwner != NULL ) pev->owner = m_hOwner->edict(); - CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); + CBaseMonster::Killed( pevAttacker, GIB_ALWAYS ); } -void CSqueakGrenade :: GibMonster( void ) +void CSqueakGrenade::GibMonster( void ) { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); + 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()) + if( !IsInWorld() ) { SetTouch( NULL ); UTIL_Remove( this ); return; } - - StudioFrameAdvance( ); + + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; // explode when ready - if (gpGlobals->time >= m_flDie) + if( gpGlobals->time >= m_flDie ) { - g_vecAttackDir = pev->velocity.Normalize( ); + g_vecAttackDir = pev->velocity.Normalize(); pev->health = -1; Killed( pev, 0 ); return; } // float - if (pev->waterlevel != 0) + if( pev->waterlevel != 0 ) { - if (pev->movetype == MOVETYPE_BOUNCE) + 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 ) ) + else if( ( pev->movetype = MOVETYPE_FLY ) ) { pev->movetype = MOVETYPE_BOUNCE; } // return if not time to hunt - if (m_flNextHunt > gpGlobals->time) + if( m_flNextHunt > gpGlobals->time ) return; m_flNextHunt = gpGlobals->time + 2.0; @@ -246,41 +247,41 @@ void CSqueakGrenade::HuntThink( void ) Vector vecFlat = pev->velocity; vecFlat.z = 0; - vecFlat = vecFlat.Normalize( ); + vecFlat = vecFlat.Normalize(); UTIL_MakeVectors( pev->angles ); - if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) + if( m_hEnemy == NULL || !m_hEnemy->IsAlive() ) { // find target, bounce a bit towards it. Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); + m_hEnemy = BestVisibleEnemy(); } // squeek if it's about time blow up - if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) + 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 ); + 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) + float flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY ); + if( flpitch < 80 ) flpitch = 80; - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { - if (FVisible( m_hEnemy )) + if( FVisible( m_hEnemy ) ) { vecDir = m_hEnemy->EyePosition() - pev->origin; - m_vecTarget = vecDir.Normalize( ); + m_vecTarget = vecDir.Normalize(); } float flVel = pev->velocity.Length(); - float flAdj = 50.0 / (flVel + 10.0); + float flAdj = 50.0 / ( flVel + 10.0 ); - if (flAdj > 1.2) + if( flAdj > 1.2 ) flAdj = 1.2; // ALERT( at_console, "think : enemy\n"); @@ -290,20 +291,20 @@ void CSqueakGrenade::HuntThink( void ) pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; } - if (pev->flags & FL_ONGROUND) + if( pev->flags & FL_ONGROUND ) { pev->avelocity = Vector( 0, 0, 0 ); } else { - if (pev->avelocity == Vector( 0, 0, 0)) + 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) + if( ( pev->origin - m_posPrev ).Length() < 1.0 ) { pev->velocity.x = RANDOM_FLOAT( -100, 100 ); pev->velocity.y = RANDOM_FLOAT( -100, 100 ); @@ -317,12 +318,12 @@ void CSqueakGrenade::HuntThink( void ) void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) { - float flpitch; + float flpitch; - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); // don't hit the guy that launched this grenade - if ( pev->owner && pOther->edict() == pev->owner ) + if( pev->owner && pOther->edict() == pev->owner ) return; // at least until we've bounced once @@ -332,26 +333,26 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) pev->angles.z = 0; // avoid bouncing too much - if (m_flNextHit > gpGlobals->time) + 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); + flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY ); - if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) + if( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) { // attack! // make sure it's me who has touched them - if (tr.pHit == pOther->edict()) + if( tr.pHit == pOther->edict() ) { // and it's not another squeakgrenade - if (tr.pHit->v.modelindex != pev->modelindex) + if( tr.pHit->v.modelindex != pev->modelindex ) { - // ALERT( at_console, "hit enemy\n"); + // ALERT( at_console, "hit enemy\n" ); ClearMultiDamage( ); - pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if (m_hOwner != NULL) + pOther->TraceAttack( pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); + if( m_hOwner != NULL ) ApplyMultiDamage( pev, m_hOwner->pev ); else ApplyMultiDamage( pev, pev ); @@ -360,46 +361,46 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) // 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); + 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"); + // ALERT( at_console, "been hit\n" ); } } m_flNextHit = gpGlobals->time + 0.1; m_flNextHunt = gpGlobals->time; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. - if ( gpGlobals->time < m_flNextBounceSoundTime ) + if( gpGlobals->time < m_flNextBounceSoundTime ) { // too soon! return; } } - if (!(pev->flags & FL_ONGROUND)) + if( !( pev->flags & FL_ONGROUND ) ) { // play bounce sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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 ); + 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 ); + CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 100, 0.1 ); } m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. @@ -408,16 +409,16 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ) -void CSqueak::Spawn( ) +void CSqueak::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_SNARK; - SET_MODEL(ENT(pev), "models/w_sqknest.mdl"); + 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; @@ -425,19 +426,19 @@ void CSqueak::Spawn( ) 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"); + 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" ); + m_usSnarkFire = PRECACHE_EVENT( 1, "events/snarkfire.sc" ); } -int CSqueak::GetItemInfo(ItemInfo *p) +int CSqueak::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "Snarks"; p->iMaxAmmo1 = SNARK_MAX_CARRY; p->pszAmmo2 = NULL; @@ -452,15 +453,15 @@ int CSqueak::GetItemInfo(ItemInfo *p) return 1; } -BOOL CSqueak::Deploy( ) +BOOL CSqueak::Deploy() { // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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); + 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; @@ -470,22 +471,22 @@ BOOL CSqueak::Deploy( ) void CSqueak::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) + + if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { - m_pPlayer->pev->weapons &= ~(1<pev->weapons &= ~( 1 << WEAPON_SNARK ); SetThink( &CBasePlayerItem::DestroyItem ); pev->nextthink = gpGlobals->time + 0.1; return; } SendWeaponAnim( SQUEAK_DOWN ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); + 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 ] ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { UTIL_MakeVectors( m_pPlayer->pev->v_angle ); TraceResult tr; @@ -494,7 +495,7 @@ void CSqueak::PrimaryAttack() // 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 ) + if( m_pPlayer->pev->flags & FL_DUCKING ) { trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); } @@ -502,15 +503,15 @@ void CSqueak::PrimaryAttack() // 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; + int flags; #ifdef CLIENT_WEAPONS - flags = FEV_NOTHOST; + flags = FEV_NOTHOST; #else - flags = 0; + 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 ); + 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 ) + if( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) { // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); @@ -519,12 +520,12 @@ void CSqueak::PrimaryAttack() pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; #endif // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 105 ); m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; @@ -545,14 +546,14 @@ void CSqueak::SecondaryAttack( void ) void CSqueak::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if (m_fJustThrown) + if( m_fJustThrown ) { m_fJustThrown = 0; - if ( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) + if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) { RetireWeapon(); return; @@ -565,12 +566,12 @@ void CSqueak::WeaponIdle( void ) int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) + if( flRand <= 0.75 ) { iAnim = SQUEAK_IDLE1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); } - else if (flRand <= 0.875) + else if( flRand <= 0.875 ) { iAnim = SQUEAK_FIDGETFIT; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; diff --git a/dlls/stats.cpp b/dlls/stats.cpp index a725af1a..cdb42d82 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -21,28 +21,28 @@ float AmmoDamage( const char *pName ) { - if ( !pName ) + if( !pName ) return 0; - if ( !strcmp( pName, "9mm" ) ) + if( !strcmp( pName, "9mm" ) ) return gSkillData.plrDmg9MM; - if ( !strcmp( pName, "357" ) ) + if( !strcmp( pName, "357" ) ) return gSkillData.plrDmg357; - if ( !strcmp( pName, "ARgrenades" ) ) + if( !strcmp( pName, "ARgrenades" ) ) return gSkillData.plrDmgM203Grenade; - if ( !strcmp( pName, "buckshot" ) ) + if( !strcmp( pName, "buckshot" ) ) return gSkillData.plrDmgBuckshot; - if ( !strcmp( pName, "bolts") ) + if( !strcmp( pName, "bolts") ) return gSkillData.plrDmgCrossbowMonster; - if ( !strcmp( pName, "rockets") ) + if( !strcmp( pName, "rockets") ) return gSkillData.plrDmgRPG; - if ( !strcmp( pName, "uranium") ) + if( !strcmp( pName, "uranium") ) return gSkillData.plrDmgGauss; - if ( !strcmp( pName, "Hand Grenade") ) + if( !strcmp( pName, "Hand Grenade") ) return gSkillData.plrDmgHandGrenade; - if ( !strcmp( pName, "Satchel Charge") ) + if( !strcmp( pName, "Satchel Charge") ) return gSkillData.plrDmgSatchel; - if ( !strcmp( pName, "Trip Mine") ) + if( !strcmp( pName, "Trip Mine") ) return gSkillData.plrDmgTripmine; return 0; @@ -53,7 +53,7 @@ void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, FILE *fp; fp = fopen( "stats.txt", "a" ); - if ( !fp ) + if( !fp ) return; fprintf( fp, "%6.2f, %6.2f, %6.2f, %s, %2d\n", dataTime, health, ammo, pMapname, skillLevel ); fclose( fp ); @@ -65,27 +65,27 @@ void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, 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; + 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}; +TESTSTATS gStats = { 0, 0, 0, 0, 0, 0, 0 }; void UpdateStats( CBasePlayer *pPlayer ) { int i; - int ammoCount[ MAX_AMMO_SLOTS ]; + 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 + + if( gpGlobals->time < gStats.lastGameTime ) // Changed level or died, don't b0rk { gStats.lastGameTime = gpGlobals->time; gStats.dataTime = gStats.gameTime; @@ -94,26 +94,26 @@ void UpdateStats( CBasePlayer *pPlayer ) gStats.gameTime += gpGlobals->time - gStats.lastGameTime; gStats.lastGameTime = gpGlobals->time; - for (i = 0; i < MAX_ITEM_TYPES; i++) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; - while (p) + while( p ) { ItemInfo II; - memset(&II, 0, sizeof(II)); - p->GetItemInfo(&II); + memset( &II, 0, sizeof(II) ); + p->GetItemInfo( &II ); + + int index = pPlayer->GetAmmoIndex( II.pszAmmo1 ); + if( index >= 0 ) + ammoCount[index] += ( (CBasePlayerWeapon *)p )->m_iClip; - 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++) + for( i = 1; i < MAX_AMMO_SLOTS; i++ ) { ammo += ammoCount[i] * AmmoDamage( CBasePlayerItem::AmmoInfoArray[i].pszName ); } @@ -122,12 +122,12 @@ void UpdateStats( CBasePlayer *pPlayer ) float ammoDelta = fabs( ammo - gStats.lastAmmo ); float healthDelta = fabs( health - gStats.lastHealth ); int forceWrite = 0; - if ( health <= 0 && gStats.lastHealth > 0 ) + if( health <= 0 && gStats.lastHealth > 0 ) forceWrite = 1; - if ( (ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD) && !forceWrite ) + if( ( ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD ) && !forceWrite ) { - if ( gStats.nextOutputTime == 0 ) + if( gStats.nextOutputTime == 0 ) gStats.dataTime = gStats.gameTime; gStats.lastAmmo = ammo; @@ -135,9 +135,9 @@ void UpdateStats( CBasePlayer *pPlayer ) gStats.nextOutputTime = gStats.gameTime + OUTPUT_LATENCY; } - else if ( (gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime) || forceWrite ) + else if( ( gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime ) || forceWrite ) { - UpdateStatsFile( gStats.dataTime, (char *)STRING(gpGlobals->mapname), health, ammo, (int)CVAR_GET_FLOAT("skill") ); + UpdateStatsFile( gStats.dataTime, (char *)STRING( gpGlobals->mapname ), health, ammo, (int)CVAR_GET_FLOAT( "skill" ) ); gStats.lastAmmo = ammo; gStats.lastHealth = health; diff --git a/dlls/subs.cpp b/dlls/subs.cpp index a9a8caa1..bc7baf18 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -29,15 +29,15 @@ extern CGraph WorldGraph; -extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget); +extern BOOL FEntIsVisible( entvars_t *pev, entvars_t *pevTarget ); extern DLL_GLOBAL int g_iSkillLevel; // Landmark class -void CPointEntity :: Spawn( void ) +void CPointEntity::Spawn( void ) { pev->solid = SOLID_NOT; - //UTIL_SetSize(pev, g_vecZero, g_vecZero); + //UTIL_SetSize( pev, g_vecZero, g_vecZero ); } class CNullEntity : public CBaseEntity @@ -47,32 +47,32 @@ public: }; // Null Entity, remove on startup -void CNullEntity :: Spawn( void ) +void CNullEntity::Spawn( void ) { - REMOVE_ENTITY(ENT(pev)); + REMOVE_ENTITY( ENT( pev ) ); } -LINK_ENTITY_TO_CLASS(info_null,CNullEntity) +LINK_ENTITY_TO_CLASS( info_null, CNullEntity ) class CBaseDMStart : public CPointEntity { public: - void KeyValue( KeyValueData *pkvd ); - BOOL IsTriggered( CBaseEntity *pEntity ); + 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) +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")) + if( FStrEq( pkvd->szKeyName, "master" ) ) { - pev->netname = ALLOC_STRING(pkvd->szValue); + pev->netname = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -89,46 +89,45 @@ BOOL CBaseDMStart::IsTriggered( CBaseEntity *pEntity ) // This updates global tables that need to know about entities being removed void CBaseEntity::UpdateOnRemove( void ) { - int i; + int i; - if ( FBitSet( pev->flags, FL_GRAPHED ) ) + 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++ ) + // 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( 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; + WorldGraph.m_pLinkPool[i].m_pLinkEnt = NULL; } } } - if ( pev->globalname ) + + if( pev->globalname ) gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); } // Convenient way to delay removing oneself -void CBaseEntity :: SUB_Remove( void ) +void CBaseEntity::SUB_Remove( void ) { UpdateOnRemove(); - if (pev->health > 0) + 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"); + ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n" ); } - REMOVE_ENTITY(ENT(pev)); + REMOVE_ENTITY( ENT( pev ) ); } - // Convenient way to explicitly do nothing (passed to functions that require a method) -void CBaseEntity :: SUB_DoNothing( void ) +void CBaseEntity::SUB_DoNothing( void ) { } - // Global Savedata for Delay TYPEDESCRIPTION CBaseDelay::m_SaveData[] = { @@ -138,16 +137,16 @@ TYPEDESCRIPTION CBaseDelay::m_SaveData[] = IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ) -void CBaseDelay :: KeyValue( KeyValueData *pkvd ) +void CBaseDelay::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "delay")) + if( FStrEq( pkvd->szKeyName, "delay" ) ) { m_flDelay = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "killtarget")) + else if( FStrEq( pkvd->szKeyName, "killtarget" ) ) { - m_iszKillTarget = ALLOC_STRING(pkvd->szValue); + m_iszKillTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -171,36 +170,35 @@ match (string)self.target and call their .use function (if they have one) ============================== */ -void CBaseEntity :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) +void CBaseEntity::SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) { // // fire targets // - if (!FStringNull(pev->target)) + if( !FStringNull( pev->target ) ) { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); + 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 ) + if( !targetName ) return; ALERT( at_aiconsole, "Firing: (%s)\n", targetName ); - for (;;) + for( ; ; ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName); - if (FNullEnt(pentTarget)) + 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 + 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 ); + ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING( pTarget->pev->classname ), targetName ); pTarget->Use( pActivator, pCaller, useType, value ); } } @@ -208,22 +206,22 @@ void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity * LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ) -void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) +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) + if( FStringNull( pev->target ) && !m_iszKillTarget ) return; // // check for a delay // - if (m_flDelay != 0) + 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"); + CBaseDelay *pTemp = GetClassPtr( (CBaseDelay *)NULL ); + pTemp->pev->classname = MAKE_STRING( "DelayedUse" ); pTemp->pev->nextthink = gpGlobals->time + m_flDelay; @@ -239,7 +237,7 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl // 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 + if( pActivator && pActivator->IsPlayer() ) // If a player activates, then save it { pTemp->pev->owner = pActivator->edict(); } @@ -254,35 +252,34 @@ void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, fl // // kill the killtargets // - - if ( m_iszKillTarget ) + 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) ) + 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) ); + UTIL_Remove( CBaseEntity::Instance( pentKillTarget ) ); ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) ); - pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) ); + pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING( m_iszKillTarget ) ); } } - + // // fire targets // - if (!FStringNull(pev->target)) + if( !FStringNull( pev->target ) ) { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); + FireTargets( STRING( pev->target ), pActivator, this, useType, value ); } } /* -void CBaseDelay :: SUB_UseTargetsEntMethod( void ) +void CBaseDelay::SUB_UseTargetsEntMethod( void ) { - SUB_UseTargets(pev); + SUB_UseTargets( pev ); } */ @@ -292,20 +289,20 @@ just constant angles. */ void SetMovedir( entvars_t *pev ) { - if (pev->angles == Vector(0, -1, 0)) + if( pev->angles == Vector( 0, -1, 0 ) ) { - pev->movedir = Vector(0, 0, 1); + pev->movedir = Vector( 0, 0, 1 ); } - else if (pev->angles == Vector(0, -2, 0)) + else if (pev->angles == Vector( 0, -2, 0 ) ) { - pev->movedir = Vector(0, 0, -1); + pev->movedir = Vector( 0, 0, -1 ); } else { - UTIL_MakeVectors(pev->angles); + UTIL_MakeVectors( pev->angles ); pev->movedir = gpGlobals->v_forward; } - + pev->angles = g_vecZero; } @@ -313,14 +310,14 @@ void CBaseDelay::DelayThink( void ) { CBaseEntity *pActivator = NULL; - if ( pev->owner != NULL ) // A player activated this on delay + 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)); + REMOVE_ENTITY( ENT( pev ) ); } // Global Savedata for Toggle @@ -351,24 +348,24 @@ IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ) void CBaseToggle::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "lip")) + if( FStrEq(pkvd->szKeyName, "lip" ) ) { - m_flLip = atof(pkvd->szValue); + m_flLip = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "wait")) + else if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_flWait = atof(pkvd->szValue); + m_flWait = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "master")) + else if( FStrEq( pkvd->szKeyName, "master" ) ) { - m_sMaster = ALLOC_STRING(pkvd->szValue); + m_sMaster = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "distance")) + else if( FStrEq( pkvd->szKeyName, "distance" ) ) { - m_flMoveDistance = atof(pkvd->szValue); + m_flMoveDistance = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -383,20 +380,20 @@ calculate pev->velocity and pev->nextthink to reach vecDest from pev->origin traveling at flSpeed =============== */ -void CBaseToggle :: LinearMove( Vector vecDest, float 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"); + 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) + if( vecDest == pev->origin ) { LinearMoveDone(); return; } - + // set destdelta to the vector needed to move Vector vecDestDelta = vecDest - pev->origin; @@ -416,18 +413,18 @@ void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) After moving, set origin to exact final destination, call "move done" function ============ */ -void CBaseToggle :: LinearMoveDone( void ) +void CBaseToggle::LinearMoveDone( void ) { - UTIL_SetOrigin(pev, m_vecFinalDest); + UTIL_SetOrigin( pev, m_vecFinalDest ); pev->velocity = g_vecZero; pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); + if( m_pfnCallWhenMoveDone ) + ( this->*m_pfnCallWhenMoveDone )(); } -BOOL CBaseToggle :: IsLockedByMaster( void ) +BOOL CBaseToggle::IsLockedByMaster( void ) { - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) + if( m_sMaster && !UTIL_IsMasterTriggered( m_sMaster, m_hActivator ) ) return TRUE; else return FALSE; @@ -442,15 +439,15 @@ pev->origin traveling at flSpeed Just like LinearMove, but rotational. =============== */ -void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) +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"); + 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) + if( vecDestAngle == pev->angles ) { AngularMoveDone(); return; @@ -475,41 +472,41 @@ void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) After rotating, set angle to exact final angle, call "move done" function ============ */ -void CBaseToggle :: AngularMoveDone( void ) +void CBaseToggle::AngularMoveDone( void ) { pev->angles = m_vecFinalAngle; pev->avelocity = g_vecZero; pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); + if( m_pfnCallWhenMoveDone ) + ( this->*m_pfnCallWhenMoveDone )(); } -float CBaseToggle :: AxisValue( int flags, const Vector &angles ) +float CBaseToggle::AxisValue( int flags, const Vector &angles ) { - if ( FBitSet(flags, SF_DOOR_ROTATE_Z) ) + if( FBitSet( flags, SF_DOOR_ROTATE_Z ) ) return angles.z; - if ( FBitSet(flags, SF_DOOR_ROTATE_X) ) + if( FBitSet( flags, SF_DOOR_ROTATE_X ) ) return angles.x; return angles.y; } -void CBaseToggle :: AxisDir( entvars_t *pev ) +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 + 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 + pev->movedir = Vector( 0, 1, 0 ); // around y-axis } -float CBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ) +float CBaseToggle::AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ) { - if ( FBitSet (flags, SF_DOOR_ROTATE_Z) ) + if( FBitSet( flags, SF_DOOR_ROTATE_Z ) ) return angle1.z - angle2.z; - if ( FBitSet (flags, SF_DOOR_ROTATE_X) ) + if( FBitSet( flags, SF_DOOR_ROTATE_X ) ) return angle1.x - angle2.x; return angle1.y - angle2.y; @@ -522,18 +519,18 @@ FEntIsVisible returns TRUE if the passed entity is visible to caller, even if not infront () ============= */ -BOOL FEntIsVisible( entvars_t* pev, entvars_t* pevTarget) +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); + UTIL_TraceLine( vecSpot1, vecSpot2, ignore_monsters, ENT( pev ), &tr ); - if (tr.fInOpen && tr.fInWater) + if( tr.fInOpen && tr.fInWater ) return FALSE; // sight line crossed contents - if (tr.flFraction == 1) + if( tr.flFraction == 1 ) return TRUE; return FALSE; diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index b626a384..a370b949 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -28,7 +28,7 @@ // 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 +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 @@ -38,8 +38,8 @@ TYPEDESCRIPTION CTalkMonster::m_SaveData[] = 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_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 ), @@ -61,51 +61,49 @@ char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = //========================================================= // AI Schedules Specific to talking monsters //========================================================= - -Task_t tlIdleResponse[] = +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 + { 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[] = +Schedule_t slIdleResponse[] = { - { + { tlIdleResponse, - ARRAYSIZE ( tlIdleResponse ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlIdleResponse ), + bits_COND_NEW_ENEMY | + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "Idle Response" - }, }; -Task_t tlIdleSpeak[] = +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 }, + { 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[] = +Schedule_t slIdleSpeak[] = { { tlIdleSpeak, - ARRAYSIZE ( tlIdleSpeak ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlIdleSpeak ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "Idle Speak" @@ -114,202 +112,197 @@ Schedule_t slIdleSpeak[] = 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 + { 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[] = +Schedule_t slIdleSpeakWait[] = { - { + { tlIdleSpeakWait, - ARRAYSIZE ( tlIdleSpeakWait ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | + 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_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 + { 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[] = +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 | + 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_t tlIdleStopShooting[] = { - { TASK_TLK_STOPSHOOTING, (float)0 },// tell player to stop shooting friend - // { TASK_TLK_EYECONTACT, (float)0 },// look at the player + { TASK_TLK_STOPSHOOTING, (float)0 },// tell player to stop shooting friend + // { TASK_TLK_EYECONTACT, (float)0 },// look at the player }; -Schedule_t slIdleStopShooting[] = +Schedule_t slIdleStopShooting[] = { - { + { tlIdleStopShooting, - ARRAYSIZE ( tlIdleStopShooting ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | + 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_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 }, + { 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[] = +Schedule_t slMoveAway[] = { { tlMoveAway, - ARRAYSIZE ( tlMoveAway ), + ARRAYSIZE( tlMoveAway ), 0, 0, "MoveAway" }, }; -Task_t tlMoveAwayFail[] = +Task_t tlMoveAwayFail[] = { - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_PLAYER, (float)0.5 }, + { TASK_STOP_MOVING, (float)0 }, + { TASK_FACE_PLAYER, (float)0.5 }, }; -Schedule_t slMoveAwayFail[] = +Schedule_t slMoveAwayFail[] = { { tlMoveAwayFail, - ARRAYSIZE ( tlMoveAwayFail ), + ARRAYSIZE( tlMoveAwayFail ), 0, 0, "MoveAwayFail" }, }; -Task_t tlMoveAwayFollow[] = +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 }, + { 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[] = +Schedule_t slMoveAwayFollow[] = { { tlMoveAwayFollow, - ARRAYSIZE ( tlMoveAwayFollow ), + ARRAYSIZE( tlMoveAwayFollow ), 0, 0, "MoveAwayFollow" }, }; -Task_t tlTlkIdleWatchClient[] = +Task_t tlTlkIdleWatchClient[] = { - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_TLK_LOOK_AT_CLIENT, (float)6 }, + { TASK_STOP_MOVING, 0 }, + { TASK_SET_ACTIVITY, (float)ACT_IDLE }, + { TASK_TLK_LOOK_AT_CLIENT, (float)6 }, }; -Task_t tlTlkIdleWatchClientStare[] = +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 }, + { 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[] = +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 | + 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_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 | + 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_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" }, @@ -317,20 +310,20 @@ Schedule_t slTlkIdleWatchClient[] = 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 + { 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[] = +Schedule_t slTlkIdleEyecontact[] = { { tlTlkIdleEyecontact, - ARRAYSIZE ( tlTlkIdleEyecontact ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | + ARRAYSIZE( tlTlkIdleEyecontact ), + bits_COND_NEW_ENEMY | + bits_COND_CLIENT_PUSH | + bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE, 0, "TlkIdleEyecontact" @@ -348,26 +341,26 @@ DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) slMoveAwayFollow, slMoveAwayFail, slTlkIdleWatchClient, - &slTlkIdleWatchClient[ 1 ], + &slTlkIdleWatchClient[1], slTlkIdleEyecontact, }; IMPLEMENT_CUSTOM_SCHEDULES( CTalkMonster, CBaseMonster ) -void CTalkMonster :: SetActivity ( Activity newActivity ) +void CTalkMonster::SetActivity( Activity newActivity ) { - if (newActivity == ACT_IDLE && IsTalking() ) + if( newActivity == ACT_IDLE && IsTalking() ) newActivity = ACT_SIGNAL3; - if ( newActivity == ACT_SIGNAL3 && (LookupActivity ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE)) + if( newActivity == ACT_SIGNAL3 && ( LookupActivity( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE ) ) newActivity = ACT_IDLE; CBaseMonster::SetActivity( newActivity ); } -void CTalkMonster :: StartTask( Task_t *pTask ) +void CTalkMonster::StartTask( Task_t *pTask ) { - switch ( pTask->iTask ) + switch( pTask->iTask ) { case TASK_TLK_SPEAK: // ask question or make statement @@ -398,15 +391,17 @@ void CTalkMonster :: StartTask( Task_t *pTask ) case TASK_TLK_EYECONTACT: break; case TASK_TLK_IDEALYAW: - if (m_hTalkTarget != NULL) + if( m_hTalkTarget != NULL ) { pev->yaw_speed = 60; - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; + float yaw = VecToYaw( m_hTalkTarget->pev->origin - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; + if( yaw > 180 ) + yaw -= 360; + if( yaw < -180 ) + yaw += 360; - if (yaw < 0) + if( yaw < 0 ) { pev->ideal_yaw = min( yaw + 45, 0 ) + pev->angles.y; } @@ -424,12 +419,12 @@ void CTalkMonster :: StartTask( Task_t *pTask ) 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 ); + 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 ); + PlaySentence( m_szGrp[TLK_STOP], RANDOM_FLOAT( 2, 2.5 ), VOL_NORM, ATTN_NORM ); TaskComplete(); break; case TASK_WALK_PATH_FOR_UNITS: @@ -443,11 +438,11 @@ void CTalkMonster :: StartTask( Task_t *pTask ) UTIL_MakeVectorsPrivate( dir, move, NULL, NULL ); dir = pev->origin + move * pTask->flData; - if ( MoveToLocation( ACT_WALK, 2, dir ) ) + if( MoveToLocation( ACT_WALK, 2, dir ) ) { TaskComplete(); } - else if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) + else if( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + 2; @@ -469,7 +464,7 @@ void CTalkMonster :: StartTask( Task_t *pTask ) } } -void CTalkMonster :: RunTask( Task_t *pTask ) +void CTalkMonster::RunTask( Task_t *pTask ) { switch( pTask->iTask ) { @@ -478,14 +473,14 @@ void CTalkMonster :: RunTask( Task_t *pTask ) edict_t *pPlayer; // track head to the client for a while. - if ( m_MonsterState == MONSTERSTATE_IDLE && - !IsMoving() && - !IsTalking() ) + if( m_MonsterState == MONSTERSTATE_IDLE && + !IsMoving() && + !IsTalking() ) { // Get edict for one player pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) + if( pPlayer ) { IdleHeadTurn( pPlayer->v.origin ); } @@ -497,24 +492,24 @@ void CTalkMonster :: RunTask( Task_t *pTask ) return; } - if ( pTask->iTask == TASK_TLK_CLIENT_STARE ) + 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 ) + 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 ) + if( UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) < m_flFieldOfView ) { // player looked away TaskFail(); } } - if ( gpGlobals->time > m_flWaitFinished ) + if( gpGlobals->time > m_flWaitFinished ) { TaskComplete(); } @@ -524,12 +519,12 @@ void CTalkMonster :: RunTask( Task_t *pTask ) // Get edict for one player edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) + if( pPlayer ) { - MakeIdealYaw ( pPlayer->v.origin ); - ChangeYaw ( pev->yaw_speed ); + MakeIdealYaw( pPlayer->v.origin ); + ChangeYaw( pev->yaw_speed ); IdleHeadTurn( pPlayer->v.origin ); - if ( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 ) + if( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 ) { TaskComplete(); } @@ -541,7 +536,7 @@ void CTalkMonster :: RunTask( Task_t *pTask ) } break; case TASK_TLK_EYECONTACT: - if (!IsMoving() && IsTalking() && m_hTalkTarget != NULL) + if( !IsMoving() && IsTalking() && m_hTalkTarget != NULL ) { // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); IdleHeadTurn( m_hTalkTarget->pev->origin ); @@ -555,10 +550,10 @@ void CTalkMonster :: RunTask( Task_t *pTask ) { float distance; - distance = (m_vecLastPosition - pev->origin).Length2D(); + distance = ( m_vecLastPosition - pev->origin ).Length2D(); // Walk path until far enough away - if ( distance > pTask->flData || MovementIsComplete() ) + if( distance > pTask->flData || MovementIsComplete() ) { TaskComplete(); RouteClear(); // Stop moving @@ -566,9 +561,9 @@ void CTalkMonster :: RunTask( Task_t *pTask ) } break; case TASK_WAIT_FOR_MOVEMENT: - if (IsTalking() && m_hTalkTarget != NULL) + if( IsTalking() && m_hTalkTarget != NULL ) { - // ALERT(at_console, "walking, talking\n"); + // ALERT( at_console, "walking, talking\n" ); IdleHeadTurn( m_hTalkTarget->pev->origin ); } else @@ -576,18 +571,18 @@ void CTalkMonster :: RunTask( Task_t *pTask ) IdleHeadTurn( pev->origin ); // override so that during walk, a scientist may talk and greet player FIdleHello(); - if (RANDOM_LONG(0,m_nSpeak * 20) == 0) + if( RANDOM_LONG( 0, m_nSpeak * 20 ) == 0) { FIdleSpeak(); } } CBaseMonster::RunTask( pTask ); - if (TaskIsComplete()) + if( TaskIsComplete() ) IdleHeadTurn( pev->origin ); break; default: - if (IsTalking() && m_hTalkTarget != NULL) + if( IsTalking() && m_hTalkTarget != NULL ) { IdleHeadTurn( m_hTalkTarget->pev->origin ); } @@ -599,13 +594,13 @@ void CTalkMonster :: RunTask( Task_t *pTask ) } } -void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) +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 ) + if( ( pevAttacker->flags & FL_CLIENT) && m_MonsterState != MONSTERSTATE_PRONE ) { AlertFriends(); - LimitFollowers( CBaseEntity::Instance(pevAttacker), 0 ); + LimitFollowers( CBaseEntity::Instance( pevAttacker ), 0 ); } m_hTargetEnt = NULL; @@ -615,30 +610,30 @@ void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) CBaseMonster::Killed( pevAttacker, iGib ); } -CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) +CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) { CBaseEntity *pFriend = pPrevious; char *pszFriend; TraceResult tr; Vector vecCheck; - pszFriend = m_szFriends[ FriendNumber(listNumber) ]; - while ( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) + pszFriend = m_szFriends[FriendNumber( listNumber )]; + while( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) { - if (pFriend == this || !pFriend->IsAlive()) + if( pFriend == this || !pFriend->IsAlive() ) // don't talk to self or dead people continue; - if ( bTrace ) + if( bTrace ) { vecCheck = pFriend->pev->origin; vecCheck.z = pFriend->pev->absmax.z; - UTIL_TraceLine( pev->origin, vecCheck, ignore_monsters, ENT(pev), &tr); + UTIL_TraceLine( pev->origin, vecCheck, ignore_monsters, ENT( pev ), &tr ); } else tr.flFraction = 1.0; - if (tr.flFraction == 1.0) + if( tr.flFraction == 1.0 ) { return pFriend; } @@ -653,12 +648,12 @@ void CTalkMonster::AlertFriends( void ) int i; // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) + for( i = 0; i < TLK_CFRIENDS; i++ ) { - while ( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) + while( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster->IsAlive() ) + if( pMonster->IsAlive() ) { // don't provoke a friend that's playing a death animation. They're a goner pMonster->m_afMemory |= bits_MEMORY_PROVOKED; @@ -673,12 +668,12 @@ void CTalkMonster::ShutUpFriends( void ) int i; // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) + for( i = 0; i < TLK_CFRIENDS; i++ ) { - while ( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) + while( ( pFriend = EnumFriends( pFriend, i, TRUE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) + if( pMonster ) { pMonster->SentenceStop(); } @@ -696,17 +691,17 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) count = 0; // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) + for( i = 0; i < TLK_CFRIENDS; i++ ) { - while ( ( pFriend = EnumFriends( pFriend, i, FALSE ) ) ) + while( ( pFriend = EnumFriends( pFriend, i, FALSE ) ) ) { CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) + if( pMonster ) { - if ( pMonster->m_hTargetEnt == pPlayer ) + if( pMonster->m_hTargetEnt == pPlayer ) { count++; - if ( count > maxFollowers ) + if( count > maxFollowers ) pMonster->StopFollowing( TRUE ); } } @@ -717,28 +712,28 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) float CTalkMonster::TargetDistance( void ) { // If we lose the player, or he dies, return a really large distance - if ( m_hTargetEnt == NULL || !m_hTargetEnt->IsAlive() ) + if( m_hTargetEnt == NULL || !m_hTargetEnt->IsAlive() ) return 1e6; - return (m_hTargetEnt->pev->origin - pev->origin).Length(); + 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 ) +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) + 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"); + 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 ); @@ -747,7 +742,7 @@ void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) } // monsters derived from ctalkmonster should call this in precache() -void CTalkMonster :: TalkInit( void ) +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) @@ -760,7 +755,7 @@ void CTalkMonster :: TalkInit( void ) // Scan for nearest, visible friend. If fPlayer is true, look for // nearest player //========================================================= -CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) +CBaseEntity *CTalkMonster::FindNearestFriend( BOOL fPlayer ) { CBaseEntity *pFriend = NULL; CBaseEntity *pNearest = NULL; @@ -774,50 +769,50 @@ CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) vecStart.z = pev->absmax.z; - if (fPlayer) + if( fPlayer ) cfriends = 1; else cfriends = TLK_CFRIENDS; // for each type of friend... - for (i = cfriends-1; i > -1; i--) + for( i = cfriends-1; i > -1; i-- ) { - if (fPlayer) + if( fPlayer ) pszFriend = "player"; else - pszFriend = m_szFriends[FriendNumber(i)]; + pszFriend = m_szFriends[FriendNumber( i )]; - if (!pszFriend) + if( !pszFriend ) continue; // for each friend in this bsp... - while ( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) + while( ( pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ) ) ) { - if (pFriend == this || !pFriend->IsAlive()) + 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 ) + 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()) + if( range > ( vecStart - vecCheck ).Length()) { - UTIL_TraceLine(vecStart, vecCheck, ignore_monsters, ENT(pev), &tr); + UTIL_TraceLine( vecStart, vecCheck, ignore_monsters, ENT( pev ), &tr ); - if (tr.flFraction == 1.0) + if( tr.flFraction == 1.0 ) { // visible and in range, this is the new nearest scientist - if ((vecStart - vecCheck).Length() < TALKRANGE_MIN) + if( ( vecStart - vecCheck ).Length() < TALKRANGE_MIN ) { pNearest = pFriend; - range = (vecStart - vecCheck).Length(); + range = ( vecStart - vecCheck ).Length(); } } } @@ -826,27 +821,27 @@ CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) return pNearest; } -int CTalkMonster :: GetVoicePitch( void ) +int CTalkMonster::GetVoicePitch( void ) { - return m_voicePitch + RANDOM_LONG(0,3); + return m_voicePitch + RANDOM_LONG( 0, 3 ); } -void CTalkMonster :: Touch( CBaseEntity *pOther ) +void CTalkMonster::Touch( CBaseEntity *pOther ) { // Did the player touch me? - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { // Ignore if pissed at player - if ( m_afMemory & bits_MEMORY_PROVOKED ) + if( m_afMemory & bits_MEMORY_PROVOKED ) return; // Stay put during speech - if ( IsTalking() ) + 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 ) + float speed = fabs( pOther->pev->velocity.x ) + fabs( pOther->pev->velocity.y ); + if( speed > 50 ) { SetConditions( bits_COND_CLIENT_PUSH ); MakeIdealYaw( pOther->pev->origin ); @@ -858,44 +853,44 @@ void CTalkMonster :: Touch( CBaseEntity *pOther ) // IdleRespond // Respond to a previous question //========================================================= -void CTalkMonster :: IdleRespond( void ) +void CTalkMonster::IdleRespond( void ) { int pitch = GetVoicePitch(); // play response - PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE ); } -int CTalkMonster :: FOkToSpeak( void ) +int CTalkMonster::FOkToSpeak( void ) { // if in the grip of a barnacle, don't speak - if ( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) + if( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) { return FALSE; } // if not alive, certainly don't speak - if ( pev->deadflag != DEAD_NO ) + if( pev->deadflag != DEAD_NO ) { return FALSE; } // if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) + if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) return FALSE; - if ( pev->spawnflags & SF_MONSTER_GAG ) + if( pev->spawnflags & SF_MONSTER_GAG ) return FALSE; - if ( m_MonsterState == MONSTERSTATE_PRONE ) + if( m_MonsterState == MONSTERSTATE_PRONE ) return FALSE; // if player is not in pvs, don't speak - if (!IsAlive() || FNullEnt(FIND_CLIENT_IN_PVS(edict()))) + if( !IsAlive() || FNullEnt(FIND_CLIENT_IN_PVS( edict() ) ) ) return FALSE; // don't talk if you're in combat - if (m_hEnemy != NULL && FVisible( m_hEnemy )) + if( m_hEnemy != NULL && FVisible( m_hEnemy ) ) return FALSE; return TRUE; @@ -903,7 +898,7 @@ int CTalkMonster :: FOkToSpeak( void ) int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) { - if ( fDisregardState ) + if( fDisregardState ) return CBaseMonster::CanPlaySentence( fDisregardState ); return FOkToSpeak(); } @@ -911,9 +906,9 @@ int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) //========================================================= // FIdleStare //========================================================= -int CTalkMonster :: FIdleStare( void ) +int CTalkMonster::FIdleStare( void ) { - if (!FOkToSpeak()) + if( !FOkToSpeak() ) return FALSE; PlaySentence( m_szGrp[TLK_STARE], RANDOM_FLOAT(5, 7.5), VOL_NORM, ATTN_IDLE ); @@ -926,30 +921,30 @@ int CTalkMonster :: FIdleStare( void ) // IdleHello // Try to greet player first time he's seen //========================================================= -int CTalkMonster :: FIdleHello( void ) +int CTalkMonster::FIdleHello( void ) { - if (!FOkToSpeak()) + if( !FOkToSpeak() ) return FALSE; // if this is first time scientist has seen player, greet him - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) + if( !FBitSet( m_bitsSaid, bit_saidHelloPlayer ) ) { // get a player - CBaseEntity *pPlayer = FindNearestFriend(TRUE); + CBaseEntity *pPlayer = FindNearestFriend( TRUE ); - if (pPlayer) + if( pPlayer ) { - if (FInViewCone(pPlayer) && FVisible(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 ); + 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 ); + PlaySentence( m_szGrp[TLK_HELLO], RANDOM_FLOAT( 3, 3.5 ), VOL_NORM, ATTN_IDLE ); + + SetBits( m_bitsSaid, bit_saidHelloPlayer ); - SetBits(m_bitsSaid, bit_saidHelloPlayer); - return TRUE; } } @@ -958,15 +953,17 @@ int CTalkMonster :: FIdleHello( void ) } // turn head towards supplied origin -void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) +void CTalkMonster::IdleHeadTurn( Vector &vecFriend ) { // turn head in desired direction only if ent has a turnable head - if (m_afCapability & bits_CAP_TURN_HEAD) + if( m_afCapability & bits_CAP_TURN_HEAD ) { - float yaw = VecToYaw(vecFriend - pev->origin) - pev->angles.y; + float yaw = VecToYaw( vecFriend - pev->origin ) - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; + if( yaw > 180 ) + yaw -= 360; + if( yaw < -180 ) + yaw += 360; // turn towards vector SetBoneController( 0, yaw ); @@ -977,7 +974,7 @@ void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) // FIdleSpeak // ask question of nearby friend, or make statement //========================================================= -int CTalkMonster :: FIdleSpeak ( void ) +int CTalkMonster::FIdleSpeak( void ) { // try to start a conversation, or make statement int pitch; @@ -985,23 +982,23 @@ int CTalkMonster :: FIdleSpeak ( void ) const char *szQuestionGroup; float duration; - if (!FOkToSpeak()) + if( !FOkToSpeak() ) return FALSE; // set idle groups based on pre/post disaster - if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) + 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); + 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); + duration = RANDOM_FLOAT( 2.8, 3.2 ); } pitch = GetVoicePitch(); @@ -1009,35 +1006,35 @@ int CTalkMonster :: FIdleSpeak ( void ) // player using this entity is alive and wounded? CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget != NULL ) + if( pTarget != NULL ) { - if ( pTarget->IsPlayer() ) + if( pTarget->IsPlayer() ) { - if ( pTarget->IsAlive() ) + if( pTarget->IsAlive() ) { m_hTalkTarget = m_hTargetEnt; - if (!FBitSet(m_bitsSaid, bit_saidDamageHeavy) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 8)) + 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); + //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); + SetBits( m_bitsSaid, bit_saidDamageHeavy ); return TRUE; } - else if (!FBitSet(m_bitsSaid, bit_saidDamageMedium) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 4)) + 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); + //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); + SetBits( m_bitsSaid, bit_saidDamageMedium ); return TRUE; } - else if (!FBitSet(m_bitsSaid, bit_saidDamageLight) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 2)) + 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); + //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); + SetBits( m_bitsSaid, bit_saidDamageLight ); return TRUE; } } @@ -1051,12 +1048,12 @@ int CTalkMonster :: FIdleSpeak ( void ) } // if there is a friend nearby to speak to, play sentence, set friend's response time, return - CBaseEntity *pFriend = FindNearestFriend(FALSE); + CBaseEntity *pFriend = FindNearestFriend( FALSE ); - if (pFriend && !(pFriend->IsMoving()) && (RANDOM_LONG(0,99) < 75)) + 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 ); + //SENTENCEG_PlayRndSz( ENT( pev ), szQuestionGroup, 1.0, ATTN_IDLE, 0, pitch ); // force friend to answer CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; @@ -1069,12 +1066,12 @@ int CTalkMonster :: FIdleSpeak ( void ) } // otherwise, play an idle statement, try to face client when making a statement. - if ( RANDOM_LONG(0,1) ) + if( RANDOM_LONG( 0, 1 ) ) { - //SENTENCEG_PlayRndSz( ENT(pev), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); - pFriend = FindNearestFriend(TRUE); + //SENTENCEG_PlayRndSz( ENT( pev ), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); + pFriend = FindNearestFriend( TRUE ); - if ( pFriend ) + if( pFriend ) { m_hTalkTarget = pFriend; PlaySentence( szIdleGroup, duration, VOL_NORM, ATTN_IDLE ); @@ -1091,7 +1088,7 @@ int CTalkMonster :: FIdleSpeak ( void ) void CTalkMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { - if ( !bConcurrent ) + if( !bConcurrent ) ShutUpFriends(); ClearConditions( bits_COND_CLIENT_PUSH ); // Forget about moving! I've got something to say! @@ -1103,28 +1100,28 @@ void CTalkMonster::PlayScriptedSentence( const char *pszSentence, float duration void CTalkMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { - if ( !pszSentence ) + if( !pszSentence ) return; - Talk ( duration ); + Talk( duration ); CTalkMonster::g_talkWaitTime = gpGlobals->time + duration + 2.0; - if ( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, GetVoicePitch()); + 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); + SetBits( m_bitsSaid, bit_saidHelloPlayer ); } //========================================================= // Talk - set a timer that tells us when the monster is done // talking. //========================================================= -void CTalkMonster :: Talk( float flDuration ) +void CTalkMonster::Talk( float flDuration ) { - if ( flDuration <= 0 ) + if( flDuration <= 0 ) { // no duration :( m_flStopTalkTime = gpGlobals->time + 3; @@ -1136,23 +1133,23 @@ void CTalkMonster :: Talk( float flDuration ) } // Prepare this talking monster to answer question -void CTalkMonster :: SetAnswerQuestion( CTalkMonster *pSpeaker ) +void CTalkMonster::SetAnswerQuestion( CTalkMonster *pSpeaker ) { - if ( !m_pCine ) + if( !m_pCine ) ChangeSchedule( slIdleResponse ); m_hTalkTarget = (CBaseMonster *)pSpeaker; } -int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +int CTalkMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( IsAlive() ) + if( IsAlive() ) { // if player damaged this entity, have other friends talk about it - if (pevAttacker && m_MonsterState != MONSTERSTATE_PRONE && FBitSet(pevAttacker->flags, FL_CLIENT)) + if( pevAttacker && m_MonsterState != MONSTERSTATE_PRONE && FBitSet( pevAttacker->flags, FL_CLIENT ) ) { - CBaseEntity *pFriend = FindNearestFriend(FALSE); + CBaseEntity *pFriend = FindNearestFriend( FALSE ); - if (pFriend && pFriend->IsAlive()) + if( pFriend && pFriend->IsAlive() ) { // only if not dead or dying! CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; @@ -1160,10 +1157,10 @@ int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, } } } - return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); + return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) +Schedule_t *CTalkMonster::GetScheduleOfType( int Type ) { switch( Type ) { @@ -1175,58 +1172,58 @@ Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) return slMoveAwayFail; case SCHED_TARGET_FACE: // speak during 'use' - if (RANDOM_LONG(0,99) < 2) - //ALERT ( at_console, "target chase speak\n" ); + 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)) + if( !FBitSet( m_bitsSaid, bit_saidHelloPlayer ) ) { return slIdleHello; } // sustained light wounds? - if (!FBitSet(m_bitsSaid, bit_saidWoundLight) && (pev->health <= (pev->max_health * 0.75))) + 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); + //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))) + 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); + //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) + 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 ) + if( !IsTalking() && HasConditions( bits_COND_SEE_CLIENT ) && RANDOM_LONG( 0, 6 ) == 0 ) { edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) + 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 ) + 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[1]; } return slTlkIdleWatchClient; @@ -1234,7 +1231,7 @@ Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) } else { - if (IsTalking()) + if( IsTalking() ) // look at who we're talking to return slTlkIdleEyecontact; else @@ -1255,9 +1252,9 @@ Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) //========================================================= // IsTalking - am I saying a sentence right now? //========================================================= -BOOL CTalkMonster :: IsTalking( void ) +BOOL CTalkMonster::IsTalking( void ) { - if ( m_flStopTalkTime > gpGlobals->time ) + if( m_flStopTalkTime > gpGlobals->time ) { return TRUE; } @@ -1268,74 +1265,74 @@ BOOL CTalkMonster :: IsTalking( void ) //========================================================= // If there's a player around, watch him. //========================================================= -void CTalkMonster :: PrescheduleThink ( void ) +void CTalkMonster::PrescheduleThink( void ) { - if ( !HasConditions ( bits_COND_SEE_CLIENT ) ) + if( !HasConditions( bits_COND_SEE_CLIENT ) ) { - SetConditions ( bits_COND_CLIENT_UNSEEN ); + SetConditions( bits_COND_CLIENT_UNSEEN ); } } // try to smell something -void CTalkMonster :: TrySmellTalk( void ) +void CTalkMonster::TrySmellTalk( void ) { - if ( !FOkToSpeak() ) + if( !FOkToSpeak() ) return; // clear smell bits periodically - if ( gpGlobals->time > m_flLastSaidSmelled ) + if( gpGlobals->time > m_flLastSaidSmelled ) { - //ALERT ( at_aiconsole, "Clear smell bits\n" ); - ClearBits(m_bitsSaid, bit_saidSmelled); + //ALERT( at_aiconsole, "Clear smell bits\n" ); + ClearBits( m_bitsSaid, bit_saidSmelled ); } // smelled something? - if (!FBitSet(m_bitsSaid, bit_saidSmelled) && HasConditions ( bits_COND_SMELL )) + 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 ); + 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); + SetBits( m_bitsSaid, bit_saidSmelled ); } } int CTalkMonster::IRelationship( CBaseEntity *pTarget ) { - if ( pTarget->IsPlayer() ) - if ( m_afMemory & bits_MEMORY_PROVOKED ) + if( pTarget->IsPlayer() ) + if( m_afMemory & bits_MEMORY_PROVOKED ) return R_HT; return CBaseMonster::IRelationship( pTarget ); } void CTalkMonster::StopFollowing( BOOL clearSchedule ) { - if ( IsFollowing() ) + if( IsFollowing() ) { - if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) + if( !( m_afMemory & bits_MEMORY_PROVOKED ) ) { - PlaySentence( m_szGrp[TLK_UNUSE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + PlaySentence( m_szGrp[TLK_UNUSE], RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE ); m_hTalkTarget = m_hTargetEnt; } - if ( m_movementGoal == MOVEGOAL_TARGETENT ) + if( m_movementGoal == MOVEGOAL_TARGETENT ) RouteClear(); // Stop him from walking toward the player m_hTargetEnt = NULL; - if ( clearSchedule ) + if( clearSchedule ) ClearSchedule(); - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) m_IdealMonsterState = MONSTERSTATE_COMBAT; } } void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) { - if ( m_pCine ) + if( m_pCine ) m_pCine->CancelScript(); - if ( m_hEnemy != NULL ) + if( m_hEnemy != NULL ) m_IdealMonsterState = MONSTERSTATE_ALERT; m_hTargetEnt = pLeader; - PlaySentence( m_szGrp[TLK_USE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + 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(); @@ -1343,41 +1340,41 @@ void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) BOOL CTalkMonster::CanFollow( void ) { - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) + if( m_MonsterState == MONSTERSTATE_SCRIPT ) { - if ( !m_pCine->CanInterrupt() ) + if( !m_pCine->CanInterrupt() ) return FALSE; } - - if ( !IsAlive() ) + + if( !IsAlive() ) return FALSE; return !IsFollowing(); } -void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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 ) + if( m_useTime > gpGlobals->time ) return; - if ( pCaller != NULL && pCaller->IsPlayer() ) + if( pCaller != NULL && pCaller->IsPlayer() ) { // Pre-disaster followers can't be used - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) + if( pev->spawnflags & SF_MONSTER_PREDISASTER ) { DeclineFollowing(); } - else if ( CanFollow() ) + else if( CanFollow() ) { - LimitFollowers( pCaller , 1 ); + LimitFollowers( pCaller, 1 ); - if ( m_afMemory & bits_MEMORY_PROVOKED ) + 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 + SetBits( m_bitsSaid, bit_saidHelloPlayer ); // Don't say hi after you've started following } } else @@ -1389,14 +1386,14 @@ void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, void CTalkMonster::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "UseSentence")) + if( FStrEq( pkvd->szKeyName, "UseSentence" ) ) { - m_iszUse = ALLOC_STRING(pkvd->szValue); + m_iszUse = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "UnUseSentence")) + else if( FStrEq( pkvd->szKeyName, "UnUseSentence" ) ) { - m_iszUnUse = ALLOC_STRING(pkvd->szValue); + m_iszUnUse = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -1405,8 +1402,8 @@ void CTalkMonster::KeyValue( KeyValueData *pkvd ) void CTalkMonster::Precache( void ) { - if ( m_iszUse ) + if( m_iszUse ) m_szGrp[TLK_USE] = STRING( m_iszUse ); - if ( m_iszUnUse ) + if( m_iszUnUse ) m_szGrp[TLK_UNUSE] = STRING( m_iszUnUse ); } diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index 52f3512a..6c9d72af 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -31,7 +31,7 @@ static int num_teams = 0; extern DLL_GLOBAL BOOL g_fGameOver; -CHalfLifeTeamplay :: CHalfLifeTeamplay() +CHalfLifeTeamplay::CHalfLifeTeamplay() { m_DisableDeathMessages = FALSE; m_DisableDeathPenalty = FALSE; @@ -46,20 +46,20 @@ CHalfLifeTeamplay :: CHalfLifeTeamplay() // 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 ) + edict_t *pWorld = INDEXENT( 0 ); + if( pWorld && pWorld->v.team ) { - if ( teamoverride.value ) + if( teamoverride.value ) { - const char *pTeamList = STRING(pWorld->v.team); - if ( pTeamList && strlen(pTeamList) ) + 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 ) ) + if( strlen( m_szTeamList ) ) m_teamLimit = TRUE; else m_teamLimit = FALSE; @@ -71,9 +71,9 @@ extern cvar_t timeleft, fragsleft; #ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; +extern CVoiceGameMgr g_VoiceGameMgr; #endif -void CHalfLifeTeamplay :: Think ( void ) +void CHalfLifeTeamplay::Think( void ) { ///// Check game rules ///// static int last_frags; @@ -85,39 +85,39 @@ void CHalfLifeTeamplay :: Think ( void ) #ifndef NO_VOICEGAMEMGR g_VoiceGameMgr.Update(gpGlobals->frametime); #endif - if ( g_fGameOver ) // someone else quit the game already + if( g_fGameOver ) // someone else quit the game already { CHalfLifeMultiplay::Think(); return; } - float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60; + float flTimeLimit = CVAR_GET_FLOAT( "mp_timelimit" ) * 60; - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + time_remaining = (int)( flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0 ); - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) + if( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) { GoToIntermission(); return; } float flFragLimit = fraglimit.value; - if ( flFragLimit ) + if( flFragLimit ) { int bestfrags = 9999; int remain; // check if any team is over the frag limit - for ( int i = 0; i < num_teams; i++ ) + for( int i = 0; i < num_teams; i++ ) { - if ( team_scores[i] >= flFragLimit ) + if( team_scores[i] >= flFragLimit ) { GoToIntermission(); return; } remain = flFragLimit - team_scores[i]; - if ( remain < bestfrags ) + if( remain < bestfrags ) { bestfrags = remain; } @@ -126,19 +126,19 @@ void CHalfLifeTeamplay :: Think ( void ) } // Updates when frags change - if ( frags_remaining != last_frags ) + if( frags_remaining != last_frags ) { g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); } // Updates once per second - if ( timeleft.value != last_time ) + if( timeleft.value != last_time ) { g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); } last_frags = frags_remaining; - last_time = time_remaining; + last_time = time_remaining; } //========================================================= @@ -146,18 +146,18 @@ void CHalfLifeTeamplay :: Think ( void ) // 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 ) +BOOL CHalfLifeTeamplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { #ifndef NO_VOICEGAMEMGR - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + if( g_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) ) return TRUE; #endif - if ( FStrEq( pcmd, "menuselect" ) ) + if( FStrEq( pcmd, "menuselect" ) ) { - if ( CMD_ARGC() < 2 ) + if( CMD_ARGC() < 2 ) return TRUE; - int slot = atoi( CMD_ARGV(1) ); + int slot = atoi( CMD_ARGV( 1 ) ); // select the item from the current menu return TRUE; @@ -172,7 +172,7 @@ extern int gmsgTeamInfo; extern int gmsgTeamNames; extern int gmsgScoreInfo; -void CHalfLifeTeamplay :: UpdateGameMode( CBasePlayer *pPlayer ) +void CHalfLifeTeamplay::UpdateGameMode( CBasePlayer *pPlayer ) { MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() ); WRITE_BYTE( 1 ); // game mode teamplay @@ -188,11 +188,11 @@ const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) RecountTeams(); // update the current player of the team he is joining - if ( pPlayer->m_szTeamName[0] == '\0' || !IsValidTeam( pPlayer->m_szTeamName ) || defaultteam.value ) + if( pPlayer->m_szTeamName[0] == '\0' || !IsValidTeam( pPlayer->m_szTeamName ) || defaultteam.value ) { const char *pTeamName = NULL; - if ( defaultteam.value ) + if( defaultteam.value ) { pTeamName = team_names[0]; } @@ -219,9 +219,9 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *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++ ) + for( i = 0; i < num_teams; i++ ) { - WRITE_STRING( team_names[ i ] ); + WRITE_STRING( team_names[i] ); } MESSAGE_END(); @@ -230,7 +230,7 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) 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 ) ) + if( !strcmp( mdls, pPlayer->m_szTeamName ) ) { sprintf( text, "* you are on team \'%s\'\n", pPlayer->m_szTeamName ); } @@ -245,10 +245,10 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *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++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if ( plr && IsValidTeam( plr->TeamID() ) ) + if( plr && IsValidTeam( plr->TeamID() ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgTeamInfo, NULL, pPlayer->edict() ); WRITE_BYTE( plr->entindex() ); @@ -263,7 +263,7 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea int damageFlags = DMG_GENERIC; int clientIndex = pPlayer->entindex(); - if ( !bGib ) + if( !bGib ) { damageFlags |= DMG_NEVERGIB; } @@ -272,13 +272,13 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea damageFlags |= DMG_ALWAYSGIB; } - if ( bKill ) + 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) ); + entvars_t *pevWorld = VARS( INDEXENT( 0 ) ); pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); m_DisableDeathMessages = FALSE; @@ -317,10 +317,10 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob // prevent skin/color/model changes char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); - if ( !stricmp( mdls, pPlayer->m_szTeamName ) ) + if( !stricmp( mdls, pPlayer->m_szTeamName ) ) return; - if ( defaultteam.value ) + if( defaultteam.value ) { int clientIndex = pPlayer->entindex(); @@ -331,7 +331,7 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob return; } - if ( defaultteam.value || !IsValidTeam( mdls ) ) + if( defaultteam.value || !IsValidTeam( mdls ) ) { int clientIndex = pPlayer->entindex(); @@ -347,7 +347,7 @@ void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infob UTIL_SayTextAll( text, pPlayer ); UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n", - STRING(pPlayer->pev->netname), + STRING( pPlayer->pev->netname ), GETPLAYERUSERID( pPlayer->edict() ), GETPLAYERAUTHID( pPlayer->edict() ), pPlayer->m_szTeamName, @@ -366,20 +366,20 @@ extern int gmsgDeathMsg; //========================================================= void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) { - if ( m_DisableDeathMessages ) + if( m_DisableDeathMessages ) return; - if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) + if( pVictim && pKiller && pKiller->flags & FL_CLIENT ) { CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); - if ( pk ) + if( pk ) { - if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) + 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_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; @@ -392,9 +392,9 @@ void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, e //========================================================= //========================================================= -void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +void CHalfLifeTeamplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) { - if ( !m_DisableDeathPenalty ) + if( !m_DisableDeathPenalty ) { CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); RecountTeams(); @@ -411,10 +411,10 @@ BOOL CHalfLifeTeamplay::IsTeamplay( void ) BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) { - if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) + if( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) { // my teammate hit me. - if ( (friendlyfire.value == 0) && (pAttacker != pPlayer) ) + 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; @@ -430,10 +430,10 @@ int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pT { // 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() ) + if( !pPlayer || !pTarget || !pTarget->IsPlayer() ) return GR_NOTTEAMMATE; - if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) + if( ( *GetTeamID( pPlayer ) != '\0' ) && ( *GetTeamID( pTarget ) != '\0' ) && !stricmp( GetTeamID( pPlayer ), GetTeamID( pTarget ) ) ) { return GR_TEAMMATE; } @@ -447,9 +447,9 @@ 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( pTgt && pTgt->IsPlayer() ) { - if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) + if( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) return FALSE; // don't autoaim at teammates } @@ -460,13 +460,13 @@ BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) //========================================================= int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) { - if ( !pKilled ) + if( !pKilled ) return 0; - if ( !pAttacker ) + if( !pAttacker ) return 1; - if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) + if( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) return -1; return 1; @@ -476,7 +476,7 @@ int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKil //========================================================= const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) { - if ( pEntity == NULL || pEntity->pev == NULL ) + if( pEntity == NULL || pEntity->pev == NULL ) return ""; // return their team name @@ -485,12 +485,12 @@ const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) { - if ( pTeamName && *pTeamName != 0 ) + if( pTeamName && *pTeamName != 0 ) { // try to find existing team - for ( int tm = 0; tm < num_teams; tm++ ) + for( int tm = 0; tm < num_teams; tm++ ) { - if ( !stricmp( team_names[tm], pTeamName ) ) + if( !stricmp( team_names[tm], pTeamName ) ) return tm; } } @@ -500,15 +500,15 @@ int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) { - if ( teamIndex < 0 || teamIndex >= num_teams ) + if( teamIndex < 0 || teamIndex >= num_teams ) return ""; - return team_names[ teamIndex ]; + return team_names[teamIndex]; } BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) { - if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set + if( !m_teamLimit ) // Any team is valid if the teamlist isn't set return TRUE; return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; @@ -518,28 +518,28 @@ const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) { int i; int minPlayers = MAX_TEAMS; - int teamCount[ 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++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if ( plr ) + if( plr ) { int team = GetTeamIndex( plr->TeamID() ); - if ( team >= 0 ) - teamCount[team] ++; + if( team >= 0 ) + teamCount[team]++; } } // Find team with least players - for ( i = 0; i < num_teams; i++ ) + for( i = 0; i < num_teams; i++ ) { - if ( teamCount[i] < minPlayers ) + if( teamCount[i] < minPlayers ) { minPlayers = teamCount[i]; pTeamName = team_names[i]; @@ -553,8 +553,8 @@ const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) //========================================================= void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) { - char *pName; - char teamlist[TEAMPLAY_TEAMLISTLENGTH]; + char *pName; + char teamlist[TEAMPLAY_TEAMLISTLENGTH]; // loop through all teams, recounting everything num_teams = 0; @@ -564,9 +564,9 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) strcpy( teamlist, m_szTeamList ); pName = teamlist; pName = strtok( pName, ";" ); - while ( pName != NULL && *pName ) + while( pName != NULL && *pName ) { - if ( GetTeamIndex( pName ) < 0 ) + if( GetTeamIndex( pName ) < 0 ) { strcpy( team_names[num_teams], pName ); num_teams++; @@ -574,7 +574,7 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) pName = strtok( NULL, ";" ); } - if ( num_teams < 2 ) + if( num_teams < 2 ) { num_teams = 0; m_teamLimit = FALSE; @@ -584,20 +584,20 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) memset( team_scores, 0, sizeof(team_scores) ); // loop through all clients - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if ( plr ) + if( plr ) { const char *pTeamName = plr->TeamID(); // try add to existing team int tm = GetTeamIndex( pTeamName ); - if ( tm < 0 ) // no team match found + if( tm < 0 ) // no team match found { - if ( !m_teamLimit ) + if( !m_teamLimit ) { // add to new team tm = num_teams; @@ -607,14 +607,14 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) } } - if ( tm >= 0 ) + if( tm >= 0 ) { team_scores[tm] += plr->pev->frags; } - if ( bResendInfo ) //Someone's info changed, let's send the team info again. + if( bResendInfo ) //Someone's info changed, let's send the team info again. { - if ( plr && IsValidTeam( plr->TeamID() ) ) + if( plr && IsValidTeam( plr->TeamID() ) ) { MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo, NULL ); WRITE_BYTE( plr->entindex() ); diff --git a/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index 5d4246bd..06823ca6 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -16,7 +16,7 @@ // teamplay_gamerules.h // -#define MAX_TEAMNAME_LENGTH 16 +#define MAX_TEAMNAME_LENGTH 16 #define MAX_TEAMS 32 #define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH @@ -39,7 +39,7 @@ public: 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 void Think( void ); virtual int GetTeamIndex( const char *pTeamName ); virtual const char *GetIndexedTeamName( int teamIndex ); virtual BOOL IsValidTeam( const char *pTeamName ); diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index 3af50ee2..637b8946 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -28,30 +28,30 @@ #include "soundent.h" #define ACT_T_IDLE 1010 -#define ACT_T_TAP 1020 +#define ACT_T_TAP 1020 #define ACT_T_STRIKE 1030 -#define ACT_T_REARIDLE 1040 +#define ACT_T_REARIDLE 1040 class CTentacle : public CBaseMonster { public: CTentacle( void ); - void Spawn( ); - void Precache( ); + void Spawn(); + void Precache(); void KeyValue( KeyValueData *pkvd ); - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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; } + 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); + pev->absmin = pev->origin + Vector( -400, -400, 0 ); + pev->absmax = pev->origin + Vector( 400, 400, 850 ); } void EXPORT Cycle( void ); @@ -65,11 +65,11 @@ public: float HearingSensitivity( void ) { return 2.0; }; - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + 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; }; + MONSTERSTATE GetIdealState( void ) { return MONSTERSTATE_IDLE; }; int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; int Classify( void ); @@ -107,8 +107,8 @@ public: static const char *pHitWater[]; }; -int CTentacle :: g_fFlySound; -int CTentacle :: g_fSquirmSound; +int CTentacle::g_fFlySound; +int CTentacle::g_fSquirmSound; LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ) @@ -231,31 +231,31 @@ typedef enum // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CTentacle :: Classify ( void ) +int CTentacle::Classify( void ) { - return CLASS_ALIEN_MONSTER; + return CLASS_ALIEN_MONSTER; } // // Tentacle Spawn // -void CTentacle :: Spawn( ) +void CTentacle::Spawn() { - Precache( ); + Precache(); - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - pev->effects = 0; - pev->health = 75; - pev->sequence = 0; + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_FLY; + pev->effects = 0; + pev->health = 75; + pev->sequence = 0; - SET_MODEL(ENT(pev), "models/tentacle2.mdl"); + 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; + pev->takedamage = DAMAGE_AIM; + pev->flags |= FL_MONSTER; - m_bloodColor = BLOOD_COLOR_GREEN; + m_bloodColor = BLOOD_COLOR_GREEN; SetThink( &CTentacle::Start ); SetTouch( &CTentacle::HitTouch ); @@ -263,7 +263,7 @@ void CTentacle :: Spawn( ) pev->nextthink = gpGlobals->time + 0.2; - ResetSequenceInfo( ); + ResetSequenceInfo(); m_iDir = 1; pev->yaw_speed = 18; @@ -275,7 +275,7 @@ void CTentacle :: Spawn( ) m_iHitDmg = 20; - if (m_flMaxYaw <= 0) + if( m_flMaxYaw <= 0 ) m_flMaxYaw = 65; m_MonsterState = MONSTERSTATE_IDLE; @@ -284,36 +284,36 @@ void CTentacle :: Spawn( ) UTIL_SetOrigin( pev, pev->origin ); } -void CTentacle :: Precache( ) +void CTentacle::Precache() { - PRECACHE_MODEL("models/tentacle2.mdl"); + PRECACHE_MODEL( "models/tentacle2.mdl" ); - PRECACHE_SOUND("ambience/flies.wav"); - PRECACHE_SOUND("ambience/squirm2.wav"); + 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( "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( ) +CTentacle::CTentacle() { m_flMaxYaw = 65; m_iTapSound = 0; @@ -321,34 +321,34 @@ CTentacle::CTentacle( ) void CTentacle::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "sweeparc")) + if( FStrEq( pkvd->szKeyName, "sweeparc" ) ) { - m_flMaxYaw = atof(pkvd->szValue) / 2.0; + m_flMaxYaw = atof( pkvd->szValue ) / 2.0; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "sound")) + else if( FStrEq( pkvd->szKeyName, "sound" ) ) { - m_iTapSound = atoi(pkvd->szValue); + m_iTapSound = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else CBaseMonster::KeyValue( pkvd ); } -int CTentacle :: Level( float dz ) +int CTentacle::Level( float dz ) { - if (dz < 216) + if( dz < 216 ) return 0; - if (dz < 408) + if( dz < 408 ) return 1; - if (dz < 600) + if( dz < 600 ) return 2; return 3; } -float CTentacle :: MyHeight( ) +float CTentacle::MyHeight() { - switch ( MyLevel( ) ) + switch( MyLevel() ) { case 1: return 256; @@ -360,7 +360,7 @@ float CTentacle :: MyHeight( ) return 0; } -int CTentacle :: MyLevel( ) +int CTentacle::MyLevel() { switch( pev->sequence ) { @@ -421,56 +421,56 @@ int CTentacle :: MyLevel( ) return -1; } -void CTentacle :: Test( void ) +void CTentacle::Test( void ) { pev->sequence = TENTACLE_ANIM_Floor_Strike; pev->framerate = 0; - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; } // // TentacleThink // -void CTentacle :: Cycle( void ) +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) + if( m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT ) { pev->angles.y = m_flInitialYaw; pev->ideal_yaw = m_flInitialYaw; ClearConditions( IgnoreConditions() ); - MonsterThink( ); + MonsterThink(); m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; return; } - DispatchAnimEvents( ); - StudioFrameAdvance( ); + DispatchAnimEvents(); + StudioFrameAdvance(); ChangeYaw( pev->yaw_speed ); CSound *pSound; - Listen( ); + Listen(); // Listen will set this if there's something in my sound list - if ( HasConditions( bits_COND_HEAR_SOUND ) ) + if( HasConditions( bits_COND_HEAR_SOUND ) ) pSound = PBestSound(); else pSound = NULL; - if ( pSound ) + if( pSound ) { Vector vecDir; - if (gpGlobals->time - m_flPrevSoundTime < 0.5) + 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; + vecDir = pSound->m_vecOrigin + ( pSound->m_vecOrigin - m_vecPrevSound ) / dt - pev->origin; } else { @@ -479,27 +479,31 @@ void CTentacle :: Cycle( void ) m_flPrevSoundTime = gpGlobals->time; m_vecPrevSound = pSound->m_vecOrigin; - m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; + m_flSoundYaw = UTIL_VecToYaw( vecDir ) - m_flInitialYaw; m_iSoundLevel = Level( vecDir.z ); - if (m_flSoundYaw < -180) + if( m_flSoundYaw < -180 ) m_flSoundYaw += 360; - if (m_flSoundYaw > 180) + if( m_flSoundYaw > 180 ) m_flSoundYaw -= 360; // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); - if (m_flSoundTime < gpGlobals->time) + if( m_flSoundTime < gpGlobals->time ) { // play "I hear new something" sound - char *sound; + char *sound; - switch( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: sound = "tentacle/te_alert1.wav"; break; - case 1: sound = "tentacle/te_alert2.wav"; break; + 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); + // UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), sound, 1.0, ATTN_NORM, 0, 100 ); } m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); } @@ -516,38 +520,38 @@ void CTentacle :: Cycle( void ) case TENTACLE_ANIM_Lev2_Rear_Idle: case TENTACLE_ANIM_Lev3_Rear: case TENTACLE_ANIM_Lev3_Rear_Idle: - if (dy < 0 && dy > -m_flMaxYaw) + if( dy < 0 && dy > -m_flMaxYaw ) dy = -m_flMaxYaw; - if (dy > 0 && dy < m_flMaxYaw) + if( dy > 0 && dy < m_flMaxYaw ) dy = m_flMaxYaw; break; default: - if (dy < -m_flMaxYaw) + if( dy < -m_flMaxYaw ) dy = -m_flMaxYaw; - if (dy > m_flMaxYaw) + if( dy > m_flMaxYaw ) dy = m_flMaxYaw; } pev->ideal_yaw = m_flInitialYaw + dy; - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); - if (pev->health <= 1) + if( pev->health <= 1 ) { m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - if (pev->sequence == TENTACLE_ANIM_Pit_Idle) + if( pev->sequence == TENTACLE_ANIM_Pit_Idle ) { pev->health = 75; } } - else if ( m_flSoundTime > gpGlobals->time ) + else if( m_flSoundTime > gpGlobals->time ) { - if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) + 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) + else if( m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2 ) { // tap m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); @@ -558,16 +562,16 @@ void CTentacle :: Cycle( void ) m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); } } - else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) + 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) + else if( pev->sequence == m_iGoalAnim ) { - if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) + if( MyLevel() >= 0 && gpGlobals->time < m_flSoundTime ) { - if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) + if( RANDOM_LONG( 0, 9 ) < m_flSoundTime - gpGlobals->time ) { // continue stike m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); @@ -578,45 +582,49 @@ void CTentacle :: Cycle( void ) m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); } } - else if (MyLevel( ) < 0) + else if( MyLevel() < 0 ) { m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); } else { - if (m_flNextSong < gpGlobals->time) + if( m_flNextSong < gpGlobals->time ) { // play "I hear new something" sound char *sound; - switch( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: sound = "tentacle/te_sing1.wav"; break; - case 1: sound = "tentacle/te_sing2.wav"; break; + 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); + 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) + if( RANDOM_LONG( 0,15 ) == 0 ) { // idle on new level - m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); + m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG( 0, 3 ) ); } - else if (RANDOM_LONG(0,3) == 0) + else if( RANDOM_LONG( 0, 3 ) == 0 ) { // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); + m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel() ); } else { // idle - m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); + m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel() ); } } - if (m_flSoundYaw < 0) + if( m_flSoundYaw < 0 ) m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); else m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); @@ -624,7 +632,7 @@ void CTentacle :: Cycle( void ) pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - if (m_iDir > 0) + if( m_iDir > 0 ) { pev->frame = 0; } @@ -633,12 +641,12 @@ void CTentacle :: Cycle( void ) m_iDir = -1; // just to safe pev->frame = 255; } - ResetSequenceInfo( ); + ResetSequenceInfo(); m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; - switch( pev->sequence) + switch( pev->sequence ) { case TENTACLE_ANIM_Floor_Tap: case TENTACLE_ANIM_Lev1_Tap: @@ -650,10 +658,10 @@ void CTentacle :: Cycle( void ) TraceResult tr1, tr2; - vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); + 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); + 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 ); @@ -665,19 +673,19 @@ void CTentacle :: Cycle( void ) m_flTapRadius = 336; // 400 - 64 break; } - pev->view_ofs.z = MyHeight( ); + pev->view_ofs.z = MyHeight(); // ALERT( at_console, "seq %d\n", pev->sequence ); } - if (m_flPrevSoundTime + 2.0 > gpGlobals->time) + 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) + 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; + pev->framerate = m_iDir + m_iDir * ( 5 - ( gpGlobals->time - m_flPrevSoundTime ) ) / 2 + m_flFramerateAdj; } } @@ -692,10 +700,10 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; break; case USE_ON: - if (pActivator) + if( pActivator ) { - // ALERT( at_console, "insert sound\n"); - CSoundEnt::InsertSound ( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); + // ALERT( at_console, "insert sound\n" ); + CSoundEnt::InsertSound( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); } break; case USE_SET: @@ -706,21 +714,20 @@ void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; break; } - } -void CTentacle :: DieThink( void ) +void CTentacle::DieThink( void ) { pev->nextthink = gpGlobals-> time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); + DispatchAnimEvents(); + StudioFrameAdvance(); ChangeYaw( 24 ); - if (m_fSequenceFinished) + if( m_fSequenceFinished ) { - if (pev->sequence == m_iGoalAnim) + if( pev->sequence == m_iGoalAnim ) { switch( m_iGoalAnim ) { @@ -742,7 +749,7 @@ void CTentacle :: DieThink( void ) pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); // ALERT( at_console, "%d\n", pev->sequence ); - if (m_iDir > 0) + if( m_iDir > 0 ) { pev->frame = 0; } @@ -750,7 +757,7 @@ void CTentacle :: DieThink( void ) { pev->frame = 255; } - ResetSequenceInfo( ); + ResetSequenceInfo(); float dy; switch( pev->sequence ) @@ -782,97 +789,119 @@ void CTentacle :: DieThink( void ) } } -void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CTentacle::HandleAnimEvent( MonsterEvent_t *pEvent ) { char *sound; switch( pEvent->event ) { - case 1: // bang + 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 ); + // 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( ); + // vecSrc.z += MyHeight(); switch( m_iTapSound ) { case TE_SILO: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100); + 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); + 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); + UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100 ); break; } - gpGlobals->force_retouch++; + gpGlobals->force_retouch++; } break; - case 3: // start killing swing + 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); + // 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 + 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); + 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 + 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 ); + 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( ); + 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); + 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); + 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); + 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 7: + // roar + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: sound = "tentacle/te_roar1.wav"; break; - case 1: sound = "tentacle/te_roar2.wav"; break; + 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 8: // search - switch( RANDOM_LONG(0,1) ) + case 9: + // swing + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: sound = "tentacle/te_search1.wav"; break; - case 1: sound = "tentacle/te_search2.wav"; break; + 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; - 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); + UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), sound, 1.0, ATTN_NORM, 0, 100 ); break; default: CBaseMonster::HandleAnimEvent( pEvent ); @@ -882,46 +911,46 @@ void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) // // TentacleStart // -// void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -void CTentacle :: Start( void ) +// void CTentacle::Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CTentacle::Start( void ) { SetThink( &CTentacle::Cycle ); - if ( !g_fFlySound ) + if( !g_fFlySound ) { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); + 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 ) + else if( !g_fSquirmSound ) { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); + 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 ) +void CTentacle::HitTouch( CBaseEntity *pOther ) { - TraceResult tr = UTIL_GetGlobalTrace( ); + TraceResult tr = UTIL_GetGlobalTrace(); - if (pOther->pev->modelindex == pev->modelindex) + if( pOther->pev->modelindex == pev->modelindex ) return; - if (m_flHitTime > gpGlobals->time) + 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) + if( tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex ) return; - if (tr.iHitgroup >= 3) + if( tr.iHitgroup >= 3 ) { pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); // ALERT( at_console, "wack %3d : ", m_iHitDmg ); } - else if (tr.iHitgroup != 0) + else if( tr.iHitgroup != 0 ) { pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); // ALERT( at_console, "tap %3d : ", 20 ); @@ -938,9 +967,9 @@ void CTentacle :: HitTouch( CBaseEntity *pOther ) // 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 ) +int CTentacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if (flDamage > pev->health) + if( flDamage > pev->health ) { pev->health = 1; } @@ -951,7 +980,7 @@ int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa return 1; } -void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) +void CTentacle::Killed( entvars_t *pevAttacker, int iGib ) { m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; return; @@ -960,8 +989,8 @@ void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) class CTentacleMaw : public CBaseMonster { public: - void Spawn( ); - void Precache( ); + void Spawn(); + void Precache(); }; LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ) @@ -969,25 +998,25 @@ LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ) // // Tentacle Spawn // -void CTentacleMaw :: Spawn( ) +void CTentacleMaw::Spawn() { - Precache( ); - SET_MODEL(ENT(pev), "models/maw.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + 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->solid = SOLID_NOT; + pev->movetype = MOVETYPE_STEP; + pev->effects = 0; + pev->health = 75; + pev->yaw_speed = 8; + pev->sequence = 0; - pev->angles.x = 90; + pev->angles.x = 90; // ResetSequenceInfo( ); } -void CTentacleMaw :: Precache( ) +void CTentacleMaw::Precache() { - PRECACHE_MODEL("models/maw.mdl"); + PRECACHE_MODEL( "models/maw.mdl" ); } #endif diff --git a/dlls/trains.h b/dlls/trains.h index f1fabaae..e8003b3e 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -25,11 +25,11 @@ #define SF_PATH_DISABLED 0x00000001 #define SF_PATH_FIREONCE 0x00000002 #define SF_PATH_ALTREVERSE 0x00000004 -#define SF_PATH_DISABLE_TRAIN 0x00000008 +#define SF_PATH_DISABLE_TRAIN 0x00000008 #define SF_PATH_ALTERNATE 0x00008000 // Spawnflags of CPathCorner -#define SF_CORNER_WAITFORTRIG 0x001 +#define SF_CORNER_WAITFORTRIG 0x001 #define SF_CORNER_TELEPORT 0x002 #define SF_CORNER_FIREONCE 0x004 @@ -37,37 +37,37 @@ class CPathTrack : public CPointEntity { public: - void Spawn( void ); - void Activate( void ); - void KeyValue( KeyValueData* pkvd); + 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 ); + 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 ); + 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 *LookAhead( Vector *origin, float dist, int move ); + CPathTrack *Nearest( Vector origin ); - CPathTrack *GetNext( void ); - CPathTrack *GetPrevious( void ); + CPathTrack *GetNext( void ); + CPathTrack *GetPrevious( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; #if PATH_SPARKLE_DEBUG - void EXPORT Sparkle(void); + void EXPORT Sparkle( void ); #endif - float m_length; - string_t m_altName; - CPathTrack *m_pnext; - CPathTrack *m_pprevious; - CPathTrack *m_paltpath; + float m_length; + string_t m_altName; + CPathTrack *m_pnext; + CPathTrack *m_pprevious; + CPathTrack *m_paltpath; }; class CFuncTrackTrain : public CBaseEntity @@ -85,38 +85,38 @@ public: void EXPORT NearestPath( void ); void EXPORT DeadEnd( void ); - void NextThink( float thinkTime, BOOL alwaysThink ); + void NextThink( float thinkTime, BOOL alwaysThink ); - void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(pev->origin); } + 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 ); - + 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 int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - virtual void OverrideReset( void ); + static TYPEDESCRIPTION m_SaveData[]; + virtual int ObjectCaps( void ) { return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | FCAP_DIRECTIONAL_USE; } - 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; + 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; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index a6e8102b..d7f9483c 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -43,17 +43,17 @@ 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 ); + 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; } + virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; - float m_frictionFraction; // Sorry, couldn't resist this name :) + float m_frictionFraction; // Sorry, couldn't resist this name :) }; LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ) @@ -67,27 +67,27 @@ TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFrictionModifier, CBaseEntity ) // Modify an entity's friction -void CFrictionModifier :: Spawn( void ) +void CFrictionModifier::Spawn( void ) { pev->solid = SOLID_TRIGGER; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + 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 ) +void CFrictionModifier::ChangeFriction( CBaseEntity *pOther ) { - if ( pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE ) + 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 ) +void CFrictionModifier::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "modifier")) + if( FStrEq(pkvd->szKeyName, "modifier" ) ) { - m_frictionFraction = atof(pkvd->szValue) / 100.0; + m_frictionFraction = atof( pkvd->szValue ) / 100.0; pkvd->fHandled = TRUE; } else @@ -108,14 +108,14 @@ public: void Think( void ); int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; private: - int m_globalstate; - USE_TYPE triggerType; + int m_globalstate; + USE_TYPE triggerType; }; LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ) @@ -130,12 +130,12 @@ IMPLEMENT_SAVERESTORE( CAutoTrigger, CBaseDelay ) void CAutoTrigger::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "globalstate")) + if( FStrEq( pkvd->szKeyName, "globalstate" ) ) { m_globalstate = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) + else if( FStrEq( pkvd->szKeyName, "triggerstate" ) ) { int type = atoi( pkvd->szValue ); switch( type ) @@ -168,10 +168,10 @@ void CAutoTrigger::Precache( void ) void CAutoTrigger::Think( void ) { - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) + if( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) { SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_AUTO_FIREONCE ) + if( pev->spawnflags & SF_AUTO_FIREONCE ) UTIL_Remove( this ); } } @@ -186,13 +186,13 @@ public: 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; private: - USE_TYPE triggerType; + USE_TYPE triggerType; }; LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ) @@ -206,7 +206,7 @@ IMPLEMENT_SAVERESTORE( CTriggerRelay, CBaseDelay ) void CTriggerRelay::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "triggerstate")) + if( FStrEq( pkvd->szKeyName, "triggerstate" ) ) { int type = atoi( pkvd->szValue ); switch( type ) @@ -234,7 +234,7 @@ 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 ) + if( pev->spawnflags & SF_RELAY_FIREONCE ) UTIL_Remove( this ); } @@ -251,35 +251,35 @@ 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 ); + 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 ); + BOOL HasTarget( string_t targetname ); int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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 + 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 ) + inline BOOL IsClone( void ) { return ( pev->spawnflags & SF_MULTIMAN_CLONE ) ? TRUE : FALSE; } + inline BOOL ShouldClone( void ) { - if ( IsClone() ) + if( IsClone() ) return FALSE; - return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE; + return ( pev->spawnflags & SF_MULTIMAN_THREAD ) ? TRUE : FALSE; } CMultiManager *Clone( void ); @@ -297,37 +297,37 @@ TYPEDESCRIPTION CMultiManager::m_SaveData[] = DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), }; -IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle) +IMPLEMENT_SAVERESTORE( CMultiManager, CBaseToggle ) -void CMultiManager :: KeyValue( KeyValueData *pkvd ) +void CMultiManager::KeyValue( KeyValueData *pkvd ) { // UNDONE: Maybe this should do something like this: //CBaseToggle::KeyValue( pkvd ); - // if ( !pkvd->fHandled ) + // if( !pkvd->fHandled ) // ... etc. - if (FStrEq(pkvd->szKeyName, "wait")) + if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_flWait = atof(pkvd->szValue); + 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 ) + 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_iTargetName[m_cTargets] = ALLOC_STRING( tmp ); + m_flTargetDelay[m_cTargets] = atof( pkvd->szValue ); m_cTargets++; pkvd->fHandled = TRUE; } } } -void CMultiManager :: Spawn( void ) +void CMultiManager::Spawn( void ) { pev->solid = SOLID_NOT; SetUse( &CMultiManager::ManagerUse ); @@ -337,20 +337,20 @@ void CMultiManager :: Spawn( void ) // Quick and dirty bubble sort int swapped = 1; - while ( swapped ) + while( swapped ) { swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) + for( int i = 1; i < m_cTargets; i++ ) { - if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) + 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; + 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; } } @@ -359,8 +359,8 @@ void CMultiManager :: Spawn( void ) BOOL CMultiManager::HasTarget( string_t targetname ) { - for ( int i = 0; i < m_cTargets; i++ ) - if ( FStrEq(STRING(targetname), STRING(m_iTargetName[i])) ) + for( int i = 0; i < m_cTargets; i++ ) + if( FStrEq( STRING( targetname ), STRING( m_iTargetName[i] ) ) ) return TRUE; return FALSE; @@ -368,21 +368,21 @@ BOOL CMultiManager::HasTarget( string_t targetname ) // 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 ) +void CMultiManager::ManagerThink( void ) { - float time; + float time; time = gpGlobals->time - m_startTime; - while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) + while( m_index < m_cTargets && m_flTargetDelay[m_index] <= time ) { - FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); + FireTargets( STRING( m_iTargetName[m_index] ), m_hActivator, this, USE_TOGGLE, 0 ); m_index++; } - if ( m_index >= m_cTargets )// have we fired all targets? + if( m_index >= m_cTargets )// have we fired all targets? { SetThink( NULL ); - if ( IsClone() ) + if( IsClone() ) { UTIL_Remove( this ); return; @@ -390,7 +390,7 @@ void CMultiManager :: ManagerThink ( void ) SetUse( &CMultiManager::ManagerUse );// allow manager re-use } else - pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; + pev->nextthink = m_startTime + m_flTargetDelay[m_index]; } CMultiManager *CMultiManager::Clone( void ) @@ -410,11 +410,11 @@ CMultiManager *CMultiManager::Clone( void ) } // The USE function builds the time table and starts the entity thinking. -void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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() ) + if( ShouldClone() ) { CMultiManager *pClone = Clone(); pClone->ManagerUse( pActivator, pCaller, useType, value ); @@ -432,13 +432,13 @@ void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller } #if _DEBUG -void CMultiManager :: ManagerReport ( void ) +void CMultiManager::ManagerReport( void ) { - int cIndex; + int cIndex; - for ( cIndex = 0 ; cIndex < m_cTargets ; cIndex++ ) + for( cIndex = 0; cIndex < m_cTargets; cIndex++ ) { - ALERT ( at_console, "%s %f\n", STRING(m_iTargetName[cIndex]), m_flTargetDelay[cIndex] ); + ALERT( at_console, "%s %f\n", STRING( m_iTargetName[cIndex] ), m_flTargetDelay[cIndex] ); } } #endif @@ -452,44 +452,44 @@ void CMultiManager :: ManagerReport ( void ) // // 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) +#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 ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); }; LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ) -void CRenderFxManager :: Spawn ( void ) +void CRenderFxManager::Spawn( void ) { pev->solid = SOLID_NOT; } -void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CRenderFxManager::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if (!FStringNull(pev->target)) + if( !FStringNull( pev->target ) ) { - edict_t* pentTarget = NULL; - while ( 1 ) + edict_t *pentTarget = NULL; + while( 1 ) { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) + 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 ) ) + if( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) pevTarget->renderfx = pev->renderfx; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) + if( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) pevTarget->renderamt = pev->renderamt; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) + if( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) pevTarget->rendermode = pev->rendermode; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) + if( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) pevTarget->rendercolor = pev->rendercolor; } } @@ -498,18 +498,18 @@ void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, US class CBaseTrigger : public CBaseToggle { public: - void EXPORT TeleportTouch ( CBaseEntity *pOther ); + 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 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 EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void InitTrigger( void ); - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } }; LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ) @@ -519,38 +519,37 @@ LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ) InitTrigger ================ */ -void 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); + 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 ) + 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 ) +void CBaseTrigger::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "damage")) + if( FStrEq( pkvd->szKeyName, "damage" ) ) { - pev->dmg = atof(pkvd->szValue); + pev->dmg = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "count")) + else if( FStrEq( pkvd->szKeyName, "count" ) ) { - m_cTriggersLeft = (int) atof(pkvd->szValue); + m_cTriggersLeft = (int)atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "damagetype")) + else if( FStrEq( pkvd->szKeyName, "damagetype" ) ) { - m_bitsDamageInflict = atoi(pkvd->szValue); + m_bitsDamageInflict = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -579,17 +578,17 @@ public: LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ) -void CTriggerMonsterJump :: Spawn ( void ) +void CTriggerMonsterJump::Spawn( void ) { - SetMovedir ( pev ); + SetMovedir( pev ); - InitTrigger (); + InitTrigger(); pev->nextthink = 0; pev->speed = 200; m_flHeight = 150; - if ( !FStringNull ( pev->targetname ) ) + if( !FStringNull( pev->targetname ) ) { // if targetted, spawn turned off pev->solid = SOLID_NOT; @@ -598,18 +597,18 @@ void CTriggerMonsterJump :: Spawn ( void ) } } -void CTriggerMonsterJump :: Think( void ) +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 ) +void CTriggerMonsterJump::Touch( CBaseEntity *pOther ) { entvars_t *pevOther = pOther->pev; - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) + if( !FBitSet( pevOther->flags, FL_MONSTER ) ) { // touched by a non-monster. return; @@ -617,7 +616,7 @@ void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) pevOther->origin.z += 1; - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) + if( FBitSet( pevOther->flags, FL_ONGROUND ) ) { // clear the onground so physics don't bitch pevOther->flags &= ~FL_ONGROUND; @@ -640,7 +639,7 @@ public: virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void PlayTrack( void ); - void Touch ( CBaseEntity *pOther ); + void Touch( CBaseEntity *pOther ); }; LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ) @@ -649,9 +648,9 @@ 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 ) +void CTriggerCDAudio::Touch( CBaseEntity *pOther ) { - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { // only clients may trigger these events return; @@ -660,7 +659,7 @@ void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) PlayTrack(); } -void CTriggerCDAudio :: Spawn( void ) +void CTriggerCDAudio::Spawn( void ) { InitTrigger(); } @@ -678,30 +677,30 @@ void PlayCDTrack( int iTrack ) pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); // Can't play if the client is not connected! - if ( !pClient ) + if( !pClient ) return; - if ( iTrack < -1 || iTrack > 30 ) + if( iTrack < -1 || iTrack > 30 ) { - ALERT ( at_console, "TriggerCDAudio - Track %d out of range\n" ); + ALERT( at_console, "TriggerCDAudio - Track %d out of range\n" ); return; } - if ( iTrack == -1 ) + if( iTrack == -1 ) { - CLIENT_COMMAND ( pClient, "cd pause\n"); + CLIENT_COMMAND( pClient, "cd pause\n" ); } else { - char string [ 64 ]; + char string[64]; sprintf( string, "cd play %3d\n", iTrack ); - CLIENT_COMMAND ( pClient, string); + CLIENT_COMMAND( pClient, string ); } } // only plays for ONE client, so only use in single play! -void CTriggerCDAudio :: PlayTrack( void ) +void CTriggerCDAudio::PlayTrack( void ) { PlayCDTrack( (int)pev->health ); @@ -713,33 +712,33 @@ void CTriggerCDAudio :: PlayTrack( void ) class CTargetCDAudio : public CPointEntity { public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); + 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 ); + 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 ) +void CTargetCDAudio::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "radius")) + if( FStrEq( pkvd->szKeyName, "radius" ) ) { - pev->scale = atof(pkvd->szValue); + pev->scale = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else CPointEntity::KeyValue( pkvd ); } -void CTargetCDAudio :: Spawn( void ) +void CTargetCDAudio::Spawn( void ) { pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; - if ( pev->scale > 0 ) + if( pev->scale > 0 ) pev->nextthink = gpGlobals->time + 1.0; } @@ -757,34 +756,33 @@ void CTargetCDAudio::Think( void ) pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); // Can't play if the client is not connected! - if ( !pClient ) + if( !pClient ) return; pev->nextthink = gpGlobals->time + 0.5; - if ( (pClient->v.origin - pev->origin).Length() <= pev->scale ) + if( ( pClient->v.origin - pev->origin ).Length() <= pev->scale ) Play(); } void CTargetCDAudio::Play( void ) -{ +{ PlayCDTrack( (int)pev->health ); - UTIL_Remove(this); + 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 ) +void CTriggerHurt::Spawn( void ) { InitTrigger(); SetTouch( &CBaseTrigger::HurtTouch ); - if ( !FStringNull ( pev->targetname ) ) + if( !FStringNull( pev->targetname ) ) { SetUse( &CBaseTrigger::ToggleUse ); } @@ -793,13 +791,13 @@ void CTriggerHurt :: Spawn( void ) SetUse( NULL ); } - if (m_bitsDamageInflict & DMG_RADIATION) + if( m_bitsDamageInflict & DMG_RADIATION ) { SetThink( &CTriggerHurt::RadiationThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); + 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. + 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 @@ -808,10 +806,8 @@ void CTriggerHurt :: Spawn( void ) // 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 ) +void CTriggerHurt::RadiationThink( void ) { - edict_t *pentPlayer; CBasePlayer *pPlayer = NULL; float flRange; @@ -829,24 +825,24 @@ void CTriggerHurt :: RadiationThink( void ) origin = pev->origin; view_ofs = pev->view_ofs; - pev->origin = (pev->absmin + pev->absmax) * 0.5; + pev->origin = ( pev->absmin + pev->absmax ) * 0.5; pev->view_ofs = pev->view_ofs * 0.0; - pentPlayer = FIND_CLIENT_IN_PVS(edict()); + pentPlayer = FIND_CLIENT_IN_PVS( edict() ); pev->origin = origin; pev->view_ofs = view_ofs; // reset origin - if (!FNullEnt(pentPlayer)) + if( !FNullEnt( pentPlayer ) ) { - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); + pPlayer = GetClassPtr( (CBasePlayer *)VARS( pentPlayer ) ); - pevTarget = VARS(pentPlayer); + pevTarget = VARS( pentPlayer ); // get range to player; - vecSpot1 = (pev->absmin + pev->absmax) * 0.5; - vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; + vecSpot1 = ( pev->absmin + pev->absmax ) * 0.5; + vecSpot2 = ( pevTarget->absmin + pevTarget->absmax ) * 0.5; vecRange = vecSpot1 - vecSpot2; flRange = vecRange.Length(); @@ -855,7 +851,7 @@ void CTriggerHurt :: RadiationThink( void ) // than range to this trigger hurt, reset player's // geiger counter range - if (pPlayer->m_flgeigerRange >= flRange) + if( pPlayer->m_flgeigerRange >= flRange ) pPlayer->m_flgeigerRange = flRange; } @@ -865,9 +861,9 @@ void CTriggerHurt :: RadiationThink( void ) // // 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 ) +void CBaseTrigger::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if (pev->solid == SOLID_NOT) + if( pev->solid == SOLID_NOT ) { // if the trigger is off, turn it on pev->solid = SOLID_TRIGGER; @@ -884,38 +880,38 @@ void CBaseTrigger :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, } // When touched, a hurt trigger does DMG points of damage each half-second -void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) +void CBaseTrigger::HurtTouch( CBaseEntity *pOther ) { float fldmg; - if ( !pOther->pev->takedamage ) + if( !pOther->pev->takedamage ) return; - if ( (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer() ) + 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() ) + 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( g_pGameRules->IsMultiplayer() ) { - if ( pev->dmgtime > gpGlobals->time ) + if( pev->dmgtime > gpGlobals->time ) { - if ( gpGlobals->time != pev->pain_finished ) + if( gpGlobals->time != pev->pain_finished ) { // too early to hurt again, and not same frame with a different entity - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { - int playerMask = 1 << (pOther->entindex() - 1); + int playerMask = 1 << ( pOther->entindex() - 1 ); // If I've already touched this player (this time), then bail out - if ( pev->impulse & playerMask ) + if( pev->impulse & playerMask ) return; // Mark this player as touched @@ -932,9 +928,9 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) { // New clock, "un-touch" all players pev->impulse = 0; - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { - int playerMask = 1 << (pOther->entindex() - 1); + int playerMask = 1 << ( pOther->entindex() - 1 ); // Mark this player as touched // BUGBUG - There can be only 32 players! @@ -944,7 +940,7 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) } else // Original code -- single player { - if ( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) + if( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) { // too early to hurt again, and not same frame with a different entity return; @@ -960,19 +956,34 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) // JAY: Cut this because it wasn't fully realized. Damage is simpler now. #if 0 - switch (m_bitsDamageInflict) + 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; + 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: // UNDONE: cut this? should slow movement to 50% + fldmg = PARALYZE_DAMAGE / 4; + break; + 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 ) + if( fldmg < 0 ) pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); else pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); @@ -983,20 +994,20 @@ void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) // Apply damage every half second pev->dmgtime = gpGlobals->time + 0.5;// half second delay until this trigger can hurt toucher again - if ( pev->target ) + if( pev->target ) { // trigger has a target it wants to fire. - if ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) + if( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) { // if the toucher isn't a client, don't fire the target! - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { return; } } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - if ( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) + if( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) pev->target = 0; } } @@ -1024,28 +1035,28 @@ public: LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ) -void CTriggerMultiple :: Spawn( void ) +void CTriggerMultiple::Spawn( void ) { - if (m_flWait == 0) + 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 + 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( &CBaseTrigger::MultiTouch ); } @@ -1075,27 +1086,27 @@ void CTriggerOnce::Spawn( void ) { m_flWait = -1; - CTriggerMultiple :: Spawn(); + CTriggerMultiple::Spawn(); } -void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) +void CBaseTrigger::MultiTouch( CBaseEntity *pOther ) { - entvars_t *pevToucher; + 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)) || + 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) + if( pev->movedir != g_vecZero ) { UTIL_MakeVectors( pevToucher->angles ); - if ( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) + if( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) return; // not facing the right way } #endif @@ -1108,23 +1119,23 @@ void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) // 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 ) +void CBaseTrigger::ActivateMultiTrigger( CBaseEntity *pActivator ) { - if (pev->nextthink > gpGlobals->time) + if( pev->nextthink > gpGlobals->time ) return; // still waiting for reset time - if (!UTIL_IsMasterTriggered(m_sMaster,pActivator)) + if( !UTIL_IsMasterTriggered( m_sMaster,pActivator ) ) return; - if (FClassnameIs(pev, "trigger_secret")) + if( FClassnameIs( pev, "trigger_secret" ) ) { - if ( pev->enemy == NULL || !FClassnameIs(pev->enemy, "player")) + 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); + 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; @@ -1132,13 +1143,13 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) m_hActivator = pActivator; SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - if ( pev->message && pActivator->IsPlayer() ) + if( pev->message && pActivator->IsPlayer() ) { - UTIL_ShowMessage( STRING(pev->message), pActivator ); - //CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); + UTIL_ShowMessage( STRING( pev->message ), pActivator ); + //CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING( pev->message ) ); } - if (m_flWait > 0) + if( m_flWait > 0 ) { SetThink( &CBaseTrigger::MultiWaitOver ); pev->nextthink = gpGlobals->time + m_flWait; @@ -1154,13 +1165,13 @@ void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) } // the wait time has passed, so set back up for another activation -void CBaseTrigger :: MultiWaitOver( void ) +void CBaseTrigger::MultiWaitOver( void ) { - /*if (pev->max_health) + /*if( pev->max_health ) { - pev->health = pev->max_health; + pev->health = pev->max_health; pev->takedamage = DAMAGE_YES; - pev->solid = SOLID_BBOX; + pev->solid = SOLID_BBOX; }*/ SetThink( NULL ); } @@ -1175,32 +1186,40 @@ void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US m_cTriggersLeft--; m_hActivator = pActivator; - if (m_cTriggersLeft < 0) + if( m_cTriggersLeft < 0 ) return; BOOL fTellActivator = - (m_hActivator != 0) && - FClassnameIs(m_hActivator->pev, "player") && - !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE); - if (m_cTriggersLeft != 0) + ( m_hActivator != 0 ) && + FClassnameIs( m_hActivator->pev, "player" ) && + !FBitSet( pev->spawnflags, SPAWNFLAG_NOMESSAGE ); + if( m_cTriggersLeft != 0 ) { - if (fTellActivator) + if( fTellActivator ) { // UNDONE: I don't think we want these Quakesque messages - switch (m_cTriggersLeft) + 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; + 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!"); + if( fTellActivator ) + ALERT( at_console, "Sequence completed!" ); ActivateMultiTrigger( m_hActivator ); } @@ -1219,13 +1238,13 @@ public: LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ) -void CTriggerCounter :: Spawn( void ) +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) + if( m_cTriggersLeft == 0 ) m_cTriggersLeft = 2; SetUse( &CBaseTrigger::CounterUse ); } @@ -1235,17 +1254,17 @@ void CTriggerCounter :: Spawn( void ) class CTriggerVolume : public CPointEntity // Derive from point entity so this doesn't move across levels { public: - void Spawn( void ); + void Spawn( void ); }; LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ) // Define space that travels across a level transition -void CTriggerVolume :: Spawn( void ) +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 + SET_MODEL( ENT(pev), STRING( pev->model ) ); // set size and link into world pev->model = NULL; pev->modelindex = 0; } @@ -1264,7 +1283,7 @@ LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ) void CFireAndDie::Spawn( void ) { - pev->classname = MAKE_STRING("fireanddie"); + pev->classname = MAKE_STRING( "fireanddie" ); // Don't call Precache() - it should be called on restore } @@ -1286,7 +1305,7 @@ 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 UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT TriggerChangeLevel( void ); void EXPORT ExecuteChangeLevel( void ); void EXPORT TouchChangeLevel( CBaseEntity *pOther ); @@ -1297,15 +1316,15 @@ public: 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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; + int m_changeTarget; + float m_changeTargetDelay; }; LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ) @@ -1324,29 +1343,28 @@ IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger) // // Cache user-entity-field values until spawn is called. // - -void CChangeLevel :: KeyValue( KeyValueData *pkvd ) +void CChangeLevel::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "map")) + if( FStrEq( pkvd->szKeyName, "map" ) ) { - if (strlen(pkvd->szValue) >= cchMapNameMost) + if( strlen( pkvd->szValue ) >= cchMapNameMost ) ALERT( at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szMapName, pkvd->szValue); + strcpy( m_szMapName, pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "landmark")) + else if( FStrEq( pkvd->szKeyName, "landmark" ) ) { - if (strlen(pkvd->szValue) >= cchMapNameMost) + if( strlen( pkvd->szValue ) >= cchMapNameMost ) ALERT( at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szLandmarkName, pkvd->szValue); + strcpy( m_szLandmarkName, pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "changetarget")) + else if( FStrEq( pkvd->szKeyName, "changetarget" ) ) { m_changeTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "changedelay")) + else if( FStrEq( pkvd->szKeyName, "changedelay" ) ) { m_changeTargetDelay = atof( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -1358,48 +1376,47 @@ void CChangeLevel :: KeyValue( KeyValueData *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 ) +void CChangeLevel::Spawn( void ) { - if ( FStrEq( m_szMapName, "" ) ) + if( FStrEq( m_szMapName, "" ) ) ALERT( at_console, "a trigger_changelevel doesn't have a map" ); - if ( FStrEq( m_szLandmarkName, "" ) ) + if( FStrEq( m_szLandmarkName, "" ) ) ALERT( at_console, "trigger_changelevel to %s doesn't have a landmark\n", m_szMapName ); - if (!FStringNull ( pev->targetname ) ) + if( !FStringNull( pev->targetname ) ) { SetUse( &CChangeLevel::UseChangeLevel ); } InitTrigger(); - if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) + if( !( pev->spawnflags & SF_CHANGELEVEL_USEONLY ) ) SetTouch( &CChangeLevel::TouchChangeLevel ); //ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); } -void CChangeLevel :: ExecuteChangeLevel( void ) +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_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 *CChangeLevel::FindLandmark( const char *pLandmarkName ) { edict_t *pentLandmark; pentLandmark = FIND_ENTITY_BY_STRING( NULL, "targetname", pLandmarkName ); - while ( !FNullEnt( pentLandmark ) ) + while( !FNullEnt( pentLandmark ) ) { // Found the landmark - if ( FClassnameIs( pentLandmark, "info_landmark" ) ) + if( FClassnameIs( pentLandmark, "info_landmark" ) ) return pentLandmark; else pentLandmark = FIND_ENTITY_BY_STRING( pentLandmark, "targetname", pLandmarkName ); @@ -1413,40 +1430,40 @@ edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) // triggered by buttons, etc. // //========================================================= -void CChangeLevel :: UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CChangeLevel::UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { ChangeLevelNow( pActivator ); } -void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) +void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) { edict_t *pentLandmark; - LEVELLIST levels[16]; + LEVELLIST levels[16]; - ASSERT(!FStrEq(m_szMapName, "")); + ASSERT( !FStrEq( m_szMapName, "" ) ); // Don't work in deathmatch - if ( g_pGameRules->IsDeathmatch() ) + if( g_pGameRules->IsDeathmatch() ) return; // Some people are firing these multiple times in a frame, disable - if ( gpGlobals->time == pev->dmgtime ) + if( gpGlobals->time == pev->dmgtime ) return; pev->dmgtime = gpGlobals->time; CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) + 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 ) + if( m_changeTarget ) { CFireAndDie *pFireAndDie = GetClassPtr( (CFireAndDie *)NULL ); - if ( pFireAndDie ) + if( pFireAndDie ) { // Set target and delay pFireAndDie->pev->target = m_changeTarget; @@ -1459,18 +1476,18 @@ void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) } // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy(st_szNextMap, m_szMapName); + 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 + // look for a landmark entity pentLandmark = FindLandmark( m_szLandmarkName ); - if ( !FNullEnt( pentLandmark ) ) + if( !FNullEnt( pentLandmark ) ) { - strcpy(st_szNextSpot, m_szLandmarkName); - gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; + 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 ); @@ -1480,9 +1497,9 @@ void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) // // GLOBALS ASSUMED SET: st_szNextMap // -void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) +void CChangeLevel::TouchChangeLevel( CBaseEntity *pOther ) { - if (!FClassnameIs(pOther->pev, "player")) + if( !FClassnameIs( pOther->pev, "player" ) ) return; ChangeLevelNow( pOther ); @@ -1494,18 +1511,18 @@ int CChangeLevel::AddTransitionToList( LEVELLIST *pLevelList, int listCount, con { int i; - if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) + if( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) return 0; - for ( i = 0; i < listCount; i++ ) + for( i = 0; i < listCount; i++ ) { - if ( pLevelList[i].pentLandmark == pentLandmark && strcmp( pLevelList[i].mapName, pMapName ) == 0 ) + 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; + pLevelList[listCount].vecLandmarkOrigin = VARS( pentLandmark )->origin; return 1; } @@ -1519,26 +1536,26 @@ int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) { edict_t *pentVolume; - if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) + 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->movetype == MOVETYPE_FOLLOW ) { - if ( pEntity->pev->aiment != NULL ) + 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 ) ) + while( !FNullEnt( pentVolume ) ) { CBaseEntity *pVolume = CBaseEntity::Instance( pentVolume ); - - if ( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) + + if( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) { - if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume + 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! @@ -1559,30 +1576,30 @@ int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) { edict_t *pentChangelevel, *pentLandmark; - int i, count; + 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 ) ) + if( FNullEnt( pentChangelevel ) ) return 0; - while ( !FNullEnt( pentChangelevel ) ) + while( !FNullEnt( pentChangelevel ) ) { CChangeLevel *pTrigger; pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); - if ( pTrigger ) + if( pTrigger ) { // Find the corresponding landmark pentLandmark = FindLandmark( pTrigger->m_szLandmarkName ); - if ( pentLandmark ) + if( pentLandmark ) { // Build a list of unique transitions - if ( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) + if( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) { count++; - if ( count >= maxList ) // FULL!! + if( count >= maxList ) // FULL!! break; } } @@ -1590,66 +1607,66 @@ int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) pentChangelevel = FIND_ENTITY_BY_STRING( pentChangelevel, "classname", "trigger_changelevel" ); } - if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) + if( gpGlobals->pSaveData && ( (SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) { CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); - for ( i = 0; i < count; i++ ) + for( i = 0; i < count; i++ ) { int j, entityCount = 0; - CBaseEntity *pEntList[ MAX_ENTITY ]; - int entityFlags[ MAX_ENTITY ]; + 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 ) ) + while( !FNullEnt( pent ) ) { - CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if ( pEntity ) + CBaseEntity *pEntity = CBaseEntity::Instance( pent ); + if( pEntity ) { - //ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); + //ALERT( at_console, "Trying %s\n", STRING( pEntity->pev->classname ) ); int caps = pEntity->ObjectCaps(); - if ( !(caps & FCAP_DONT_SAVE) ) + if( !(caps & FCAP_DONT_SAVE ) ) { int flags = 0; // If this entity can be moved or is global, mark it - if ( caps & FCAP_ACROSS_TRANSITION ) + if( caps & FCAP_ACROSS_TRANSITION ) flags |= FENTTABLE_MOVEABLE; - if ( pEntity->pev->globalname && !pEntity->IsDormant() ) + if( pEntity->pev->globalname && !pEntity->IsDormant() ) flags |= FENTTABLE_GLOBAL; - if ( flags ) + if( flags ) { - pEntList[ entityCount ] = pEntity; - entityFlags[ entityCount ] = flags; + pEntList[entityCount] = pEntity; + entityFlags[entityCount] = flags; entityCount++; - if ( entityCount > MAX_ENTITY ) + if( entityCount > MAX_ENTITY ) ALERT( at_error, "Too many entities across a transition!" ); } //else - // ALERT( at_console, "Failed %s\n", STRING(pEntity->pev->classname) ); + // ALERT( at_console, "Failed %s\n", STRING( pEntity->pev->classname ) ); } //else - // ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); + // ALERT( at_console, "DON'T SAVE %s\n", STRING( pEntity->pev->classname ) ); } pent = pent->v.chain; } - for ( j = 0; j < entityCount; j++ ) + 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 ) ) + if( entityFlags[j] && InTransitionVolume( pEntList[j], pLevelList[i].landmarkName ) ) { // Mark entity table with 1<pev->classname) ); + // ALERT( at_console, "Screened out %s\n", STRING( pEntList[j]->pev->classname ) ); } } } @@ -1667,22 +1684,22 @@ void NextLevel( void ) CChangeLevel *pChange; // find a trigger_changelevel - pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel"); + pent = FIND_ENTITY_BY_CLASSNAME( NULL, "trigger_changelevel" ); // go back to start if no trigger_changelevel - if (FNullEnt(pent)) + if( FNullEnt( pent ) ) { - gpGlobals->mapname = ALLOC_STRING("start"); + gpGlobals->mapname = ALLOC_STRING( "start" ); pChange = GetClassPtr( (CChangeLevel *)NULL ); - strcpy(pChange->m_szMapName, "start"); + strcpy( pChange->m_szMapName, "start" ); } else - pChange = GetClassPtr( (CChangeLevel *)VARS(pent)); + pChange = GetClassPtr( (CChangeLevel *)VARS( pent ) ); - strcpy(st_szNextMap, pChange->m_szMapName); + strcpy( st_szNextMap, pChange->m_szMapName ); g_fGameOver = TRUE; - if (pChange->pev->nextthink < gpGlobals->time) + if( pChange->pev->nextthink < gpGlobals->time ) { pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); pChange->pev->nextthink = gpGlobals->time + 0.1; @@ -1701,7 +1718,7 @@ public: LINK_ENTITY_TO_CLASS( func_ladder, CLadder ) -void CLadder :: KeyValue( KeyValueData *pkvd ) +void CLadder::KeyValue( KeyValueData *pkvd ) { CBaseTrigger::KeyValue( pkvd ); } @@ -1709,12 +1726,12 @@ void CLadder :: KeyValue( KeyValueData *pkvd ) //========================================================= // func_ladder - makes an area vertically negotiable //========================================================= -void CLadder :: Precache( void ) +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 ) + if( CVAR_GET_FLOAT( "showtriggers" ) == 0 ) { pev->rendermode = kRenderTransTexture; pev->renderamt = 0; @@ -1722,11 +1739,11 @@ void CLadder :: Precache( void ) pev->effects &= ~EF_NODRAW; } -void CLadder :: Spawn( void ) +void CLadder::Spawn( void ) { Precache(); - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world + SET_MODEL( ENT( pev ), STRING( pev->model ) ); // set size and link into world pev->movetype = MOVETYPE_PUSH; } @@ -1742,7 +1759,7 @@ public: LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ) -void CTriggerPush :: KeyValue( KeyValueData *pkvd ) +void CTriggerPush::KeyValue( KeyValueData *pkvd ) { CBaseTrigger::KeyValue( pkvd ); } @@ -1751,20 +1768,20 @@ void CTriggerPush :: KeyValue( KeyValueData *pkvd ) Pushes the player */ -void CTriggerPush :: Spawn( ) +void CTriggerPush::Spawn() { - if ( pev->angles == g_vecZero ) + if( pev->angles == g_vecZero ) pev->angles.y = 360; InitTrigger(); - if (pev->speed == 0) + if( pev->speed == 0 ) pev->speed = 100; // this flag was changed and flying barrels on c2a5 stay broken - if ( FStrEq( STRING( gpGlobals->mapname ), "c2a5" ) && pev->spawnflags & 4) + if( FStrEq( STRING( gpGlobals->mapname ), "c2a5" ) && pev->spawnflags & 4 ) pev->spawnflags |= SF_TRIG_PUSH_ONCE; - if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. + if( FBitSet( pev->spawnflags, SF_TRIGGER_PUSH_START_OFF ) )// if flagged to Start Turned Off, make trigger nonsolid. pev->solid = SOLID_NOT; SetUse( &CBaseTrigger::ToggleUse ); @@ -1772,9 +1789,9 @@ void CTriggerPush :: Spawn( ) UTIL_SetOrigin( pev, pev->origin ); // Link into the list } -void CTriggerPush :: Touch( CBaseEntity *pOther ) +void CTriggerPush::Touch( CBaseEntity *pOther ) { - entvars_t* pevToucher = pOther->pev; + entvars_t *pevToucher = pOther->pev; // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) switch( pevToucher->movetype ) @@ -1786,22 +1803,22 @@ void CTriggerPush :: Touch( CBaseEntity *pOther ) return; } - if ( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) + if( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) { // Instant trigger, just transfer velocity and remove - if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE)) + if( FBitSet( pev->spawnflags, SF_TRIG_PUSH_ONCE ) ) { - pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir); - if ( pevToucher->velocity.z > 0 ) + 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; + Vector vecPush = pev->speed * pev->movedir; + if( pevToucher->flags & FL_BASEVELOCITY ) + vecPush = vecPush + pevToucher->basevelocity; pevToucher->basevelocity = vecPush; @@ -1815,44 +1832,43 @@ void CTriggerPush :: Touch( CBaseEntity *pOther ) // teleport trigger // // - -void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) +void CBaseTrigger::TeleportTouch( CBaseEntity *pOther ) { - entvars_t* pevToucher = pOther->pev; + entvars_t *pevToucher = pOther->pev; edict_t *pentTarget = NULL; // Only teleport monsters or clients - if ( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER ) ) + if( !FBitSet( pevToucher->flags, FL_CLIENT | FL_MONSTER ) ) return; - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) + if( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) return; - if ( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) + if( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) { // no monsters allowed! - if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) + if( FBitSet( pevToucher->flags, FL_MONSTER ) ) { return; } } - if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) + if( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) { // no clients allowed - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { return; } } - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); - if (FNullEnt(pentTarget)) + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->target ) ); + if( FNullEnt( pentTarget ) ) return; Vector tmp = VARS( pentTarget )->origin; - if ( pOther->IsPlayer() ) + 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) } @@ -1865,7 +1881,7 @@ void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) pevToucher->angles = pentTarget->v.angles; - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { pevToucher->v_angle = pentTarget->v.angles; } @@ -1882,7 +1898,7 @@ public: LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ) -void CTriggerTeleport :: Spawn( void ) +void CTriggerTeleport::Spawn( void ) { InitTrigger(); @@ -1902,9 +1918,9 @@ LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ) void CTriggerSave::Spawn( void ) { - if ( g_pGameRules->IsDeathmatch() ) + if( g_pGameRules->IsDeathmatch() ) { - REMOVE_ENTITY( ENT(pev) ); + REMOVE_ENTITY( ENT( pev ) ); return; } @@ -1914,11 +1930,11 @@ void CTriggerSave::Spawn( void ) void CTriggerSave::SaveTouch( CBaseEntity *pOther ) { - if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) + if( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) return; // Only save on clients - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) return; SetTouch( NULL ); @@ -1942,23 +1958,23 @@ 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() ) + if( pActivator && !pActivator->IsNetClient() ) return; SetUse( NULL ); - if ( pev->message ) + if( pev->message ) { - g_engfuncs.pfnEndSection(STRING(pev->message)); + g_engfuncs.pfnEndSection( STRING( pev->message ) ); } UTIL_Remove( this ); } void CTriggerEndSection::Spawn( void ) { - if ( g_pGameRules->IsDeathmatch() ) + if( g_pGameRules->IsDeathmatch() ) { - REMOVE_ENTITY( ENT(pev) ); + REMOVE_ENTITY( ENT( pev ) ); return; } @@ -1967,28 +1983,28 @@ void CTriggerEndSection::Spawn( void ) SetUse( &CTriggerEndSection::EndSectionUse ); // If it is a "use only" trigger, then don't set the touch function. - if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) + if( !( pev->spawnflags & SF_ENDSECTION_USEONLY ) ) SetTouch( &CTriggerEndSection::EndSectionTouch ); } void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) { // Only save on clients - if ( !pOther->IsNetClient() ) + if( !pOther->IsNetClient() ) return; SetTouch( NULL ); - if (pev->message) + if( pev->message ) { - g_engfuncs.pfnEndSection(STRING(pev->message)); + g_engfuncs.pfnEndSection( STRING( pev->message ) ); } UTIL_Remove( this ); } -void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) +void CTriggerEndSection::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "section")) + 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 @@ -2017,7 +2033,7 @@ void CTriggerGravity::Spawn( void ) void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) { // Only save on clients - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) return; pOther->pev->gravity = pev->gravity; @@ -2032,13 +2048,13 @@ public: 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 ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; private: - int m_iszNewTarget; + int m_iszNewTarget; }; LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ) @@ -2048,11 +2064,11 @@ TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), }; -IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay) +IMPLEMENT_SAVERESTORE( CTriggerChangeTarget,CBaseDelay ) void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "m_iszNewTarget")) + if( FStrEq( pkvd->szKeyName, "m_iszNewTarget" ) ) { m_iszNewTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -2069,11 +2085,11 @@ void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, U { CBaseEntity *pTarget = UTIL_FindEntityByString( NULL, "targetname", STRING( pev->target ) ); - if (pTarget) + if( pTarget ) { pTarget->pev->target = m_iszNewTarget; - CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); - if (pMonster) + CBaseMonster *pMonster = pTarget->MyMonsterPointer(); + if( pMonster ) { pMonster->m_pGoalEnt = NULL; } @@ -2091,17 +2107,17 @@ public: void KeyValue( KeyValueData *pkvd ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT FollowTarget( void ); - void Move(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[]; + 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; + int m_sPath; float m_flWait; float m_flReturnTime; float m_flStopTime; @@ -2110,13 +2126,13 @@ public: float m_initialSpeed; float m_acceleration; float m_deceleration; - int m_state; + int m_state; }; LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ) // Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = +TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = { DEFINE_FIELD( CTriggerCamera, m_hPlayer, FIELD_EHANDLE ), DEFINE_FIELD( CTriggerCamera, m_hTarget, FIELD_EHANDLE ), @@ -2133,7 +2149,7 @@ TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), }; -IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay) +IMPLEMENT_SAVERESTORE( CTriggerCamera, CBaseDelay ) void CTriggerCamera::Spawn( void ) { @@ -2143,30 +2159,30 @@ void CTriggerCamera::Spawn( void ) pev->rendermode = kRenderTransTexture; m_initialSpeed = pev->speed; - if ( m_acceleration == 0 ) + if( m_acceleration == 0 ) m_acceleration = 500; - if ( m_deceleration == 0 ) + if( m_deceleration == 0 ) m_deceleration = 500; } -void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) +void CTriggerCamera::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "wait")) + if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_flWait = atof(pkvd->szValue); + m_flWait = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "moveto")) + else if( FStrEq(pkvd->szKeyName, "moveto" ) ) { m_sPath = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "acceleration")) + else if( FStrEq( pkvd->szKeyName, "acceleration" ) ) { m_acceleration = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "deceleration")) + else if( FStrEq(pkvd->szKeyName, "deceleration" ) ) { m_deceleration = atof( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -2177,28 +2193,28 @@ void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_state ) ) + if( !ShouldToggle( useType, m_state ) ) return; // Toggle state m_state = !m_state; - if (m_state == 0) + if( m_state == 0 ) { m_flReturnTime = gpGlobals->time; return; } - if ( !pActivator || !pActivator->IsPlayer() ) + if( !pActivator || !pActivator->IsPlayer() ) { - pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); + 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 ) ) + if( FBitSet( pev->spawnflags, SF_CAMERA_PLAYER_TARGET ) ) { m_hTarget = m_hPlayer; } @@ -2208,19 +2224,19 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP } // Nothing to look at! - if ( m_hTarget == NULL ) + if( m_hTarget == NULL ) { return; } - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) + if( FBitSet( pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) { - ((CBasePlayer *)pActivator)->EnableControl(FALSE); + ( (CBasePlayer *)pActivator )->EnableControl( FALSE ); } - if ( m_sPath ) + if( m_sPath ) { - m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_sPath)) ); + m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_sPath ) ) ); } else { @@ -2228,16 +2244,16 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP } m_flStopTime = gpGlobals->time; - if ( m_pentPath ) + if( m_pentPath ) { - if ( m_pentPath->pev->speed != 0 ) + 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 ) ) + 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; @@ -2252,7 +2268,7 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP SET_VIEW( pActivator->edict(), edict() ); - SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); + SET_MODEL( ENT( pev ), STRING( pActivator->pev->model ) ); // follow the player down SetThink( &CTriggerCamera::FollowTarget ); @@ -2262,17 +2278,17 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP Move(); } -void CTriggerCamera::FollowTarget( ) +void CTriggerCamera::FollowTarget() { - if (m_hPlayer == NULL) + if( m_hPlayer == NULL ) return; - if (m_hTarget == NULL || m_flReturnTime < gpGlobals->time) + if( m_hTarget == NULL || m_flReturnTime < gpGlobals->time ) { - if (m_hPlayer->IsAlive( )) + if( m_hPlayer->IsAlive() ) { SET_VIEW( m_hPlayer->edict(), m_hPlayer->edict() ); - ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE); + ( (CBasePlayer *)( (CBaseEntity *)m_hPlayer ) )->EnableControl( TRUE ); } SUB_UseTargets( this, USE_TOGGLE, 0 ); pev->avelocity = Vector( 0, 0, 0 ); @@ -2283,32 +2299,32 @@ void CTriggerCamera::FollowTarget( ) Vector vecGoal = UTIL_VecToAngles( m_hTarget->pev->origin - pev->origin ); vecGoal.x = -vecGoal.x; - if (pev->angles.y > 360) + if( pev->angles.y > 360 ) pev->angles.y -= 360; - if (pev->angles.y < 0) + 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) + if( dx < -180 ) dx += 360; - if (dx > 180) + if( dx > 180 ) dx = dx - 360; - if (dy < -180) + if( dy < -180 ) dy += 360; - if (dy > 180) + 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))) + if( !( FBitSet( pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) ) { pev->velocity = pev->velocity * 0.8; - if (pev->velocity.Length( ) < 10.0) + if( pev->velocity.Length() < 10.0 ) pev->velocity = g_vecZero; } @@ -2320,20 +2336,20 @@ void CTriggerCamera::FollowTarget( ) void CTriggerCamera::Move() { // Not moving on a path, return - if (!m_pentPath) + 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 ) + if( m_moveDistance <= 0 ) { // Fire the passtarget if there is one - if ( m_pentPath->pev->message ) + 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 ) ) + 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; } @@ -2341,13 +2357,13 @@ void CTriggerCamera::Move() m_pentPath = m_pentPath->GetNextTarget(); // Set up next corner - if ( !m_pentPath ) + if( !m_pentPath ) { pev->velocity = g_vecZero; } else { - if ( m_pentPath->pev->speed != 0 ) + if( m_pentPath->pev->speed != 0 ) m_targetSpeed = m_pentPath->pev->speed; Vector delta = m_pentPath->pev->origin - pev->origin; @@ -2357,11 +2373,11 @@ void CTriggerCamera::Move() } } - if ( m_flStopTime > gpGlobals->time ) + 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)); + pev->velocity = ( ( pev->movedir * pev->speed ) * fraction ) + ( pev->velocity * ( 1 - fraction ) ); } diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 477aa466..f04d906a 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -25,7 +25,8 @@ #define TRIPMINE_PRIMARY_VOLUME 450 -enum tripmine_e { +enum tripmine_e +{ TRIPMINE_IDLE1 = 0, TRIPMINE_IDLE2, TRIPMINE_ARM1, @@ -43,13 +44,13 @@ class CTripmineGrenade : public CGrenade void Spawn( void ); void Precache( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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 ); @@ -59,16 +60,16 @@ class CTripmineGrenade : public CGrenade void MakeBeam( void ); void KillBeam( void ); - float m_flPowerUp; - Vector m_vecDir; - Vector m_vecEnd; - float m_flBeamLength; + 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. + 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 ) @@ -86,27 +87,27 @@ TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = DEFINE_FIELD( CTripmineGrenade, m_pRealOwner, FIELD_EDICT ), }; -IMPLEMENT_SAVERESTORE(CTripmineGrenade,CGrenade) +IMPLEMENT_SAVERESTORE( CTripmineGrenade, CGrenade ) -void CTripmineGrenade :: Spawn( void ) +void CTripmineGrenade::Spawn( void ) { - Precache( ); + Precache(); // motor pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_NOT; - SET_MODEL(ENT(pev), "models/v_tripmine.mdl"); + SET_MODEL( ENT( pev ), "models/v_tripmine.mdl" ); pev->frame = 0; pev->body = 3; pev->sequence = TRIPMINE_WORLD; - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->framerate = 0; - UTIL_SetSize(pev, Vector( -8, -8, -8), Vector(8, 8, 8)); + UTIL_SetSize( pev, Vector( -8, -8, -8 ), Vector( 8, 8, 8 ) ); UTIL_SetOrigin( pev, pev->origin ); - if (pev->spawnflags & 1) + if( pev->spawnflags & 1 ) { // power up quickly m_flPowerUp = gpGlobals->time + 1.0; @@ -124,11 +125,11 @@ void CTripmineGrenade :: Spawn( void ) pev->dmg = gSkillData.plrDmgTripmine; pev->health = 1; // don't let die normally - if (pev->owner != NULL) + 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 + 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. } @@ -139,42 +140,42 @@ void CTripmineGrenade :: Spawn( void ) m_vecEnd = pev->origin + m_vecDir * 2048; } -void CTripmineGrenade :: Precache( void ) +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"); + 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 ) +void CTripmineGrenade::WarningThink( void ) { // play warning sound - // EMIT_SOUND( ENT(pev), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); + // 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 ) +void CTripmineGrenade::PowerupThink( void ) { TraceResult tr; - if (m_hOwner == NULL) + if( m_hOwner == NULL ) { // 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)) + 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) + if( tr.flFraction < 1.0 ) { pev->owner = tr.pHit; m_hOwner = CBaseEntity::Instance( pev->owner ); @@ -183,8 +184,8 @@ void CTripmineGrenade :: PowerupThink( void ) } else { - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); - STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); + STOP_SOUND( ENT( pev ), CHAN_VOICE, "weapons/mine_deploy.wav" ); + STOP_SOUND( ENT( pev ), CHAN_BODY, "weapons/mine_charge.wav" ); SetThink( &CBaseEntity::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 ); @@ -192,11 +193,11 @@ void CTripmineGrenade :: PowerupThink( void ) return; } } - else if (m_posOwner != m_hOwner->pev->origin || m_angleOwner != m_hOwner->pev->angles) + 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" ); + 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; @@ -207,30 +208,30 @@ void CTripmineGrenade :: PowerupThink( void ) } // 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) + if( gpGlobals->time > m_flPowerUp ) { // make solid pev->solid = SOLID_BBOX; UTIL_SetOrigin( pev, pev->origin ); - MakeBeam( ); + MakeBeam(); // play enabled sound - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1.0, 75 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1.0, 75 ); } pev->nextthink = gpGlobals->time + 0.1; } -void CTripmineGrenade :: KillBeam( void ) +void CTripmineGrenade::KillBeam( void ) { - if ( m_pBeam ) + if( m_pBeam ) { UTIL_Remove( m_pBeam ); m_pBeam = NULL; } } -void CTripmineGrenade :: MakeBeam( void ) +void CTripmineGrenade::MakeBeam( void ) { TraceResult tr; @@ -253,7 +254,7 @@ void CTripmineGrenade :: MakeBeam( void ) m_pBeam->SetBrightness( 64 ); } -void CTripmineGrenade :: BeamBreakThink( void ) +void CTripmineGrenade::BeamBreakThink( void ) { BOOL bBlowup = 0; @@ -266,28 +267,28 @@ void CTripmineGrenade :: BeamBreakThink( void ) // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); // respawn detect. - if ( !m_pBeam ) + if( !m_pBeam ) { - MakeBeam( ); - if ( tr.pHit ) + MakeBeam(); + if( tr.pHit ) m_hOwner = CBaseEntity::Instance( tr.pHit ); // reset owner too } - if (fabs( m_flBeamLength - tr.flFraction ) > 0.001) + if( fabs( m_flBeamLength - tr.flFraction ) > 0.001 ) { bBlowup = 1; } else { - if (m_hOwner == NULL) + if( m_hOwner == NULL ) bBlowup = 1; - else if (m_posOwner != m_hOwner->pev->origin) + else if( m_posOwner != m_hOwner->pev->origin ) bBlowup = 1; - else if (m_angleOwner != m_hOwner->pev->angles) + else if( m_angleOwner != m_hOwner->pev->angles ) bBlowup = 1; } - if (bBlowup) + 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 @@ -302,9 +303,9 @@ void CTripmineGrenade :: BeamBreakThink( void ) pev->nextthink = gpGlobals->time + 0.1; } -int CTripmineGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CTripmineGrenade::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if (gpGlobals->time < m_flPowerUp && flDamage < pev->health) + if( gpGlobals->time < m_flPowerUp && flDamage < pev->health ) { // disable // Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); @@ -319,8 +320,8 @@ int CTripmineGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttac void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) { pev->takedamage = DAMAGE_NO; - - if ( pevAttacker && ( pevAttacker->flags & FL_CLIENT ) ) + + if( pevAttacker && ( pevAttacker->flags & FL_CLIENT ) ) { // some client has destroyed this mine, he'll get credit for any kills pev->owner = ENT( pevAttacker ); @@ -329,14 +330,14 @@ void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) 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 + 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); + UTIL_TraceLine( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 64, dont_ignore_monsters, ENT( pev ), &tr ); Explode( &tr, DMG_BLAST ); } @@ -344,15 +345,15 @@ void CTripmineGrenade::DelayDeathThink( void ) LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ) -void CTripmine::Spawn( ) +void CTripmine::Spawn() { - Precache( ); + Precache(); m_iId = WEAPON_TRIPMINE; - SET_MODEL(ENT(pev), "models/v_tripmine.mdl"); + SET_MODEL( ENT( pev ), "models/v_tripmine.mdl" ); pev->frame = 0; pev->body = 3; pev->sequence = TRIPMINE_GROUND; - // ResetSequenceInfo( ); + // ResetSequenceInfo(); pev->framerate = 0; FallInit();// get ready to fall down @@ -360,27 +361,27 @@ void CTripmine::Spawn( ) m_iDefaultAmmo = TRIPMINE_DEFAULT_GIVE; #ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) + if( !bIsMultiplayer() ) #else - if ( !g_pGameRules->IsDeathmatch() ) + if( !g_pGameRules->IsDeathmatch() ) #endif { - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 28) ); + 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"); + 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) +int CTripmine::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "Trip Mine"; p->iMaxAmmo1 = TRIPMINE_MAX_CARRY; p->pszAmmo2 = NULL; @@ -395,7 +396,7 @@ int CTripmine::GetItemInfo(ItemInfo *p) return 1; } -BOOL CTripmine::Deploy( ) +BOOL CTripmine::Deploy() { pev->body = 0; return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); @@ -405,25 +406,25 @@ void CTripmine::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) + if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { // out of mines - m_pPlayer->pev->weapons &= ~(1<pev->weapons &= ~( 1 << WEAPON_TRIPMINE ); SetThink( &CBasePlayerItem::DestroyItem ); pev->nextthink = gpGlobals->time + 0.1; } SendWeaponAnim( TRIPMINE_HOLSTER ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); + 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) + 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 vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = gpGlobals->v_forward; TraceResult tr; @@ -438,10 +439,10 @@ void CTripmine::PrimaryAttack( void ) #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) + if( tr.flFraction < 1.0 ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if ( pEntity && !(pEntity->pev->flags & FL_CONVEYOR) ) + if( pEntity && !( pEntity->pev->flags & FL_CONVEYOR ) ) { Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); @@ -452,7 +453,7 @@ void CTripmine::PrimaryAttack( void ) // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) { // no more mines! RetireWeapon(); @@ -475,10 +476,10 @@ void CTripmine::PrimaryAttack( void ) void CTripmine::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) { SendWeaponAnim( TRIPMINE_DRAW ); } @@ -490,12 +491,12 @@ void CTripmine::WeaponIdle( void ) int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.25) + if( flRand <= 0.25 ) { iAnim = TRIPMINE_IDLE1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; } - else if (flRand <= 0.75) + else if( flRand <= 0.75 ) { iAnim = TRIPMINE_IDLE2; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 30.0; diff --git a/dlls/turret.cpp b/dlls/turret.cpp index 0da7cd54..2dce87fb 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -54,14 +54,14 @@ typedef enum class CBaseTurret : public CBaseMonster { public: - void Spawn(void); - virtual void Precache(void); + 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); + 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? @@ -75,48 +75,48 @@ public: virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; } virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; } - // void SpinDown(void); + // void SpinDown( void ); // float EXPORT SpinDownCall( void ) { return SpinDown(); } - // virtual float SpinDown(void) { return 0;} - // virtual float Retire(void) { return 0;} + // virtual float SpinDown( void ) { return 0;} + // virtual float Retire( void ) { return 0;} - void EXPORT Deploy(void); - void EXPORT Retire(void); + void EXPORT Deploy( void ); + void EXPORT Retire( void ); - void EXPORT Initialize(void); + void EXPORT Initialize( void ); - virtual void Ping(void); - virtual void EyeOn(void); - virtual void EyeOff(void); + virtual void Ping( void ); + virtual void EyeOn( void ); + virtual void EyeOff( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; // other functions - void SetTurretAnim(TURRET_ANIM anim); - int MoveTurret(void); - virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { }; + 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_eyeBrightness; - int m_iDeployHeight; - int m_iRetractHeight; + 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_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 + // enters its range Vector m_vecLastSight; float m_flLastSight; // Last time we saw a target @@ -124,12 +124,12 @@ public: int m_iSearchSpeed; // Not Used! // movement - float m_flStartYaw; - Vector m_vecCurAngles; - Vector m_vecGoalAngles; + 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 + 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[] = @@ -168,19 +168,19 @@ IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ) class CTurret : public CBaseTurret { public: - void Spawn(void); - void Precache(void); + void Spawn( void ); + void Precache( void ); // Think functions - void SpinUpCall(void); - void SpinDownCall(void); + void SpinUpCall( void ); + void SpinDownCall( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); + void Shoot( Vector &vecSrc, Vector &vecDirToEnemy ); private: int m_iStartSpin; @@ -196,10 +196,10 @@ IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ) class CMiniTurret : public CBaseTurret { public: - void Spawn( ); - void Precache(void); + void Spawn(); + void Precache( void ); // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); + void Shoot( Vector &vecSrc, Vector &vecDirToEnemy ); }; LINK_ENTITY_TO_CLASS( monster_turret, CTurret ) @@ -207,33 +207,31 @@ LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ) void CBaseTurret::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "maxsleep")) + if( FStrEq( pkvd->szKeyName, "maxsleep" ) ) { - m_flMaxWait = atof(pkvd->szValue); + m_flMaxWait = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "orientation")) + 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); + m_iOrientation = 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")) + 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 ); @@ -241,65 +239,65 @@ void CBaseTurret::KeyValue( KeyValueData *pkvd ) void CBaseTurret::Spawn() { - Precache( ); + Precache(); pev->nextthink = gpGlobals->time + 1; pev->movetype = MOVETYPE_FLY; pev->sequence = 0; - pev->frame = 0; - pev->solid = SOLID_SLIDEBOX; + pev->frame = 0; + pev->solid = SOLID_SLIDEBOX; pev->takedamage = DAMAGE_AIM; - SetBits (pev->flags, FL_MONSTER); + SetBits( pev->flags, FL_MONSTER ); SetUse( &CBaseTurret::TurretUse ); - if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) + if( ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) + && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE ) ) { m_iAutoStart = TRUE; } - ResetSequenceInfo( ); + ResetSequenceInfo(); SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); m_flFieldOfView = VIEW_FIELD_FULL; // m_flSightRange = TURRET_RANGE; } -void CBaseTurret::Precache( ) +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"); + 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; +{ + 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; + m_flMaxSpin = TURRET_MAXSPIN; + pev->view_ofs.z = 12.75; - CBaseTurret::Spawn( ); + CBaseTurret::Spawn(); m_iRetractHeight = 16; m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); + m_iMinPitch = -15; + UTIL_SetSize( pev, Vector( -32, -32, -m_iRetractHeight ), Vector( 32, 32, m_iRetractHeight ) ); - SetThink( &CBaseTurret::Initialize); + SetThink( &CBaseTurret::Initialize ); m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); @@ -311,40 +309,40 @@ void CTurret::Spawn() void CTurret::Precache() { - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/turret.mdl"); - PRECACHE_MODEL (TURRET_GLOW_SPRITE); + 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 ); + 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( ); + CBaseTurret::Spawn(); m_iRetractHeight = 16; m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); + m_iMinPitch = -15; + UTIL_SetSize( pev, Vector( -16, -16, -m_iRetractHeight ), Vector( 16, 16, m_iRetractHeight ) ); - SetThink( &CBaseTurret::Initialize); + SetThink( &CBaseTurret::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"); + 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) +void CBaseTurret::Initialize( void ) { m_iOn = 0; m_fBeserk = 0; @@ -353,82 +351,84 @@ void CBaseTurret::Initialize(void) SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); - if (m_iBaseTurnRate == 0) m_iBaseTurnRate = TURRET_TURNRATE; - if (m_flMaxWait == 0) m_flMaxWait = TURRET_MAXWAIT; + 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) + 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) + if( pev->angles.y > 360 ) pev->angles.y = pev->angles.y - 360; } m_vecGoalAngles.x = 0; - if (m_iAutoStart) + if( m_iAutoStart ) { m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &CBaseTurret::AutoSearchThink); + SetThink( &CBaseTurret::AutoSearchThink ); pev->nextthink = gpGlobals->time + .1; } else - SetThink( &CBaseEntity::SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing ); } void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_iOn ) ) + if( !ShouldToggle( useType, m_iOn ) ) return; - if (m_iOn) + 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); + 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 ) + if( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) { m_iAutoStart = TRUE; } - SetThink( &CBaseTurret::Deploy); + SetThink( &CBaseTurret::Deploy ); } } void CBaseTurret::Ping( void ) { // make the pinging noise every second while searching - if (m_flPingTime == 0) + if( m_flPingTime == 0 ) m_flPingTime = gpGlobals->time + 1; - else if (m_flPingTime <= gpGlobals->time) + 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( ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "turret/tu_ping.wav", 1, ATTN_NORM ); + EyeOn(); } - else if (m_eyeBrightness > 0) + else if( m_eyeBrightness > 0 ) { - EyeOff( ); + EyeOff(); } } -void CBaseTurret::EyeOn( ) +void CBaseTurret::EyeOn() { - if (m_pEyeGlow) + if( m_pEyeGlow ) { - if (m_eyeBrightness != 255) + if( m_eyeBrightness != 255 ) { m_eyeBrightness = 255; } @@ -436,11 +436,11 @@ void CBaseTurret::EyeOn( ) } } -void CBaseTurret::EyeOff( ) +void CBaseTurret::EyeOff() { - if (m_pEyeGlow) + if( m_pEyeGlow ) { - if (m_eyeBrightness > 0) + if( m_eyeBrightness > 0 ) { m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); m_pEyeGlow->SetBrightness( m_eyeBrightness ); @@ -448,36 +448,36 @@ void CBaseTurret::EyeOff( ) } } -void CBaseTurret::ActiveThink(void) +void CBaseTurret::ActiveThink( void ) { int fAttack = 0; Vector vecDirToEnemy; pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); + StudioFrameAdvance(); - if ((!m_iOn) || (m_hEnemy == NULL)) + if( ( !m_iOn ) || ( m_hEnemy == NULL ) ) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &CBaseTurret::SearchThink); + SetThink( &CBaseTurret::SearchThink ); return; } // if it's dead, look for something new - if ( !m_hEnemy->IsAlive() ) + if( !m_hEnemy->IsAlive() ) { - if (!m_flLastSight) + if( !m_flLastSight ) { m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout } else { - if (gpGlobals->time > m_flLastSight) - { + if( gpGlobals->time > m_flLastSight ) + { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &CBaseTurret::SearchThink); + SetThink( &CBaseTurret::SearchThink ); return; } } @@ -487,26 +487,26 @@ void CBaseTurret::ActiveThink(void) Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); // Look for our current enemy - int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy ); + 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); + Vector vec = UTIL_VecToAngles( vecMidEnemy - vecMid ); // Current enmey is not visible. - if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE)) + if( !fEnemyVisible || ( flDistToEnemy > TURRET_RANGE ) ) { - if (!m_flLastSight) + if( !m_flLastSight ) m_flLastSight = gpGlobals->time + 0.5; else { // Should we look for a new target? - if (gpGlobals->time > m_flLastSight) + if( gpGlobals->time > m_flLastSight ) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink( &CBaseTurret::SearchThink); + SetThink( &CBaseTurret::SearchThink ); return; } } @@ -517,7 +517,7 @@ void CBaseTurret::ActiveThink(void) m_vecLastSight = vecMidEnemy; } - UTIL_MakeAimVectors(m_vecCurAngles); + UTIL_MakeAimVectors(m_vecCurAngles); /* ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", @@ -529,70 +529,70 @@ void CBaseTurret::ActiveThink(void) vecLOS = vecLOS.Normalize(); // Is the Gun looking at the target - if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop + 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))) + if( m_iSpin && ( ( fAttack ) || ( m_fBeserk ) ) ) { Vector vecSrc, vecAng; GetAttachment( 0, vecSrc, vecAng ); - SetTurretAnim(TURRET_ANIM_FIRE); - Shoot(vecSrc, gpGlobals->v_forward ); + SetTurretAnim( TURRET_ANIM_FIRE ); + Shoot( vecSrc, gpGlobals->v_forward ); } else { - SetTurretAnim(TURRET_ANIM_SPIN); + SetTurretAnim( TURRET_ANIM_SPIN ); } //move the gun - if (m_fBeserk) + if( m_fBeserk ) { - if (RANDOM_LONG(0,9) == 0) + 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 + 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) + else if( fEnemyVisible ) { - if (vec.y > 360) + if( vec.y > 360 ) vec.y -= 360; - if (vec.y < 0) + if( vec.y < 0 ) vec.y += 360; - //ALERT(at_console, "[%.2f]", vec.x); + //ALERT( at_console, "[%.2f]", vec.x ); - if (vec.x < -180) + if( vec.x < -180 ) vec.x += 360; - if (vec.x > 180) + 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( m_iOrientation == 0 ) { - if (vec.x > 90) + if( vec.x > 90 ) vec.x = 90; - else if (vec.x < m_iMinPitch) + else if( vec.x < m_iMinPitch ) vec.x = m_iMinPitch; } else { - if (vec.x < -90) + if( vec.x < -90 ) vec.x = -90; - else if (vec.x > -m_iMinPitch) + else if( vec.x > -m_iMinPitch ) vec.x = -m_iMinPitch; } - // ALERT(at_console, "->[%.2f]\n", vec.x); + // ALERT( at_console, "->[%.2f]\n", vec.x ); m_vecGoalAngles.y = vec.y; m_vecGoalAngles.x = vec.x; @@ -602,48 +602,54 @@ void CBaseTurret::ActiveThink(void) MoveTurret(); } -void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) +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); + 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) +void CMiniTurret::Shoot( Vector &vecSrc, Vector &vecDirToEnemy ) { FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_9MM, 1 ); - switch(RANDOM_LONG(0,2)) + 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; + 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) +void CBaseTurret::Deploy( void ) { pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); + StudioFrameAdvance(); - if (pev->sequence != TURRET_ANIM_DEPLOY) + 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); + 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) + if( m_fSequenceFinished ) { pev->maxs.z = m_iDeployHeight; pev->mins.z = -m_iDeployHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); + UTIL_SetSize( pev, pev->mins, pev->maxs ); m_vecCurAngles.x = 0; - if (m_iOrientation == 1) + if( m_iOrientation == 1 ) { m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); } @@ -652,15 +658,15 @@ void CBaseTurret::Deploy(void) m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); } - SetTurretAnim(TURRET_ANIM_SPIN); + SetTurretAnim( TURRET_ANIM_SPIN ); pev->framerate = 0; - SetThink( &CBaseTurret::SearchThink); + SetThink( &CBaseTurret::SearchThink ); } m_flLastSight = gpGlobals->time + m_flMaxWait; } -void CBaseTurret::Retire(void) +void CBaseTurret::Retire( void ) { // make the turret level m_vecGoalAngles.x = 0; @@ -668,69 +674,69 @@ void CBaseTurret::Retire(void) pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); + StudioFrameAdvance(); - EyeOff( ); + EyeOff(); - if (!MoveTurret()) + if( !MoveTurret() ) { - if (m_iSpin) + if( m_iSpin ) { SpinDownCall(); } - else if (pev->sequence != TURRET_ANIM_RETIRE) + 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); + 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) - { + else if( m_fSequenceFinished ) + { m_iOn = 0; m_flLastSight = 0; - SetTurretAnim(TURRET_ANIM_NONE); + SetTurretAnim( TURRET_ANIM_NONE ); pev->maxs.z = m_iRetractHeight; pev->mins.z = -m_iRetractHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - if (m_iAutoStart) + UTIL_SetSize( pev, pev->mins, pev->maxs ); + if( m_iAutoStart ) { - SetThink( &CBaseTurret::AutoSearchThink); + SetThink( &CBaseTurret::AutoSearchThink ); pev->nextthink = gpGlobals->time + .1; } else - SetThink( &CBaseEntity::SUB_DoNothing); + SetThink( &CBaseEntity::SUB_DoNothing ); } } else { - SetTurretAnim(TURRET_ANIM_SPIN); + SetTurretAnim( TURRET_ANIM_SPIN ); } } -void CTurret::SpinUpCall(void) +void CTurret::SpinUpCall( void ) { - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; // Are we already spun up? If not start the two stage process. - if (!m_iSpin) + if( !m_iSpin ) { SetTurretAnim( TURRET_ANIM_SPIN ); // for the first pass, spin up the the barrel - if (!m_iStartSpin) + 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); + 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) + 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( &CBaseTurret::ActiveThink); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM ); + SetThink( &CBaseTurret::ActiveThink ); m_iStartSpin = 0; m_iSpin = 1; } @@ -740,24 +746,24 @@ void CTurret::SpinUpCall(void) } } - if (m_iSpin) + if( m_iSpin ) { - SetThink( &CBaseTurret::ActiveThink); + SetThink( &CBaseTurret::ActiveThink ); } } -void CTurret::SpinDownCall(void) +void CTurret::SpinDownCall( void ) { - if (m_iSpin) + if( m_iSpin ) { SetTurretAnim( TURRET_ANIM_SPIN ); - if (pev->framerate == 1.0) + 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); + 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) + if( pev->framerate <= 0 ) { pev->framerate = 0; m_iSpin = 0; @@ -765,15 +771,15 @@ void CTurret::SpinDownCall(void) } } -void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) +void CBaseTurret::SetTurretAnim( TURRET_ANIM anim ) { - if (pev->sequence != anim) + if( pev->sequence != anim ) { - switch(anim) + switch( anim ) { case TURRET_ANIM_FIRE: case TURRET_ANIM_SPIN: - if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) + if( pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN ) { pev->frame = 0; } @@ -784,21 +790,21 @@ void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) } pev->sequence = anim; - ResetSequenceInfo( ); + ResetSequenceInfo(); - switch(anim) + switch( anim ) { case TURRET_ANIM_RETIRE: - pev->frame = 255; - pev->framerate = -1.0; + pev->frame = 255; + pev->framerate = -1.0; break; case TURRET_ANIM_DIE: - pev->framerate = 1.0; + pev->framerate = 1.0; break; default: break; } - //ALERT(at_console, "Turret anim #%d\n", anim); + //ALERT( at_console, "Turret anim #%d\n", anim ); } } @@ -807,58 +813,58 @@ void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) // After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will // retact. // -void CBaseTurret::SearchThink(void) +void CBaseTurret::SearchThink( void ) { // ensure rethink - SetTurretAnim(TURRET_ANIM_SPIN); - StudioFrameAdvance( ); + SetTurretAnim( TURRET_ANIM_SPIN ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if (m_flSpinUpTime == 0 && m_flMaxSpin) + if( m_flSpinUpTime == 0 && m_flMaxSpin ) m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; - Ping( ); + Ping(); // If we have a target and we're still healthy - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { - if (!m_hEnemy->IsAlive() ) + if( !m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { - Look(TURRET_RANGE); + Look( TURRET_RANGE ); m_hEnemy = BestVisibleEnemy(); } // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink( &CBaseTurret::ActiveThink); + SetThink( &CBaseTurret::ActiveThink ); } else { // Are we out of time, do we need to retract? - if (gpGlobals->time > m_flLastSight) + if( gpGlobals->time > m_flLastSight ) { //Before we retrace, make sure that we are spun down. m_flLastSight = 0; m_flSpinUpTime = 0; - SetThink( &CBaseTurret::Retire); + SetThink( &CBaseTurret::Retire ); } // should we stop the spin? - else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) + 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 = ( m_vecGoalAngles.y + 0.1 * m_fTurnRate ); + if( m_vecGoalAngles.y >= 360 ) m_vecGoalAngles.y -= 360; MoveTurret(); } @@ -868,70 +874,68 @@ void CBaseTurret::SearchThink(void) // This think function will deploy the turret when something comes into range. This is for // automatically activated turrets. // -void CBaseTurret::AutoSearchThink(void) +void CBaseTurret::AutoSearchThink( void ) { // ensure rethink - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.3; // If we have a target and we're still healthy - - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { - if (!m_hEnemy->IsAlive() ) + if( !m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target - - if (m_hEnemy == NULL) + if( m_hEnemy == NULL ) { Look( TURRET_RANGE ); m_hEnemy = BestVisibleEnemy(); } - if (m_hEnemy != NULL) + if( m_hEnemy != NULL ) { - SetThink( &CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); + SetThink( &CBaseTurret::Deploy ); + EMIT_SOUND( ENT( pev ), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM ); } } -void CBaseTurret :: TurretDeath( void ) +void CBaseTurret::TurretDeath( void ) { BOOL iActive = FALSE; - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if (pev->deadflag != DEAD_DEAD) + if( pev->deadflag != DEAD_DEAD ) { pev->deadflag = DEAD_DEAD; - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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); + 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( 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100 ); - if (m_iOrientation == 0) + if( m_iOrientation == 0 ) m_vecGoalAngles.x = -15; else m_vecGoalAngles.x = -90; - SetTurretAnim(TURRET_ANIM_DIE); + SetTurretAnim( TURRET_ANIM_DIE ); - EyeOn( ); + EyeOn(); } - EyeOff( ); + EyeOff(); - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) + if( pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time ) { // lots of smoke MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -941,14 +945,14 @@ void CBaseTurret :: TurretDeath( void ) WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 25 ); // scale * 10 - WRITE_BYTE( 10 - m_iOrientation * 5); // framerate + WRITE_BYTE( 10 - m_iOrientation * 5 ); // framerate MESSAGE_END(); } - if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) + 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) + 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 ) ); @@ -956,119 +960,119 @@ void CBaseTurret :: TurretDeath( void ) UTIL_Sparks( vecSrc ); } - if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) + 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) +void CBaseTurret::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if ( ptr->iHitgroup == 10 ) + if( ptr->iHitgroup == 10 ) { // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) + if( pev->dmgtime != gpGlobals->time || (RANDOM_LONG( 0, 10 ) < 1 ) ) { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); + 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 ) + 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) +int CBaseTurret::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( !pev->takedamage ) + if( !pev->takedamage ) return 0; - if (!m_iOn) + if( !m_iOn ) flDamage /= 10.0; pev->health -= flDamage; - if (pev->health <= 0) + 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??? + ClearBits( pev->flags, FL_MONSTER ); // why are they set in the first place??? SetUse( NULL ); - SetThink( &CBaseTurret::TurretDeath); + 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( pev->health <= 10 ) { - if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) + if( m_iOn && ( 1 || RANDOM_LONG( 0, 0x7FFF ) > 800 ) ) { m_fBeserk = 1; - SetThink( &CBaseTurret::SearchThink); + SetThink( &CBaseTurret::SearchThink ); } } return 1; } -int CBaseTurret::MoveTurret(void) +int CBaseTurret::MoveTurret( void ) { int state = 0; // any x movement? - if (m_vecCurAngles.x != m_vecGoalAngles.x) + 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( flDir == 1 ) { - if (m_vecCurAngles.x > m_vecGoalAngles.x) + if( m_vecCurAngles.x > m_vecGoalAngles.x ) m_vecCurAngles.x = m_vecGoalAngles.x; } else { - if (m_vecCurAngles.x < m_vecGoalAngles.x) + if( m_vecCurAngles.x < m_vecGoalAngles.x ) m_vecCurAngles.x = m_vecGoalAngles.x; } - if (m_iOrientation == 0) - SetBoneController(1, -m_vecCurAngles.x); + if( m_iOrientation == 0 ) + SetBoneController( 1, -m_vecCurAngles.x ); else - SetBoneController(1, m_vecCurAngles.x); + SetBoneController( 1, m_vecCurAngles.x ); state = 1; } - if (m_vecCurAngles.y != m_vecGoalAngles.y) + 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) + float flDist = fabs( m_vecGoalAngles.y - m_vecCurAngles.y ); + + if( flDist > 180 ) { flDist = 360 - flDist; flDir = -flDir; } - if (flDist > 30) + if( flDist > 30 ) { - if (m_fTurnRate < m_iBaseTurnRate * 10) + if( m_fTurnRate < m_iBaseTurnRate * 10 ) { m_fTurnRate += m_iBaseTurnRate; } } - else if (m_fTurnRate > 45) + else if( m_fTurnRate > 45 ) { m_fTurnRate -= m_iBaseTurnRate; } @@ -1079,36 +1083,36 @@ int CBaseTurret::MoveTurret(void) m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; - if (m_vecCurAngles.y < 0) + if( m_vecCurAngles.y < 0 ) m_vecCurAngles.y += 360; - else if (m_vecCurAngles.y >= 360) + else if( m_vecCurAngles.y >= 360 ) m_vecCurAngles.y -= 360; - if (flDist < (0.05 * m_iBaseTurnRate)) + 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 ); + //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 ); + SetBoneController( 0, pev->angles.y - 180 - m_vecCurAngles.y ); state = 1; } - if (!state) + 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); + //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 ) +int CBaseTurret::Classify( void ) { - if (m_iOn || m_iAutoStart) + if( m_iOn || m_iAutoStart ) return CLASS_MACHINE; return CLASS_NONE; } @@ -1119,11 +1123,11 @@ int CBaseTurret::Classify ( void ) class CSentry : public CBaseTurret { public: - void Spawn( ); - void Precache(void); + 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 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 ); }; @@ -1132,50 +1136,56 @@ LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ) void CSentry::Precache() { - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/sentry.mdl"); + 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; + 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; + 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)); + m_iMinPitch = -60; + UTIL_SetSize( pev, Vector( -16, -16, -m_iRetractHeight ), Vector( 16, 16, m_iRetractHeight ) ); - SetTouch( &CSentry::SentryTouch); - SetThink( &CBaseTurret::Initialize); + SetTouch( &CSentry::SentryTouch ); + SetThink( &CBaseTurret::Initialize ); pev->nextthink = gpGlobals->time + 0.3; } -void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) +void CSentry::Shoot( Vector &vecSrc, Vector &vecDirToEnemy ) { FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_MP5, 1 ); - switch(RANDOM_LONG(0,2)) + 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; + 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) +int CSentry::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( !pev->takedamage ) + if( !pev->takedamage ) return 0; - if (!m_iOn) + if( !m_iOn ) { SetThink( &CBaseTurret::Deploy ); SetUse( NULL ); @@ -1183,16 +1193,16 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f } pev->health -= flDamage; - if (pev->health <= 0) + 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??? + ClearBits( pev->flags, FL_MONSTER ); // why are they set in the first place??? SetUse( NULL ); - SetThink( &CSentry::SentryDeath); + SetThink( &CSentry::SentryDeath ); SUB_UseTargets( this, USE_ON, 0 ); // wake up others pev->nextthink = gpGlobals->time + 0.1; @@ -1204,51 +1214,51 @@ int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f void CSentry::SentryTouch( CBaseEntity *pOther ) { - if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) + if( pOther && ( pOther->IsPlayer() || ( pOther->pev->flags & FL_MONSTER ) ) ) { - TakeDamage(pOther->pev, pOther->pev, 0, 0 ); + TakeDamage( pOther->pev, pOther->pev, 0, 0 ); } } -void CSentry :: SentryDeath( void ) +void CSentry::SentryDeath( void ) { BOOL iActive = FALSE; - StudioFrameAdvance( ); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; - if (pev->deadflag != DEAD_DEAD) + if( pev->deadflag != DEAD_DEAD ) { pev->deadflag = DEAD_DEAD; - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); + 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); + 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( 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); + 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); + SetTurretAnim( TURRET_ANIM_DIE ); pev->solid = SOLID_NOT; pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); - EyeOn( ); + EyeOn(); } - EyeOff( ); + EyeOff(); Vector vecSrc, vecAng; GetAttachment( 1, vecSrc, vecAng ); - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) + if( pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time ) { // lots of smoke MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -1262,12 +1272,12 @@ void CSentry :: SentryDeath( void ) MESSAGE_END(); } - if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) + if( pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time ) { UTIL_Sparks( vecSrc ); } - if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) + if( m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time ) { pev->framerate = 0; SetThink( NULL ); diff --git a/dlls/util.cpp b/dlls/util.cpp index 223f973b..825e5241 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -42,7 +42,7 @@ float UTIL_WeaponTimeBase( void ) static unsigned int glSeed = 0; -unsigned int seed_table[ 256 ] = +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, @@ -65,14 +65,14 @@ unsigned int seed_table[ 256 ] = unsigned int U_Random( void ) { glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - + glSeed += seed_table[glSeed & 0xff]; + return ( ++glSeed & 0x0fffffff ); } void U_Srand( unsigned int seed ) { - glSeed = seed_table[ seed & 0xff ]; + glSeed = seed_table[seed & 0xff]; } /* @@ -87,7 +87,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) U_Srand( (int)seed + low + high ); range = high - low + 1; - if ( !(range - 1) ) + if( !( range - 1 ) ) { return low; } @@ -100,7 +100,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) offset = rnum % range; - return (low + offset); + return ( low + offset ); } } @@ -119,7 +119,7 @@ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) U_Random(); range = high - low; - if ( !range ) + if( !range ) { return low; } @@ -132,7 +132,7 @@ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) offset = (float)tensixrand / 65536.0; - return (low + offset * range ); + return ( low + offset * range ); } } @@ -142,13 +142,13 @@ void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, // 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); + 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 ) + if( pev->velocity.Length() > 0 ) { travelTime = vecTravel.Length() / pev->velocity.Length(); } @@ -162,16 +162,16 @@ int g_groupop = 0; // Normal overrides void UTIL_SetGroupTrace( int groupmask, int op ) { - g_groupmask = groupmask; - g_groupop = op; + g_groupmask = groupmask; + g_groupop = op; ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); } void UTIL_UnsetGroupTrace( void ) { - g_groupmask = 0; - g_groupop = 0; + g_groupmask = 0; + g_groupop = 0; ENGINE_SETGROUPMASK( 0, 0 ); } @@ -179,19 +179,19 @@ void UTIL_UnsetGroupTrace( void ) // 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; + m_oldgroupmask = g_groupmask; + m_oldgroupop = g_groupop; - g_groupmask = groupmask; - g_groupop = op; + 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; + g_groupmask = m_oldgroupmask; + g_groupop = m_oldgroupop; ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); } @@ -307,33 +307,33 @@ TYPEDESCRIPTION gEntvarsDescription[] = DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), }; -#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) +#define ENTVARS_COUNT ( sizeof(gEntvarsDescription) / sizeof(gEntvarsDescription[0]) ) #ifdef DEBUG edict_t *DBG_EntOfVars( const entvars_t *pev ) { - if (pev->pContainingEntity != NULL) + 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; + 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; } void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage ) { - if (fExpr) + if( fExpr ) return; char szOut[512]; - if (szMessage != NULL) - sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); + 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); + sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine ); - ALERT(at_console, szOut); + ALERT( at_console, szOut ); } #endif // DEBUG @@ -345,17 +345,18 @@ BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeap // ripped this out of the engine float UTIL_AngleMod( float a ) { - /*if (a < 0) + /*if( a < 0 ) { - a = a + 360 * ((int)(a / 360) + 1); + a = a + 360 * ( (int)( a / 360 ) + 1 ); } - else if (a >= 360) + else if( a >= 360 ) { - a = a - 360 * ((int)(a / 360)); + a = a - 360 * ( (int)( a / 360 ) ); }*/ - // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + // a = ( 360.0 / 65536 ) * ( (int)( a * ( 65536 / 360.0 ) ) & 65535 ); a = fmod( a, 360.0f ); - if( a < 0 ) a += 360; + if( a < 0 ) + a += 360; return a; } @@ -364,14 +365,14 @@ float UTIL_AngleDiff( float destAngle, float srcAngle ) float delta; delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) + if( destAngle > srcAngle ) { - if ( delta >= 180 ) + if( delta >= 180 ) delta -= 360; } else { - if ( delta <= -180 ) + if( delta <= -180 ) delta += 360; } return delta; @@ -380,54 +381,54 @@ float UTIL_AngleDiff( float destAngle, float srcAngle ) Vector UTIL_VecToAngles( const Vector &vec ) { float rgflVecOut[3]; - VEC_TO_ANGLES(vec, rgflVecOut); - return Vector(rgflVecOut); + 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 ); + 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 ); + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); CBaseEntity *pEntity; - int count; + int count; count = 0; - if ( !pEdict ) + if( !pEdict ) return count; - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) { - if ( pEdict->free ) // Not in use + if( pEdict->free ) // Not in use continue; - if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? + 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 ) + 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; - pList[ count ] = pEntity; + pEntity = CBaseEntity::Instance( pEdict ); + if( !pEntity ) + continue; + + pList[count] = pEntity; count++; - if ( count >= listMax ) + if( count >= listMax ) return count; } @@ -436,58 +437,58 @@ int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, co int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) { - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); CBaseEntity *pEntity; - int count; + int count; float distance, delta; count = 0; float radiusSquared = radius * radius; - if ( !pEdict ) + if( !pEdict ) return count; - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) + for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) { - if ( pEdict->free ) // Not in use + if( pEdict->free ) // Not in use continue; - if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? + 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 = center.x - pEdict->v.origin.x;//( pEdict->v.absmin.x + pEdict->v.absmax.x ) * 0.5; delta *= delta; - if ( delta > radiusSquared ) + 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 = center.y - pEdict->v.origin.y;//( pEdict->v.absmin.y + pEdict->v.absmax.y )*0.5; delta *= delta; distance += delta; - if ( distance > radiusSquared ) + if( distance > radiusSquared ) continue; // Now Z - delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; + delta = center.z - ( pEdict->v.absmin.z + pEdict->v.absmax.z ) * 0.5; delta *= delta; distance += delta; - if ( distance > radiusSquared ) + if( distance > radiusSquared ) continue; - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) + pEntity = CBaseEntity::Instance( pEdict ); + if( !pEntity ) continue; - pList[ count ] = pEntity; + pList[count] = pEntity; count++; - if ( count >= listMax ) + if( count >= listMax ) return count; } @@ -498,15 +499,15 @@ CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &v { edict_t *pentEntity; - if (pStartEntity) + if( pStartEntity ) pentEntity = pStartEntity->edict(); else pentEntity = NULL; - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); + pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius ); - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); + if( !FNullEnt( pentEntity ) ) + return CBaseEntity::Instance( pentEntity ); return NULL; } @@ -514,15 +515,15 @@ CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szK { edict_t *pentEntity; - if (pStartEntity) + if( pStartEntity ) pentEntity = pStartEntity->edict(); else pentEntity = NULL; pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); + if( !FNullEnt( pentEntity ) ) + return CBaseEntity::Instance( pentEntity ); return NULL; } @@ -541,16 +542,16 @@ CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, flo CBaseEntity *pEntity = NULL; pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); - if (pEntity) + if( pEntity ) return pEntity; CBaseEntity *pSearch = NULL; float flMaxDist2 = flRadius * flRadius; - while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) + while( ( pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever ) ) != NULL ) { - float flDist2 = (pSearch->pev->origin - vecSrc).Length(); + float flDist2 = ( pSearch->pev->origin - vecSrc ).Length(); flDist2 = flDist2 * flDist2; - if (flMaxDist2 > flDist2) + if( flMaxDist2 > flDist2 ) { pEntity = pSearch; flMaxDist2 = flDist2; @@ -562,14 +563,14 @@ CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, flo // 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 *UTIL_PlayerByIndex( int playerIndex ) { CBaseEntity *pPlayer = NULL; - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) + if( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) { edict_t *pPlayerEdict = INDEXENT( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) + if( pPlayerEdict && !pPlayerEdict->free ) { pPlayer = CBaseEntity::Instance( pPlayerEdict ); } @@ -588,36 +589,36 @@ void UTIL_MakeAimVectors( const Vector &vecAngles ) float rgflVec[3]; vecAngles.CopyToArray(rgflVec); rgflVec[0] = -rgflVec[0]; - MAKE_VECTORS(rgflVec); + MAKE_VECTORS( rgflVec ); } -#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) +#define SWAP( a, b, temp ) ( ( temp ) = ( a ), ( a ) = ( b ), ( b ) = ( temp ) ) void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) { - MAKE_VECTORS(vec); + 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); + 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); + vecOrigin.CopyToArray( rgfl ); - if (samp && *samp == '!') + if( samp && *samp == '!' ) { char name[32]; - if (SENTENCEG_Lookup(samp, name) >= 0) - EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); + 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); + EMIT_AMBIENT_SOUND( entity, rgfl, samp, vol, attenuation, fFlags, pitch ); } static unsigned short FixedUnsigned16( float value, float scale ) @@ -625,9 +626,9 @@ static unsigned short FixedUnsigned16( float value, float scale ) int output; output = value * scale; - if ( output < 0 ) + if( output < 0 ) output = 0; - if ( output > 0xFFFF ) + if( output > 0xFFFF ) output = 0xFFFF; return (unsigned short)output; @@ -639,10 +640,10 @@ static short FixedSigned16( float value, float scale ) output = value * scale; - if ( output > 32767 ) + if( output > 32767 ) output = 32767; - if ( output < -32768 ) + if( output < -32768 ) output = -32768; return (short)output; @@ -655,23 +656,23 @@ static short FixedSigned16( float value, float scale ) // UNDONE: Affect user controls? void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) { - int i; + int i; float localAmplitude; ScreenShake shake; - shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed - shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed + 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++ ) + 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 + if( !pPlayer || !( pPlayer->pev->flags & FL_ONGROUND ) ) // Don't shake if not onground continue; localAmplitude = 0; - if ( radius <= 0 ) + if( radius <= 0 ) localAmplitude = amplitude; else { @@ -679,19 +680,17 @@ void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, f float distance = delta.Length(); // Had to get rid of this falloff - it didn't work well - if ( distance < radius ) + if( distance < radius ) localAmplitude = amplitude;//radius - distance; } - if ( localAmplitude ) + if( localAmplitude ) { - shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed + 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(); } } @@ -704,8 +703,8 @@ void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency 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.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; @@ -715,11 +714,10 @@ void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) { - if ( !pEntity || !pEntity->IsNetClient() ) + 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) @@ -727,18 +725,17 @@ void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) 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; + int i; + ScreenFade fade; UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - for ( i = 1; i <= gpGlobals->maxClients; i++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); @@ -748,7 +745,7 @@ void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, in void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) { - ScreenFade fade; + ScreenFade fade; UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); UTIL_ScreenFadeWrite( fade, pEntity ); @@ -756,15 +753,15 @@ void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) { - if ( !pEntity || !pEntity->IsNetClient() ) + 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_SHORT( FixedSigned16( textparms.x, 1 << 13 ) ); + WRITE_SHORT( FixedSigned16( textparms.y, 1 << 13 ) ); WRITE_BYTE( textparms.effect ); WRITE_BYTE( textparms.r1 ); @@ -777,14 +774,14 @@ void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, con 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 ) ); + 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 ) + if( textparms.effect == 2 ) + WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1 << 8 ) ); + + if( strlen( pMessage ) < 512 ) { WRITE_STRING( pMessage ); } @@ -800,12 +797,12 @@ void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, con void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) { - int i; + int i; - for ( i = 1; i <= gpGlobals->maxClients; i++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) + if( pPlayer ) UTIL_HudMessage( pPlayer, textparms, pMessage ); } } @@ -817,15 +814,14 @@ void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 WRITE_BYTE( msg_dest ); WRITE_STRING( msg_name ); - if ( param1 ) + if( param1 ) WRITE_STRING( param1 ); - if ( param2 ) + if( param2 ) WRITE_STRING( param2 ); - if ( param3 ) + if( param3 ) WRITE_STRING( param3 ); - if ( param4 ) + if( param4 ) WRITE_STRING( param4 ); - MESSAGE_END(); } @@ -835,21 +831,20 @@ void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const c WRITE_BYTE( msg_dest ); WRITE_STRING( msg_name ); - if ( param1 ) + if( param1 ) WRITE_STRING( param1 ); - if ( param2 ) + if( param2 ) WRITE_STRING( param2 ); - if ( param3 ) + if( param3 ) WRITE_STRING( param3 ); - if ( param4 ) + if( param4 ) WRITE_STRING( param4 ); - MESSAGE_END(); } void UTIL_SayText( const char *pText, CBaseEntity *pEntity ) { - if ( !pEntity->IsNetClient() ) + if( !pEntity->IsNetClient() ) return; MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pEntity->edict() ); @@ -896,7 +891,7 @@ char *UTIL_dtos4( int d ) void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity ) { - if ( !pEntity || !pEntity->IsNetClient() ) + if( !pEntity || !pEntity->IsNetClient() ) return; MESSAGE_BEGIN( MSG_ONE, gmsgHudText, NULL, pEntity->edict() ); @@ -906,13 +901,13 @@ void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity ) void UTIL_ShowMessageAll( const char *pString ) { - int i; + int i; // loop through all players - for ( i = 1; i <= gpGlobals->maxClients; i++ ) + for( i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) + if( pPlayer ) UTIL_ShowMessage( pString, pPlayer ); } } @@ -920,17 +915,17 @@ void UTIL_ShowMessageAll( const char *pString ) // 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 ); + 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 ); + 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 ); + 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 ) @@ -944,8 +939,8 @@ TraceResult UTIL_GetGlobalTrace( ) tr.fAllSolid = gpGlobals->trace_allsolid; tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = gpGlobals->trace_inwater; + tr.fInOpen = gpGlobals->trace_inopen; + tr.fInWater = gpGlobals->trace_inwater; tr.flFraction = gpGlobals->trace_fraction; tr.flPlaneDist = gpGlobals->trace_plane_dist; tr.pHit = gpGlobals->trace_ent; @@ -957,18 +952,18 @@ TraceResult UTIL_GetGlobalTrace( ) void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) { - SET_SIZE( ENT(pev), vecMin, vecMax ); + SET_SIZE( ENT( pev ), vecMin, vecMax ); } float UTIL_VecToYaw( const Vector &vec ) { - return VEC_TO_YAW(vec); + return VEC_TO_YAW( vec ); } void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) { - edict_t *ent = ENT(pev); - if ( ent ) + edict_t *ent = ENT( pev ); + if( ent ) SET_ORIGIN( ent, vecOrigin ); } @@ -981,9 +976,9 @@ float UTIL_Approach( float target, float value, float speed ) { float delta = target - value; - if ( delta > speed ) + if( delta > speed ) value += speed; - else if ( delta < -speed ) + else if( delta < -speed ) value -= speed; else value = target; @@ -999,17 +994,17 @@ float UTIL_ApproachAngle( float target, float value, float speed ) float delta = target - value; // Speed is assumed to be positive - if ( speed < 0 ) + if( speed < 0 ) speed = -speed; - if ( delta < -180 ) + if( delta < -180 ) delta += 360; - else if ( delta > 180 ) + else if( delta > 180 ) delta -= 360; - if ( delta > speed ) + if( delta > speed ) value += speed; - else if ( delta < -speed ) + else if( delta < -speed ) value -= speed; else value = target; @@ -1021,9 +1016,9 @@ float UTIL_AngleDistance( float next, float cur ) { float delta = next - cur; - if ( delta < -180 ) + if( delta < -180 ) delta += 360; - else if ( delta > 180 ) + else if( delta > 180 ) delta -= 360; return delta; @@ -1038,39 +1033,39 @@ float UTIL_SplineFraction( float value, float scale ) return 3 * valueSquared - 2 * valueSquared * value; } -char* UTIL_VarArgs( char *format, ... ) +char *UTIL_VarArgs( char *format, ... ) { - va_list argptr; - static char string[1024]; + va_list argptr; + static char string[1024]; - va_start (argptr, format); - vsprintf (string, format,argptr); - va_end (argptr); + va_start( argptr, format ); + vsprintf( string, format, argptr ); + va_end( argptr ); - return string; + return string; } Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) { Vector tmp; - GET_AIM_VECTOR(pent, flSpeed, tmp); + GET_AIM_VECTOR( pent, flSpeed, tmp ); return tmp; } int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) { - if (sMaster) + if( sMaster ) { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); + edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( sMaster ) ); - if ( !FNullEnt(pentTarget) ) + if( !FNullEnt( pentTarget ) ) { - CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); - if ( pMaster && (pMaster->ObjectCaps() & FCAP_MASTER) ) + 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"); + ALERT( at_console, "Master was null or not a master!\n" ); } // if this isn't a master entity, just say yes. @@ -1079,16 +1074,16 @@ int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) BOOL UTIL_ShouldShowBlood( int color ) { - if ( color != DONT_BLEED ) + if( color != DONT_BLEED ) { - if ( color == BLOOD_COLOR_RED ) + if( color == BLOOD_COLOR_RED ) { - if ( CVAR_GET_FLOAT("violence_hblood") != 0 ) + if( CVAR_GET_FLOAT( "violence_hblood" ) != 0 ) return TRUE; } else { - if ( CVAR_GET_FLOAT("violence_ablood") != 0 ) + if( CVAR_GET_FLOAT( "violence_ablood" ) != 0 ) return TRUE; } } @@ -1102,10 +1097,10 @@ int UTIL_PointContents( const Vector &vec ) void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) { - if ( !UTIL_ShouldShowBlood( color ) ) + if( !UTIL_ShouldShowBlood( color ) ) return; - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) + if( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) color = 0; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); @@ -1123,22 +1118,22 @@ void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { - if ( !UTIL_ShouldShowBlood( color ) ) + if( !UTIL_ShouldShowBlood( color ) ) return; - if ( color == DONT_BLEED || amount == 0 ) + if( color == DONT_BLEED || amount == 0 ) return; - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) + if( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) color = 0; - if ( g_pGameRules->IsMultiplayer() ) + if( g_pGameRules->IsMultiplayer() ) { // scale up blood effect in multiplayer for better visibility amount *= 2; } - if ( amount > 255 ) + if( amount > 255 ) amount = 255; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); @@ -1157,21 +1152,21 @@ Vector UTIL_RandomBloodVector( void ) { Vector direction; - direction.x = RANDOM_FLOAT ( -1, 1 ); - direction.y = RANDOM_FLOAT ( -1, 1 ); - direction.z = RANDOM_FLOAT ( 0, 1 ); + 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( UTIL_ShouldShowBlood( bloodColor ) ) { - if ( bloodColor == BLOOD_COLOR_RED ) - UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); + if( bloodColor == BLOOD_COLOR_RED ) + UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG( 0, 5 ) ); else - UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); + UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG( 0, 5 ) ); } } @@ -1181,32 +1176,32 @@ void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) int index; int message; - if ( decalNumber < 0 ) + if( decalNumber < 0 ) return; - index = gDecals[ decalNumber ].index; + index = gDecals[decalNumber].index; - if ( index < 0 ) + if( index < 0 ) return; - if (pTrace->flFraction == 1.0) + if( pTrace->flFraction == 1.0 ) return; // Only decal BSP models - if ( pTrace->pHit ) + if( pTrace->pHit ) { CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); - if ( pEntity && !pEntity->IsBSPModel() ) + if( pEntity && !pEntity->IsBSPModel() ) return; entityIndex = ENTINDEX( pTrace->pHit ); } - else + else entityIndex = 0; message = TE_DECAL; - if ( entityIndex != 0 ) + if( entityIndex != 0 ) { - if ( index > 255 ) + if( index > 255 ) { message = TE_DECALHIGH; index -= 256; @@ -1215,20 +1210,20 @@ void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) else { message = TE_WORLDDECAL; - if ( index > 255 ) + 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 ) + if( entityIndex ) WRITE_SHORT( entityIndex ); MESSAGE_END(); } @@ -1246,42 +1241,42 @@ void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, { int index; - if (!bIsCustom) + if( !bIsCustom ) { - if ( decalNumber < 0 ) + if( decalNumber < 0 ) return; - index = gDecals[ decalNumber ].index; - if ( index < 0 ) + index = gDecals[decalNumber].index; + if( index < 0 ) return; } else index = decalNumber; - if (pTrace->flFraction == 1.0) + if( pTrace->flFraction == 1.0 ) return; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_PLAYERDECAL ); - WRITE_BYTE ( playernum ); + 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_SHORT( (short)ENTINDEX( pTrace->pHit ) ); WRITE_BYTE( index ); MESSAGE_END(); } void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { - if ( decalNumber < 0 ) + if( decalNumber < 0 ) return; - int index = gDecals[ decalNumber ].index; - if ( index < 0 ) + int index = gDecals[decalNumber].index; + if( index < 0 ) return; - if (pTrace->flFraction == 1.0) + if( pTrace->flFraction == 1.0 ) return; MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos ); @@ -1289,7 +1284,7 @@ void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) WRITE_COORD( pTrace->vecEndPos.x ); WRITE_COORD( pTrace->vecEndPos.y ); WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); + WRITE_SHORT( (short)ENTINDEX( pTrace->pHit ) ); WRITE_BYTE( index ); MESSAGE_END(); } @@ -1311,20 +1306,20 @@ void UTIL_Ricochet( const Vector &position, float scale ) WRITE_COORD( position.x ); WRITE_COORD( position.y ); WRITE_COORD( position.z ); - WRITE_BYTE( (int)(scale*10) ); + 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() ) + if( !g_pGameRules->IsTeamplay() ) return TRUE; // Both on a team? - if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) + if( *pTeamName1 != 0 && *pTeamName2 != 0 ) { - if ( !stricmp( pTeamName1, pTeamName2 ) ) // Same Team? + if( !stricmp( pTeamName1, pTeamName2 ) ) // Same Team? return TRUE; } @@ -1334,29 +1329,29 @@ BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) void UTIL_StringToVector( float *pVector, const char *pString ) { char *pstr, *pfront, tempString[128]; - int j; + int j; strcpy( tempString, pString ); pstr = pfront = tempString; - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c + for( j = 0; j < 3; j++ ) // lifted from pr_edict.c { pVector[j] = atof( pfront ); - while ( *pstr && *pstr != ' ' ) + while( *pstr && *pstr != ' ' ) pstr++; - if (!*pstr) + if( !(*pstr) ) break; pstr++; pfront = pstr; } - if (j < 2) + 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++) + for( j = j + 1;j < 3; j++ ) pVector[j] = 0; } } @@ -1364,24 +1359,24 @@ void UTIL_StringToVector( float *pVector, const char *pString ) void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) { char *pstr, *pfront, tempString[128]; - int j; + int j; strcpy( tempString, pString ); pstr = pfront = tempString; - for ( j = 0; j < count; j++ ) // lifted from pr_edict.c + for( j = 0; j < count; j++ ) // lifted from pr_edict.c { pVector[j] = atoi( pfront ); - while ( *pstr && *pstr != ' ' ) + while( *pstr && *pstr != ' ' ) pstr++; - if (!*pstr) + if( !(*pstr) ) break; pstr++; pfront = pstr; } - for ( j++; j < count; j++ ) + for( j++; j < count; j++ ) { pVector[j] = 0; } @@ -1391,23 +1386,23 @@ Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) { Vector sourceVector = input; - if ( sourceVector.x > clampSize.x ) + if( sourceVector.x > clampSize.x ) sourceVector.x -= clampSize.x; - else if ( sourceVector.x < -clampSize.x ) + else if( sourceVector.x < -clampSize.x ) sourceVector.x += clampSize.x; else sourceVector.x = 0; - if ( sourceVector.y > clampSize.y ) + if( sourceVector.y > clampSize.y ) sourceVector.y -= clampSize.y; - else if ( sourceVector.y < -clampSize.y ) + else if( sourceVector.y < -clampSize.y ) sourceVector.y += clampSize.y; else sourceVector.y = 0; - - if ( sourceVector.z > clampSize.z ) + + if( sourceVector.z > clampSize.z ) sourceVector.z -= clampSize.z; - else if ( sourceVector.z < -clampSize.z ) + else if( sourceVector.z < -clampSize.z ) sourceVector.z += clampSize.z; else sourceVector.z = 0; @@ -1420,18 +1415,18 @@ float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) Vector midUp = position; midUp.z = minz; - if (UTIL_PointContents(midUp) != CONTENTS_WATER) + if( UTIL_PointContents( midUp ) != CONTENTS_WATER ) return minz; midUp.z = maxz; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) + if( UTIL_PointContents( midUp ) == CONTENTS_WATER ) return maxz; float diff = maxz - minz; - while (diff > 1.0) + while( diff > 1.0 ) { - midUp.z = minz + diff/2.0; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) + midUp.z = minz + diff / 2.0; + if( UTIL_PointContents( midUp ) == CONTENTS_WATER ) { minz = midUp.z; } @@ -1445,13 +1440,13 @@ float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) return midUp.z; } -extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model +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; + Vector mid = ( mins + maxs ) * 0.5; - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); + float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); flHeight = flHeight - mins.z; MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid ); @@ -1471,21 +1466,21 @@ void UTIL_Bubbles( Vector mins, Vector maxs, int count ) void UTIL_BubbleTrail( Vector from, Vector to, int count ) { - float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); + float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); flHeight = flHeight - from.z; - if (flHeight < 8) + if( flHeight < 8 ) { - flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); + flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); flHeight = flHeight - to.z; - if (flHeight < 8) + if( flHeight < 8 ) return; // UNDONE: do a ploink sound flHeight = flHeight + to.z - from.z; } - if (count > 255) + if( count > 255 ) count = 255; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); @@ -1505,7 +1500,7 @@ void UTIL_BubbleTrail( Vector from, Vector to, int count ) void UTIL_Remove( CBaseEntity *pEntity ) { - if ( !pEntity ) + if( !pEntity ) return; pEntity->UpdateOnRemove(); @@ -1515,7 +1510,7 @@ void UTIL_Remove( CBaseEntity *pEntity ) BOOL UTIL_IsValidEntity( edict_t *pent ) { - if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) + if( !pent || pent->free || ( pent->v.flags & FL_KILLME ) ) return FALSE; return TRUE; } @@ -1525,16 +1520,16 @@ void UTIL_PrecacheOther( const char *szClassname ) edict_t *pent; pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) + if( FNullEnt( pent ) ) { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); + ALERT( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); return; } - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - if (pEntity) - pEntity->Precache( ); - REMOVE_ENTITY(pent); + CBaseEntity *pEntity = CBaseEntity::Instance( VARS( pent ) ); + if( pEntity ) + pEntity->Precache(); + REMOVE_ENTITY( pent ); } //========================================================= @@ -1543,12 +1538,12 @@ void UTIL_PrecacheOther( const char *szClassname ) //========================================================= void UTIL_LogPrintf( char *fmt, ... ) { - va_list argptr; - static char string[1024]; + va_list argptr; + static char string[1024]; - va_start ( argptr, fmt ); - vsprintf ( string, fmt, argptr ); - va_end ( argptr ); + va_start( argptr, fmt ); + vsprintf( string, fmt, argptr ); + va_end( argptr ); // Print to server console ALERT( at_logged, "%s", string ); @@ -1558,14 +1553,14 @@ void UTIL_LogPrintf( char *fmt, ... ) // 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 ) +float UTIL_DotPoints( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) { - Vector2D vec2LOS; + Vector2D vec2LOS; vec2LOS = ( vecCheck - vecSrc ).Make2D(); vec2LOS = vec2LOS.Normalize(); - return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); + return DotProduct( vec2LOS, ( vecDir.Make2D() ) ); } //========================================================= @@ -1575,7 +1570,7 @@ void UTIL_StripToken( const char *pKey, char *pDest ) { int i = 0; - while ( pKey[i] && pKey[i] != '#' ) + while( pKey[i] && pKey[i] != '#' ) { pDest[i] = pKey[i]; i++; @@ -1597,12 +1592,12 @@ static int gSizes[FIELD_TYPECOUNT] = 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(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 + sizeof(int *) * 2, // FIELD_FUNCTION #else sizeof(int *), // FIELD_FUNCTION #endif @@ -1615,92 +1610,92 @@ static int gSizes[FIELD_TYPECOUNT] = }; // Base class includes common SAVERESTOREDATA pointer, and manages the entity table -CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) +CSaveRestoreBuffer::CSaveRestoreBuffer( void ) { m_pdata = NULL; } -CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) +CSaveRestoreBuffer::CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) { m_pdata = pdata; } -CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) +CSaveRestoreBuffer::~CSaveRestoreBuffer( void ) { } -int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) +int CSaveRestoreBuffer::EntityIndex( CBaseEntity *pEntity ) { - if ( pEntity == NULL ) + if( pEntity == NULL ) return -1; return EntityIndex( pEntity->pev ); } -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) +int CSaveRestoreBuffer::EntityIndex( entvars_t *pevLookup ) { - if ( pevLookup == NULL ) + if( pevLookup == NULL ) return -1; return EntityIndex( ENT( pevLookup ) ); } -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) +int CSaveRestoreBuffer::EntityIndex( EOFFSET eoLookup ) { return EntityIndex( ENT( eoLookup ) ); } -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) +int CSaveRestoreBuffer::EntityIndex( edict_t *pentLookup ) { - if ( !m_pdata || pentLookup == NULL ) + if( !m_pdata || pentLookup == NULL ) return -1; int i; ENTITYTABLE *pTable; - for ( i = 0; i < m_pdata->tableCount; i++ ) + for( i = 0; i < m_pdata->tableCount; i++ ) { pTable = m_pdata->pTable + i; - if ( pTable->pent == pentLookup ) + if( pTable->pent == pentLookup ) return i; } return -1; } -edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) +edict_t *CSaveRestoreBuffer::EntityFromIndex( int entityIndex ) { - if ( !m_pdata || entityIndex < 0 ) + if( !m_pdata || entityIndex < 0 ) return NULL; int i; ENTITYTABLE *pTable; - for ( i = 0; i < m_pdata->tableCount; i++ ) + for( i = 0; i < m_pdata->tableCount; i++ ) { pTable = m_pdata->pTable + i; - if ( pTable->id == entityIndex ) + if( pTable->id == entityIndex ) return pTable->pent; } return NULL; } -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) +int CSaveRestoreBuffer::EntityFlagsSet( int entityIndex, int flags ) { - if ( !m_pdata || entityIndex < 0 ) + if( !m_pdata || entityIndex < 0 ) return 0; - if ( entityIndex > m_pdata->tableCount ) + if( entityIndex > m_pdata->tableCount ) return 0; - m_pdata->pTable[ entityIndex ].flags |= flags; + m_pdata->pTable[entityIndex].flags |= flags; - return m_pdata->pTable[ entityIndex ].flags; + return m_pdata->pTable[entityIndex].flags; } -void CSaveRestoreBuffer :: BufferRewind( int size ) +void CSaveRestoreBuffer::BufferRewind( int size ) { - if ( !m_pdata ) + if( !m_pdata ) return; - if ( m_pdata->size < size ) + if( m_pdata->size < size ) size = m_pdata->size; m_pdata->pCurrentData -= size; @@ -1709,7 +1704,7 @@ void CSaveRestoreBuffer :: BufferRewind( int size ) #ifndef _WIN32 extern "C" { -unsigned _rotr ( unsigned val, int shift) +unsigned _rotr( unsigned val, int shift ) { register unsigned lobit; /* non-zero means lo bit set */ register unsigned num = val; /* number to rotate */ @@ -1721,7 +1716,7 @@ unsigned _rotr ( unsigned val, int shift) { lobit = num & 1; /* get high bit */ num >>= 1; /* shift right one bit */ - if (lobit) + if( lobit ) num |= 0x80000000; /* set hi bit if lo bit was set */ } @@ -1730,85 +1725,85 @@ unsigned _rotr ( unsigned val, int shift) } #endif -unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) +unsigned int CSaveRestoreBuffer::HashString( const char *pszToken ) { - unsigned int hash = 0; + unsigned int hash = 0; - while ( *pszToken ) + while( *pszToken ) hash = _rotr( hash, 4 ) ^ *pszToken++; return hash; } -unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) +unsigned short CSaveRestoreBuffer::TokenHash( const char *pszToken ) { - unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); + 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 ) + if( !m_pdata->tokenCount || !m_pdata->pTokens ) ALERT( at_error, "No token table array in TokenHash()!" ); #endif - for ( int i=0; itokenCount; i++ ) + for( int i = 0; i < m_pdata->tokenCount; i++ ) { #if _DEBUG static qboolean beentheredonethat = FALSE; - if ( i > 50 && !beentheredonethat ) + 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 ) + 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 ) + 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 ) +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 ) +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 ) +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 ) +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 ) +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++ ) + 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 ) + if( m_pdata ) tmp -= m_pdata->time; BufferData( (const char *)&tmp, sizeof(float) ); @@ -1816,55 +1811,55 @@ void CSave :: WriteTime( const char *pname, const float *data, int count ) } } -void CSave :: WriteString( const char *pname, const char *pdata ) +void CSave::WriteString( const char *pname, const char *pdata ) { #ifdef TOKENIZE - short token = (short)TokenHash( pdata ); + short token = (short)TokenHash( pdata ); WriteShort( pname, &token, 1 ); #else - BufferField( pname, strlen(pdata) + 1, pdata ); + BufferField( pname, strlen( pdata ) + 1, pdata ); #endif } -void CSave :: WriteString( const char *pname, const int *stringId, int count ) +void CSave::WriteString( const char *pname, const int *stringId, int count ) { int i, size; #ifdef TOKENIZE - short token = (short)TokenHash( STRING( *stringId ) ); + short token = (short)TokenHash( STRING( *stringId ) ); WriteShort( pname, &token, 1 ); #else #if 0 - if ( count != 1 ) + if( count != 1 ) ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING(*stringId) ); + WriteString( pname, (char *)STRING( *stringId ) ); #endif size = 0; - for ( i = 0; i < count; i++ ) + for( i = 0; i < count; i++ ) size += strlen( STRING( stringId[i] ) ) + 1; BufferHeader( pname, size ); - for ( i = 0; i < count; i++ ) + for( i = 0; i < count; i++ ) { - const char *pString = STRING(stringId[i]); - BufferData( pString, strlen(pString)+1 ); + const char *pString = STRING( stringId[i] ); + BufferData( pString, strlen( pString ) + 1 ); } #endif } -void CSave :: WriteVector( const char *pname, const Vector &value ) +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 ) +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 ) +void CSave::WritePositionVector( const char *pname, const Vector &value ) { - if ( m_pdata && m_pdata->fUseLandmark ) + if( m_pdata && m_pdata->fUseLandmark ) { Vector tmp = value - m_pdata->vecLandmarkOffset; WriteVector( pname, tmp ); @@ -1873,17 +1868,17 @@ void CSave :: WritePositionVector( const char *pname, const Vector &value ) WriteVector( pname, value ); } -void CSave :: WritePositionVector( const char *pname, const float *value, int count ) +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++ ) + for( i = 0; i < count; i++ ) { Vector tmp( value[0], value[1], value[2] ); - if ( m_pdata && m_pdata->fUseLandmark ) + if( m_pdata && m_pdata->fUseLandmark ) tmp = tmp - m_pdata->vecLandmarkOffset; BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); @@ -1891,13 +1886,13 @@ void CSave :: WritePositionVector( const char *pname, const float *value, int co } } -void CSave :: WriteFunction( const char *pname, const int *data, int count ) +void CSave::WriteFunction( const char *pname, const int *data, int count ) { const char *functionName; functionName = NAME_FOR_FUNCTION( *data ); - if ( functionName ) - BufferField( pname, strlen(functionName) + 1, functionName ); + if( functionName ) + BufferField( pname, strlen( functionName ) + 1, functionName ); else ALERT( at_error, "Invalid function pointer in entity!" ); } @@ -1905,31 +1900,31 @@ void CSave :: WriteFunction( const char *pname, const int *data, int count ) void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) { int i; - TYPEDESCRIPTION *pField; + TYPEDESCRIPTION *pField; - for ( i = 0; i < ENTVARS_COUNT; i++ ) + for( i = 0; i < ENTVARS_COUNT; i++ ) { pField = &gEntvarsDescription[i]; - if ( !stricmp( pField->fieldName, pkvd->szKeyName ) ) + 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 ); + ( *(int *)( (char *)pev + pField->fieldOffset ) ) = ALLOC_STRING( pkvd->szValue ); break; case FIELD_TIME: case FIELD_FLOAT: - (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); + ( *(float *)( (char *)pev + pField->fieldOffset ) ) = atof( pkvd->szValue ); break; case FIELD_INTEGER: - (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); + ( *(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 ); + UTIL_StringToVector( (float *)( (char *)pev + pField->fieldOffset ), pkvd->szValue ); break; default: case FIELD_EVARS: @@ -1946,24 +1941,24 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) } } -int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) +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 CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) { - int i, j, actualCount, emptyCount; + int i, j, actualCount, emptyCount; TYPEDESCRIPTION *pTest; - int entityArray[MAX_ENTITYARRAY]; + int entityArray[MAX_ENTITYARRAY]; // Precalculate the number of empty fields emptyCount = 0; - for ( i = 0; i < fieldCount; i++ ) + 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] ) ) + pOutputData = ( (char *)pBaseData + pFields[i].fieldOffset ); + if( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) emptyCount++; } @@ -1971,14 +1966,14 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p actualCount = fieldCount - emptyCount; WriteInt( pname, &actualCount, 1 ); - for ( i = 0; i < fieldCount; i++ ) + for( i = 0; i < fieldCount; i++ ) { void *pOutputData; - pTest = &pFields[ i ]; - pOutputData = ((char *)pBaseData + pTest->fieldOffset ); + pTest = &pFields[i]; + pOutputData = ( (char *)pBaseData + pTest->fieldOffset ); // UNDONE: Must we do this twice? - if ( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) + if( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) continue; switch( pTest->fieldType ) @@ -1999,26 +1994,26 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p case FIELD_EDICT: case FIELD_ENTITY: case FIELD_EHANDLE: - if ( pTest->fieldSize > MAX_ENTITYARRAY ) + 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++ ) + for( j = 0; j < pTest->fieldSize; j++ ) { switch( pTest->fieldType ) { case FIELD_EVARS: - entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); + entityArray[j] = EntityIndex( ( (entvars_t **)pOutputData )[j] ); break; case FIELD_CLASSPTR: - entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); + entityArray[j] = EntityIndex( ( (CBaseEntity **)pOutputData )[j] ); break; case FIELD_EDICT: - entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); + entityArray[j] = EntityIndex( ( (edict_t **)pOutputData )[j] ); break; case FIELD_ENTITY: - entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); + entityArray[j] = EntityIndex( ( (EOFFSET *)pOutputData )[j] ); break; case FIELD_EHANDLE: - entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); + entityArray[j] = EntityIndex( (CBaseEntity *)( ( (EHANDLE *)pOutputData)[j] ) ); break; default: break; @@ -2037,10 +2032,10 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); break; case FIELD_SHORT: - WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); + WriteData( pTest->fieldName, 2 * pTest->fieldSize, ( (char *)pOutputData ) ); break; case FIELD_CHARACTER: - WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); + 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: @@ -2057,7 +2052,7 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p return 1; } -void CSave :: BufferString( char *pdata, int len ) +void CSave::BufferString( char *pdata, int len ) { char c = 0; @@ -2065,37 +2060,37 @@ void CSave :: BufferString( char *pdata, int len ) BufferData( &c, 1 ); // Write a null terminator } -int CSave :: DataEmpty( const char *pdata, int size ) +int CSave::DataEmpty( const char *pdata, int size ) { - for ( int i = 0; i < size; i++ ) + for( int i = 0; i < size; i++ ) { - if ( pdata[i] ) + if( pdata[i] ) return 0; } return 1; } -void CSave :: BufferField( const char *pname, int size, const char *pdata ) +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 ) +void CSave::BufferHeader( const char *pname, int size ) { - short hashvalue = TokenHash( pname ); - if ( size > 1<<(sizeof(short)*8) ) + 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 ) +void CSave::BufferData( const char *pdata, int size ) { - if ( !m_pdata ) + if( !m_pdata ) return; - if ( m_pdata->size + size > m_pdata->bufferSize ) + if( m_pdata->size + size > m_pdata->bufferSize ) { ALERT( at_error, "Save/Restore overflow!" ); m_pdata->size = m_pdata->bufferSize; @@ -2112,84 +2107,83 @@ void CSave :: BufferData( const char *pdata, int 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; + float time, timeData; + Vector position; edict_t *pent; - char *pString; + char *pString; time = 0; - position = Vector(0,0,0); + position = Vector( 0, 0, 0 ); - if ( m_pdata ) + if( m_pdata ) { time = m_pdata->time; - if ( m_pdata->fUseLandmark ) + if( m_pdata->fUseLandmark ) position = m_pdata->vecLandmarkOffset; } - for ( i = 0; i < fieldCount; i++ ) + for( i = 0; i < fieldCount; i++ ) { - fieldNumber = (i+startField)%fieldCount; - pTest = &pFields[ fieldNumber ]; - if ( !stricmp( pTest->fieldName, pName ) ) + fieldNumber = ( i + startField ) % fieldCount; + pTest = &pFields[fieldNumber]; + if( !stricmp( pTest->fieldName, pName ) ) { - if ( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) + if( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL ) ) { - for ( j = 0; j < pTest->fieldSize; j++ ) + for( j = 0; j < pTest->fieldSize; j++ ) { - void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); + void *pOutputData = ( (char *)pBaseData + pTest->fieldOffset + ( j * gSizes[pTest->fieldType] ) ); void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; switch( pTest->fieldType ) { case FIELD_TIME: #ifdef __VFP_FP__ - memcpy(&timeData, pInputData, 4); + memcpy( &timeData, pInputData, 4 ); // Re-base time variables timeData += time; - memcpy(pOutputData, &timeData, 4); + memcpy( pOutputData, &timeData, 4 ); #else timeData = *(float *)pInputData; // Re-base time variables timeData += time; - *((float *)pOutputData) = timeData; + *( (float *)pOutputData ) = timeData; #endif break; case FIELD_FLOAT: - memcpy(pOutputData, pInputData, 4); + memcpy( pOutputData, pInputData, 4 ); break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: // Skip over j strings pString = (char *)pData; - for ( stringCount = 0; stringCount < j; stringCount++ ) + for( stringCount = 0; stringCount < j; stringCount++ ) { - while (*pString) + while( *pString ) pString++; pString++; } pInputData = pString; - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; + if( strlen( (char *)pInputData ) == 0 ) + *( (int *)pOutputData ) = 0; else { int string; string = ALLOC_STRING( (char *)pInputData ); - *((int *)pOutputData) = string; + *( (int *)pOutputData ) = string; - if ( !FStringNull( string ) && m_precache ) + if( !FStringNull( string ) && m_precache ) { - if ( pTest->fieldType == FIELD_MODELNAME ) + if( pTest->fieldType == FIELD_MODELNAME ) PRECACHE_MODEL( (char *)STRING( string ) ); - else if ( pTest->fieldType == FIELD_SOUNDNAME ) + else if( pTest->fieldType == FIELD_SOUNDNAME ) PRECACHE_SOUND( (char *)STRING( string ) ); } } @@ -2197,83 +2191,83 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou case FIELD_EVARS: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((entvars_t **)pOutputData) = VARS(pent); + if( pent ) + *( (entvars_t **)pOutputData ) = VARS( pent ); else - *((entvars_t **)pOutputData) = NULL; + *( (entvars_t **)pOutputData ) = NULL; break; case FIELD_CLASSPTR: entityIndex = *( int *)pInputData; pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); + if( pent ) + *( (CBaseEntity **)pOutputData ) = CBaseEntity::Instance( pent ); else - *((CBaseEntity **)pOutputData) = NULL; + *( (CBaseEntity **)pOutputData ) = NULL; break; case FIELD_EDICT: - entityIndex = *( int *)pInputData; + entityIndex = *(int *)pInputData; pent = EntityFromIndex( entityIndex ); - *((edict_t **)pOutputData) = pent; + *( (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; + pOutputData = (char *)pOutputData + j * ( sizeof(EHANDLE) - gSizes[pTest->fieldType] ); + entityIndex = *(int *)pInputData; pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); + if( pent ) + *( (EHANDLE *)pOutputData ) = CBaseEntity::Instance( pent ); else - *((EHANDLE *)pOutputData) = NULL; + *( (EHANDLE *)pOutputData ) = NULL; break; case FIELD_ENTITY: - entityIndex = *( int *)pInputData; + entityIndex = *(int *)pInputData; pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EOFFSET *)pOutputData) = OFFSET(pent); + if( pent ) + *( (EOFFSET *)pOutputData ) = OFFSET( pent ); else - *((EOFFSET *)pOutputData) = 0; + *( (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]; + ( (float *)pOutputData )[0] = ( (float *)pInputData )[0]; + ( (float *)pOutputData )[1] = ( (float *)pInputData )[1]; + ( (float *)pOutputData )[2] = ( (float *)pInputData )[2]; break; case FIELD_POSITION_VECTOR: #ifdef __VFP_FP__ float tmp; - memcpy(&tmp, (char *)pInputData + 0, 4); + memcpy( &tmp, (char *)pInputData + 0, 4 ); tmp += position.x; - memcpy((char *)pOutputData + 0, &tmp, 4); - memcpy(&tmp, (char *)pInputData + 4, 4); + memcpy( (char *)pOutputData + 0, &tmp, 4 ); + memcpy( &tmp, (char *)pInputData + 4, 4 ); tmp += position.y; - memcpy((char *)pOutputData + 4, &tmp, 4); - memcpy(&tmp, (char *)pInputData + 8, 4); + memcpy( (char *)pOutputData + 4, &tmp, 4 ); + memcpy( &tmp, (char *)pInputData + 8, 4 ); tmp += position.z; - memcpy((char *)pOutputData + 8, &tmp, 4); + memcpy( (char *)pOutputData + 8, &tmp, 4 ); #else - ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; - ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; - ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; + ( (float *)pOutputData )[0] = ( (float *)pInputData )[0] + position.x; + ( (float *)pOutputData )[1] = ( (float *)pInputData )[1] + position.y; + ( (float *)pOutputData )[2] = ( (float *)pInputData )[2] + position.z; #endif break; case FIELD_BOOLEAN: case FIELD_INTEGER: - *((int *)pOutputData) = *( int *)pInputData; + *( (int *)pOutputData ) = *(int *)pInputData; break; case FIELD_SHORT: - *((short *)pOutputData) = *( short *)pInputData; + *( (short *)pOutputData ) = *(short *)pInputData; break; case FIELD_CHARACTER: - *((char *)pOutputData) = *( char *)pInputData; + *( (char *)pOutputData ) = *(char *)pInputData; break; case FIELD_POINTER: - *((void**)pOutputData) = *( void **)pInputData; + *( (void**)pOutputData ) = *(void **)pInputData; break; case FIELD_FUNCTION: - if ( strlen( (char *)pInputData ) == 0 ) - *((void**)pOutputData) = 0; + if( strlen( (char *)pInputData ) == 0 ) + *( (void**)pOutputData ) = 0; else - *((void**)pOutputData) = (void**)FUNCTION_FROM_NAME( (char *)pInputData ); + *( (void**)pOutputData ) = (void**)FUNCTION_FROM_NAME( (char *)pInputData ); break; default: ALERT( at_error, "Bad field type\n" ); @@ -2299,9 +2293,9 @@ int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) { - unsigned short i, token; - int lastField, fileCount; - HEADER header; + unsigned short i, token; + int lastField, fileCount; + HEADER header; i = ReadShort(); ASSERT( i == sizeof(int) ); // First entry should be an int @@ -2309,10 +2303,10 @@ int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p token = ReadShort(); // Check the struct name - if ( token != TokenHash(pname) ) // Field Set marker + if( token != TokenHash(pname) ) // Field Set marker { //ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); - BufferRewind( 2*sizeof(short) ); + BufferRewind( 2 * sizeof( short ) ); return 0; } @@ -2322,14 +2316,14 @@ int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p lastField = 0; // Make searches faster, most data is read/written in the same order // Clear out base data - for ( i = 0; i < fieldCount; i++ ) + 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] ); + 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++ ) + for( i = 0; i < fileCount; i++ ) { BufferReadHeader( &header ); lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); @@ -2372,7 +2366,7 @@ int CRestore::ReadNamedInt( const char *pName ) HEADER header; BufferReadHeader( &header ); - return ((int *)header.pData)[0]; + return ( (int *)header.pData )[0]; } char *CRestore::ReadNamedString( const char *pName ) @@ -2381,7 +2375,7 @@ char *CRestore::ReadNamedString( const char *pName ) BufferReadHeader( &header ); #ifdef TOKENIZE - return (char *)(m_pdata->pTokens[*(short *)header.pData]); + return (char *)( m_pdata->pTokens[*(short *)header.pData] ); #else return (char *)header.pData; #endif @@ -2389,7 +2383,7 @@ char *CRestore::ReadNamedString( const char *pName ) char *CRestore::BufferPointer( void ) { - if ( !m_pdata ) + if( !m_pdata ) return NULL; return m_pdata->pCurrentData; @@ -2399,17 +2393,17 @@ void CRestore::BufferReadBytes( char *pOutput, int size ) { ASSERT( m_pdata !=NULL ); - if ( !m_pdata || Empty() ) + if( !m_pdata || Empty() ) return; - if ( (m_pdata->size + size) > m_pdata->bufferSize ) + if( ( m_pdata->size + size ) > m_pdata->bufferSize ) { ALERT( at_error, "Restore overflow!" ); m_pdata->size = m_pdata->bufferSize; return; } - if ( pOutput ) + if( pOutput ) memcpy( pOutput, m_pdata->pCurrentData, size ); m_pdata->pCurrentData += size; m_pdata->size += size; @@ -2423,16 +2417,16 @@ void CRestore::BufferSkipBytes( int bytes ) int CRestore::BufferSkipZString( void ) { char *pszSearch; - int len; + int len; - if ( !m_pdata ) + if( !m_pdata ) return 0; int maxLen = m_pdata->bufferSize - m_pdata->size; len = 0; pszSearch = m_pdata->pCurrentData; - while ( *pszSearch++ && len < maxLen ) + while( *pszSearch++ && len < maxLen ) len++; len++; @@ -2444,14 +2438,14 @@ int CRestore::BufferSkipZString( void ) int CRestore::BufferCheckZString( const char *string ) { - if ( !m_pdata ) + if( !m_pdata ) return 0; int maxLen = m_pdata->bufferSize - m_pdata->size; int len = strlen( string ); - if ( len <= maxLen ) + if( len <= maxLen ) { - if ( !strncmp( string, m_pdata->pCurrentData, len ) ) + if( !strncmp( string, m_pdata->pCurrentData, len ) ) return 1; } return 0; diff --git a/dlls/vector.h b/dlls/vector.h index 81b3e575..d3347983 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -24,19 +24,19 @@ class Vector2D public: inline Vector2D(void) { } inline Vector2D(float X, float Y) { 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 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 float Length(void) const { return sqrt(x * x + y * y ); } inline Vector2D Normalize ( void ) const { Vector2D vec2; float flLen = Length(); - if ( flLen == 0 ) + if( flLen == 0 ) { return Vector2D( 0, 0 ); } @@ -50,8 +50,8 @@ public: 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; } +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 @@ -60,36 +60,36 @@ class Vector // same data-layout as engine's vec3_t, { // which is a vec_t[3] public: // Construction/destruction - inline Vector(void) { } - inline Vector(float X, float Y, float Z) { 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 = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + inline Vector( void ) { } + inline Vector( float X, float Y, float Z ) { 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 = v.x; y = v.y; z = v.z; } + inline Vector( float rgfl[3] ) { 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); } + 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); } + 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 + inline Vector Normalize( void ) const { float flLen = Length(); - if (flLen == 0) return Vector(0,0,1); // ???? + if( flLen == 0 ) return Vector( 0, 0, 1 ); // ???? flLen = 1 / flLen; - return Vector(x * flLen, y * flLen, z * flLen); + return Vector( x * flLen, y * flLen, z * flLen ); } - inline Vector2D Make2D ( void ) const + inline Vector2D Make2D( void ) const { Vector2D Vec2; @@ -98,12 +98,12 @@ public: return Vec2; } - inline float Length2D(void) const { return sqrt(x*x + y*y); } + 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 ); } +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/dlls/world.cpp b/dlls/world.cpp index ed416139..ffe5e8c4 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -41,19 +41,19 @@ extern CSoundEnt *pSoundEnt; extern CBaseEntity *g_pLastSpawn; DLL_GLOBAL edict_t *g_pBodyQueueHead; CGlobalState gGlobalState; -extern DLL_GLOBAL int gDisplayTitle; +extern DLL_GLOBAL int gDisplayTitle; -extern void W_Precache(void); +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 + { "{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 @@ -85,12 +85,12 @@ DLL_DECALLIST gDecals[] = { { "{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 + { "{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 }; /* @@ -106,24 +106,24 @@ BODY QUE 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 ); + 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 ) +void CDecal::Spawn( void ) { - if ( pev->skin < 0 || (gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH )) ) + if( pev->skin < 0 || ( gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH ) ) ) { - REMOVE_ENTITY(ENT(pev)); + REMOVE_ENTITY( ENT( pev ) ); return; } - if ( FStringNull ( pev->targetname ) ) + 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. @@ -133,45 +133,45 @@ void CDecal :: Spawn( void ) { // if there IS a targetname, the decal sprays itself on when it is triggered. SetThink( &CBaseEntity::SUB_DoNothing ); - SetUse( &CDecal::TriggerDecal); + SetUse( &CDecal::TriggerDecal ); } } -void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +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; + int entityIndex; - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); + 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); + 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); + entityIndex = (short)ENTINDEX( trace.pHit ); WRITE_SHORT( entityIndex ); - if ( entityIndex ) - WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); + if( entityIndex ) + WRITE_SHORT( (int)VARS( trace.pHit )->modelindex ); MESSAGE_END(); SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } -void CDecal :: StaticDecal( void ) +void CDecal::StaticDecal( void ) { TraceResult trace; - int entityIndex, modelIndex; + int entityIndex, modelIndex; - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); + 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; + entityIndex = (short)ENTINDEX( trace.pHit ); + if( entityIndex ) + modelIndex = (int)VARS( trace.pHit )->modelindex; else modelIndex = 0; @@ -180,14 +180,14 @@ void CDecal :: StaticDecal( void ) SUB_Remove(); } -void CDecal :: KeyValue( KeyValueData *pkvd ) +void CDecal::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "texture")) + if( FStrEq( pkvd->szKeyName, "texture" ) ) { pev->skin = DECAL_INDEX( pkvd->szValue ); // Found - if ( pev->skin >= 0 ) + if( pev->skin >= 0 ) return; ALERT( at_console, "Can't find decal %s\n", pkvd->szValue ); } @@ -203,18 +203,18 @@ class CCorpse : public CBaseEntity LINK_ENTITY_TO_CLASS( bodyque, CCorpse ) -static void InitBodyQue(void) +static void InitBodyQue( void ) { - string_t istrClassname = MAKE_STRING("bodyque"); + string_t istrClassname = MAKE_STRING( "bodyque" ); g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); - entvars_t *pev = VARS(g_pBodyQueueHead); + entvars_t *pev = VARS( g_pBodyQueueHead ); // Reserve 3 more slots for dead bodies - for ( int i = 0; i < 3; i++ ) + for( int i = 0; i < 3; i++ ) { pev->owner = CREATE_NAMED_ENTITY( istrClassname ); - pev = VARS(pev->owner); + pev = VARS( pev->owner ); } pev->owner = g_pBodyQueueHead; @@ -225,12 +225,12 @@ static void InitBodyQue(void) // // GLOBALS ASSUMED SET: g_eoBodyQueueHead // -void CopyToBodyQue(entvars_t *pev) +void CopyToBodyQue( entvars_t *pev ) { - if (pev->effects & EF_NODRAW) + if( pev->effects & EF_NODRAW ) return; - entvars_t *pevHead = VARS(g_pBodyQueueHead); + entvars_t *pevHead = VARS( g_pBodyQueueHead ); pevHead->angles = pev->angles; pevHead->model = pev->model; @@ -244,16 +244,16 @@ void CopyToBodyQue(entvars_t *pev) pevHead->renderfx = kRenderFxDeadPlayer; pevHead->renderamt = ENTINDEX( ENT( pev ) ); - pevHead->effects = pev->effects | EF_NOINTERP; + pevHead->effects = pev->effects | EF_NOINTERP; //pevHead->goalstarttime = pev->goalstarttime; - //pevHead->goalframe = pev->goalframe; + //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); + UTIL_SetOrigin( pevHead, pev->origin ); + UTIL_SetSize( pevHead, pev->mins, pev->maxs ); g_pBodyQueueHead = pevHead->owner; } @@ -268,18 +268,18 @@ void CGlobalState::Reset( void ) m_listCount = 0; } -globalentity_t *CGlobalState :: Find( string_t globalname ) +globalentity_t *CGlobalState::Find( string_t globalname ) { - if ( !globalname ) + if( !globalname ) return NULL; globalentity_t *pTest; - const char *pEntityName = STRING(globalname); + const char *pEntityName = STRING( globalname ); pTest = m_pList; - while ( pTest ) + while( pTest ) { - if ( FStrEq( pEntityName, pTest->name ) ) + if( FStrEq( pEntityName, pTest->name ) ) break; pTest = pTest->pNext; @@ -290,14 +290,14 @@ globalentity_t *CGlobalState :: Find( string_t globalname ) // This is available all the time now on impulse 104, remove later //#ifdef _DEBUG -void CGlobalState :: DumpGlobals( void ) +void CGlobalState::DumpGlobals( void ) { static char *estates[] = { "Off", "On", "Dead" }; globalentity_t *pTest; ALERT( at_console, "-- Globals --\n" ); pTest = m_pList; - while ( pTest ) + while( pTest ) { ALERT( at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); pTest = pTest->pNext; @@ -305,25 +305,25 @@ void CGlobalState :: DumpGlobals( void ) } //#endif -void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) +void CGlobalState::EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) { - ASSERT( !Find(globalname) ); + 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) ); + strcpy( pNewEntity->levelName, STRING( mapName ) ); pNewEntity->state = state; m_listCount++; } -void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) +void CGlobalState::EntitySetState( string_t globalname, GLOBALESTATE state ) { globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) + if( pEnt ) pEnt->state = state; } @@ -334,10 +334,10 @@ const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) return pEnt; } -GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) +GLOBALESTATE CGlobalState::EntityGetState( string_t globalname ) { globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) + if( pEnt ) return pEnt->state; return GLOBAL_OFF; @@ -362,13 +362,13 @@ int CGlobalState::Save( CSave &save ) int i; globalentity_t *pEntity; - if ( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) + if( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE( m_SaveData ) ) ) return 0; pEntity = m_pList; - for ( i = 0; i < m_listCount && pEntity; i++ ) + for( i = 0; i < m_listCount && pEntity; i++ ) { - if ( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) + if( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE( gGlobalEntitySaveData ) ) ) return 0; pEntity = pEntity->pNext; @@ -383,17 +383,17 @@ int CGlobalState::Restore( CRestore &restore ) globalentity_t tmpEntity; ClearStates(); - if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) + 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++ ) + for( i = 0; i < listCount; i++ ) { - if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) + if( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE( gGlobalEntitySaveData ) ) ) return 0; - EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); + EntityAdd( MAKE_STRING( tmpEntity.name ), MAKE_STRING( tmpEntity.levelName ), tmpEntity.state ); } return 1; } @@ -402,14 +402,14 @@ void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) { globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) - strcpy( pEnt->levelName, STRING(mapname) ); + if( pEnt ) + strcpy( pEnt->levelName, STRING( mapname ) ); } void CGlobalState::ClearStates( void ) { globalentity_t *pFree = m_pList; - while ( pFree ) + while( pFree ) { globalentity_t *pNext = pFree->pNext; free( pFree ); @@ -452,13 +452,13 @@ LINK_ENTITY_TO_CLASS( worldspawn, CWorld ) extern DLL_GLOBAL BOOL g_fGameOver; float g_flWeaponCheat; -void CWorld :: Spawn( void ) +void CWorld::Spawn( void ) { g_fGameOver = FALSE; - Precache( ); + Precache(); } -void CWorld :: Precache( void ) +void CWorld::Precache( void ) { g_pLastSpawn = NULL; #if 1 @@ -471,12 +471,12 @@ void CWorld :: Precache( void ) CVAR_SET_STRING("room_type", "0");// clear DSP // Set up game rules - if (g_pGameRules) + if( g_pGameRules ) { delete g_pGameRules; } - g_pGameRules = InstallGameRules( ); + g_pGameRules = InstallGameRules(); //!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here @@ -485,13 +485,13 @@ void CWorld :: Precache( void ) pSoundEnt = GetClassPtr( ( CSoundEnt *)NULL ); pSoundEnt->Spawn(); - if ( !pSoundEnt ) + 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(); @@ -501,12 +501,12 @@ void CWorld :: Precache( void ) // the area based ambient sounds MUST be the first precache_sounds // player precaches - W_Precache (); // get weapon precaches + W_Precache(); // get weapon precaches ClientPrecache(); // sounds used from C physics code - PRECACHE_SOUND("common/null.wav");// clears sound channels + 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. @@ -515,7 +515,7 @@ void CWorld :: Precache( void ) PRECACHE_SOUND( "common/bodydrop4.wav" ); g_Language = (int)CVAR_GET_FLOAT( "sv_language" ); - if ( g_Language == LANGUAGE_GERMAN ) + if( g_Language == LANGUAGE_GERMAN ) { PRECACHE_MODEL( "models/germangibs.mdl" ); } @@ -525,90 +525,90 @@ void CWorld :: Precache( void ) 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"); + 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"); + LIGHT_STYLE( 0, "m" ); // 1 FLICKER (first variety) - LIGHT_STYLE(1, "mmnmmommommnonmmonqnmmo"); + LIGHT_STYLE( 1, "mmnmmommommnonmmonqnmmo" ); // 2 SLOW STRONG PULSE - LIGHT_STYLE(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + LIGHT_STYLE( 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba" ); // 3 CANDLE (first variety) - LIGHT_STYLE(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + LIGHT_STYLE( 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg" ); // 4 FAST STROBE - LIGHT_STYLE(4, "mamamamamama"); + LIGHT_STYLE( 4, "mamamamamama" ); // 5 GENTLE PULSE 1 - LIGHT_STYLE(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + LIGHT_STYLE( 5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj" ); // 6 FLICKER (second variety) - LIGHT_STYLE(6, "nmonqnmomnmomomno"); + LIGHT_STYLE( 6, "nmonqnmomnmomomno" ); // 7 CANDLE (second variety) - LIGHT_STYLE(7, "mmmaaaabcdefgmmmmaaaammmaamm"); + LIGHT_STYLE( 7, "mmmaaaabcdefgmmmmaaaammmaamm" ); // 8 CANDLE (third variety) - LIGHT_STYLE(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + LIGHT_STYLE( 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa" ); // 9 SLOW STROBE (fourth variety) - LIGHT_STYLE(9, "aaaaaaaazzzzzzzz"); + LIGHT_STYLE( 9, "aaaaaaaazzzzzzzz" ); // 10 FLUORESCENT FLICKER - LIGHT_STYLE(10, "mmamammmmammamamaaamammma"); + LIGHT_STYLE( 10, "mmamammmmammamamaaamammma" ); // 11 SLOW PULSE NOT FADE TO BLACK - LIGHT_STYLE(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); + 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"); + LIGHT_STYLE( 12, "mmnnmmnnnmmnn" ); // styles 32-62 are assigned by the light program for switchable lights // 63 testing - LIGHT_STYLE(63, "a"); + LIGHT_STYLE( 63, "a" ); - for ( int i = 0; i < ARRAYSIZE(gDecals); i++ ) + for( int i = 0; i < 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 ) ) ) + if( !WorldGraph.CheckNODFile( ( char * )STRING( gpGlobals->mapname ) ) ) { // NOD file is not present, or is older than the BSP file. - WorldGraph.AllocNodes (); + WorldGraph.AllocNodes(); } else { // Load the node graph for this level - if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) + 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 (); + ALERT( at_console, "*Error opening .NOD file\n" ); + WorldGraph.AllocNodes(); } else { - ALERT ( at_console, "\n*Graph Loaded!\n" ); + ALERT( at_console, "\n*Graph Loaded!\n" ); } } - if ( pev->speed > 0 ) + if( pev->speed > 0 ) CVAR_SET_FLOAT( "sv_zmax", pev->speed ); else CVAR_SET_FLOAT( "sv_zmax", 4096 ); @@ -616,11 +616,11 @@ void CWorld :: Precache( void ) // g-cont. moved here to right restore global WaveHeight on save\restore level CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); - if ( pev->netname ) + if( pev->netname ) { - ALERT( at_aiconsole, "Chapter title: %s\n", STRING(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 ) + if( pEntity ) { pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); pEntity->pev->message = pev->netname; @@ -630,21 +630,21 @@ void CWorld :: Precache( void ) } } - if ( pev->spawnflags & SF_WORLD_DARK ) + if( pev->spawnflags & SF_WORLD_DARK ) CVAR_SET_FLOAT( "v_dark", 1.0 ); else CVAR_SET_FLOAT( "v_dark", 0.0 ); pev->spawnflags &= ~SF_WORLD_DARK; // g-cont. don't apply fade after save\restore - - if ( pev->spawnflags & SF_WORLD_TITLE ) + + if( pev->spawnflags & SF_WORLD_TITLE ) gDisplayTitle = TRUE; // display the game title if this key is set else gDisplayTitle = FALSE; pev->spawnflags &= ~SF_WORLD_TITLE; // g-cont. don't show logo after save\restore - - if ( pev->spawnflags & SF_WORLD_FORCETEAM ) + + if( pev->spawnflags & SF_WORLD_FORCETEAM ) { CVAR_SET_FLOAT( "mp_defaultteam", 1 ); } @@ -660,66 +660,66 @@ void CWorld :: Precache( void ) // // Just to ignore the "wad" field. // -void CWorld :: KeyValue( KeyValueData *pkvd ) +void CWorld::KeyValue( KeyValueData *pkvd ) { - if ( FStrEq(pkvd->szKeyName, "skyname") ) + 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") ) + else if( FStrEq( pkvd->szKeyName, "sounds" ) ) { - gpGlobals->cdAudioTrack = atoi(pkvd->szValue); + gpGlobals->cdAudioTrack = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "WaveHeight") ) + else if( FStrEq(pkvd->szKeyName, "WaveHeight" ) ) { // Sent over net now. - pev->scale = atof(pkvd->szValue) * (1.0/8.0); + pev->scale = atof( pkvd->szValue ) * ( 1.0 / 8.0 ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "MaxRange") ) + else if( FStrEq( pkvd->szKeyName, "MaxRange" ) ) { - pev->speed = atof(pkvd->szValue); + pev->speed = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) + else if( FStrEq( pkvd->szKeyName, "chaptertitle" ) ) { - pev->netname = ALLOC_STRING(pkvd->szValue); + pev->netname = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "startdark") ) + 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); + int flag = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; - if ( flag ) + if( flag ) pev->spawnflags |= SF_WORLD_DARK; } - else if ( FStrEq(pkvd->szKeyName, "newunit") ) + else if( FStrEq(pkvd->szKeyName, "newunit") ) { // Single player only. Clear save directory if set - if ( atoi(pkvd->szValue) ) + if( atoi( pkvd->szValue ) ) CVAR_SET_FLOAT( "sv_newunit", 1 ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "gametitle") ) + else if( FStrEq(pkvd->szKeyName, "gametitle" ) ) { - if ( atoi(pkvd->szValue) ) + if( atoi( pkvd->szValue ) ) pev->spawnflags |= SF_WORLD_TITLE; pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "mapteams") ) + else if( FStrEq( pkvd->szKeyName, "mapteams" ) ) { pev->team = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "defaultteam") ) + else if( FStrEq( pkvd->szKeyName, "defaultteam" ) ) { - if ( atoi(pkvd->szValue) ) + if( atoi( pkvd->szValue ) ) { pev->spawnflags |= SF_WORLD_FORCETEAM; } @@ -733,7 +733,7 @@ void CWorld :: KeyValue( KeyValueData *pkvd ) // Xash3D physics interface // -typedef void ( *LINK_ENTITY_FN)( entvars_t *pev ); +typedef void (*LINK_ENTITY_FN)( entvars_t *pev ); // // attempt to create custom entity when default method is failed @@ -744,7 +744,7 @@ int DispatchCreateEntity( edict_t *pent, const char *szName ) /* #ifdef CREATE_ENTITY_TEST // quake armor entities. we just replaced it with item_battery... - if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" )) + if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" ) ) { LINK_ENTITY_FN SpawnEdict; @@ -756,12 +756,12 @@ int DispatchCreateEntity( edict_t *pent, const char *szName ) // BUGBUG: old classname hanging in memory pent->v.classname = ALLOC_STRING( "item_battery" ); - //ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname )); + //ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname ) ); SpawnEdict( &pent->v ); return 0; // handled } - } + } #endif */ return -1; @@ -773,11 +773,11 @@ int DispatchCreateEntity( edict_t *pent, const char *szName ) // int DispatchPhysicsEntity( edict_t *pEdict ) { - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pEdict); + CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pEdict ); if( !pEntity ) { - //ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict )); + //ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict ) ); return 0; // not initialized } @@ -785,15 +785,15 @@ int DispatchPhysicsEntity( edict_t *pEdict ) /* #ifdef CUSTOM_PHYSICS_TEST // test alien controller without physics, thinking only - if( FClassnameIs( pEntity->pev, "monster_alien_controller" )) + if( FClassnameIs( pEntity->pev, "monster_alien_controller" ) ) { - float thinktime; + float thinktime; thinktime = pEntity->pev->nextthink; if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime ) return 1; - if( thinktime < PHYSICS_TIME( )) + if( thinktime < PHYSICS_TIME() ) thinktime = PHYSICS_TIME(); // don't let things stay in the past. // it is possible to start that way // by a trigger with a local time. @@ -813,8 +813,8 @@ int DispatchPhysicsEntity( edict_t *pEdict ) */ return 0; } - -static physics_interface_t gPhysicsInterface = + +static physics_interface_t gPhysicsInterface = { SV_PHYSICS_INTERFACE_VERSION, DispatchCreateEntity, @@ -823,16 +823,16 @@ static physics_interface_t gPhysicsInterface = int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ) { - if ( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) + if( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) { return FALSE; } // copy new physics interface - memcpy(&g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t)); + memcpy( &g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t) ); // fill engine callbacks - memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) ); + memcpy( pFunctionTable, &gPhysicsInterface, sizeof(physics_interface_t) ); return TRUE; } diff --git a/dlls/xen.cpp b/dlls/xen.cpp index feb61741..8e9c771c 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -24,17 +24,17 @@ class CActAnimating : public CBaseAnimating { public: - void SetActivity( Activity act ); + void SetActivity( Activity act ); inline Activity GetActivity( void ) { return m_Activity; } - virtual int ObjectCaps( void ) { return CBaseAnimating :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int ObjectCaps( void ) { return CBaseAnimating::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; private: - Activity m_Activity; + Activity m_Activity; }; TYPEDESCRIPTION CActAnimating::m_SaveData[] = @@ -44,35 +44,35 @@ TYPEDESCRIPTION CActAnimating::m_SaveData[] = IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ) -void CActAnimating :: SetActivity( Activity act ) +void CActAnimating::SetActivity( Activity act ) { int sequence = LookupActivity( act ); - if ( sequence != ACTIVITY_NOT_AVAILABLE ) + if( sequence != ACTIVITY_NOT_AVAILABLE ) { pev->sequence = sequence; m_Activity = act; pev->frame = 0; - ResetSequenceInfo( ); + ResetSequenceInfo(); } } class CXenPLight : public CActAnimating { public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); + void Spawn( void ); + void Precache( void ); + void Touch( CBaseEntity *pOther ); + void Think( void ); - void LightOn( void ); - void LightOff( void ); + void LightOn( void ); + void LightOff( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; private: - CSprite *m_pGlow; + CSprite *m_pGlow; }; LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ) @@ -84,31 +84,31 @@ TYPEDESCRIPTION CXenPLight::m_SaveData[] = IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ) -void CXenPLight :: Spawn( void ) +void CXenPLight::Spawn( void ) { Precache(); - SET_MODEL( ENT(pev), "models/light.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_TRIGGER; + 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)); + 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); + 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); m_pGlow->SetAttachment( edict(), 1 ); } -void CXenPLight :: Precache( void ) +void CXenPLight::Precache( void ) { PRECACHE_MODEL( "models/light.mdl" ); PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); } -void CXenPLight :: Think( void ) +void CXenPLight::Think( void ) { StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; @@ -116,21 +116,21 @@ void CXenPLight :: Think( void ) switch( GetActivity() ) { case ACT_CROUCH: - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { SetActivity( ACT_CROUCHIDLE ); LightOff(); } break; case ACT_CROUCHIDLE: - if ( gpGlobals->time > pev->dmgtime ) + if( gpGlobals->time > pev->dmgtime ) { SetActivity( ACT_STAND ); LightOn(); } break; case ACT_STAND: - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) SetActivity( ACT_IDLE ); break; case ACT_IDLE: @@ -139,38 +139,38 @@ void CXenPLight :: Think( void ) } } -void CXenPLight :: Touch( CBaseEntity *pOther ) +void CXenPLight::Touch( CBaseEntity *pOther ) { - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { pev->dmgtime = gpGlobals->time + XEN_PLANT_HIDE_TIME; - if ( GetActivity() == ACT_IDLE || GetActivity() == ACT_STAND ) + if( GetActivity() == ACT_IDLE || GetActivity() == ACT_STAND ) { SetActivity( ACT_CROUCH ); } } } -void CXenPLight :: LightOn( void ) +void CXenPLight::LightOn( void ) { SUB_UseTargets( this, USE_ON, 0 ); - if ( m_pGlow ) + if( m_pGlow ) m_pGlow->pev->effects &= ~EF_NODRAW; } -void CXenPLight :: LightOff( void ) +void CXenPLight::LightOff( void ) { SUB_UseTargets( this, USE_OFF, 0 ); - if ( m_pGlow ) + if( m_pGlow ) m_pGlow->pev->effects |= EF_NODRAW; } class CXenHair : public CActAnimating { public: - void Spawn( void ); - void Precache( void ); - void Think( void ); + void Spawn( void ); + void Precache( void ); + void Think( void ); }; LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ) @@ -181,15 +181,15 @@ void CXenHair::Spawn( void ) { Precache(); SET_MODEL( edict(), "models/hair.mdl" ); - UTIL_SetSize( pev, Vector(-4,-4,0), Vector(4,4,32)); + UTIL_SetSize( pev, Vector( -4, -4, 0 ), Vector( 4, 4, 32 ) ); pev->sequence = 0; - - if ( !(pev->spawnflags & SF_HAIR_SYNC) ) + + if( !( pev->spawnflags & SF_HAIR_SYNC ) ) { - pev->frame = RANDOM_FLOAT(0,255); + pev->frame = RANDOM_FLOAT( 0, 255 ); pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); } - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; @@ -210,17 +210,17 @@ void CXenHair::Precache( void ) class CXenTreeTrigger : public CBaseEntity { public: - void Touch( CBaseEntity *pOther ); + 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 *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->classname = MAKE_STRING( "xen_ttrigger" ); pTrigger->pev->solid = SOLID_TRIGGER; pTrigger->pev->movetype = MOVETYPE_NONE; pTrigger->pev->owner = pOwner; @@ -230,9 +230,9 @@ CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector void CXenTreeTrigger::Touch( CBaseEntity *pOther ) { - if ( pev->owner ) + if( pev->owner ) { - CBaseEntity *pEntity = CBaseEntity::Instance(pev->owner); + CBaseEntity *pEntity = CBaseEntity::Instance( pev->owner ); pEntity->Touch( pOther ); } } @@ -242,18 +242,18 @@ void CXenTreeTrigger::Touch( CBaseEntity *pOther ) 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; } + 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; static const char *pAttackHitSounds[]; static const char *pAttackMissSounds[]; @@ -271,25 +271,25 @@ TYPEDESCRIPTION CXenTree::m_SaveData[] = IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ) -void CXenTree :: Spawn( void ) +void CXenTree::Spawn( void ) { Precache(); - SET_MODEL( ENT(pev), "models/tree.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; + 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)); + 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->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); + 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 ) ); @@ -308,7 +308,7 @@ const char *CXenTree::pAttackMissSounds[] = "zombie/claw_miss2.wav", }; -void CXenTree :: Precache( void ) +void CXenTree::Precache( void ) { PRECACHE_MODEL( "models/tree.mdl" ); PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); @@ -316,17 +316,17 @@ void CXenTree :: Precache( void ) PRECACHE_SOUND_ARRAY( pAttackMissSounds ); } -void CXenTree :: Touch( CBaseEntity *pOther ) +void CXenTree::Touch( CBaseEntity *pOther ) { - if ( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) + if( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) return; Attack(); } -void CXenTree :: Attack( void ) +void CXenTree::Attack( void ) { - if ( GetActivity() == ACT_IDLE ) + if( GetActivity() == ACT_IDLE ) { SetActivity( ACT_MELEE_ATTACK1 ); pev->framerate = RANDOM_FLOAT( 1.0, 1.4 ); @@ -334,7 +334,7 @@ void CXenTree :: Attack( void ) } } -void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CXenTree::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -342,16 +342,16 @@ void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) { CBaseEntity *pList[8]; BOOL sound = FALSE; - int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT ); + 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++ ) + for( int i = 0; i < count; i++ ) { - if ( pList[i] != this ) + if( pList[i] != this ) { - if ( pList[i]->pev->owner != edict() ) + if( pList[i]->pev->owner != edict() ) { sound = TRUE; pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH ); @@ -361,7 +361,7 @@ void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } - if ( sound ) + if( sound ) { EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); } @@ -372,7 +372,7 @@ void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) CActAnimating::HandleAnimEvent( pEvent ); } -void CXenTree :: Think( void ) +void CXenTree::Think( void ) { float flInterval = StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; @@ -381,7 +381,7 @@ void CXenTree :: Think( void ) switch( GetActivity() ) { case ACT_MELEE_ATTACK1: - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { SetActivity( ACT_IDLE ); pev->framerate = RANDOM_FLOAT( 0.6, 1.4 ); @@ -403,30 +403,30 @@ void CXenTree :: Think( void ) 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 ) {} + 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 ); + void Spawn( void ); }; class CXenSporeMed : public CXenSpore { - void Spawn( void ); + void Spawn( void ); }; class CXenSporeLarge : public CXenSpore { - void Spawn( void ); + void Spawn( void ); static const Vector m_hullSizes[]; }; @@ -436,10 +436,10 @@ 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; } + int Classify( void ) { return CLASS_BARNACLE; } }; -CXenHull *CXenHull :: CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ) +CXenHull *CXenHull::CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ) { CXenHull *pHull = GetClassPtr( (CXenHull *)NULL ); @@ -466,14 +466,14 @@ void CXenSporeSmall::Spawn( void ) { pev->skin = 0; CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-16,-16,0), Vector(16,16,64)); + 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)); + UTIL_SetSize( pev, Vector( -40, -40, 0 ), Vector( 40, 40, 120 ) ); } // I just eyeballed these -- fill in hulls for the legs @@ -490,31 +490,31 @@ void CXenSporeLarge::Spawn( void ) { pev->skin = 2; CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-48,-48,110), Vector(48,48,240)); + 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 < 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) ); + for( int i = 0; i < 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; + 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->frame = RANDOM_FLOAT( 0, 255 ); pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - ResetSequenceInfo( ); + ResetSequenceInfo(); pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit } @@ -525,16 +525,16 @@ const char *CXenSpore::pModelNames[] = "models/fungus(large).mdl", }; -void CXenSpore :: Precache( void ) +void CXenSpore::Precache( void ) { PRECACHE_MODEL( (char *)pModelNames[pev->skin] ); } -void CXenSpore :: Touch( CBaseEntity *pOther ) +void CXenSpore::Touch( CBaseEntity *pOther ) { } -void CXenSpore :: Think( void ) +void CXenSpore::Think( void ) { float flInterval = StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 2ae4b690..7fe416c7 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -31,7 +31,7 @@ #define ZOMBIE_AE_ATTACK_LEFT 0x02 #define ZOMBIE_AE_ATTACK_BOTH 0x03 -#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs +#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs class CZombie : public CBaseMonster { @@ -39,9 +39,9 @@ public: void Spawn( void ); void Precache( void ); void SetYawSpeed( void ); - int Classify ( void ); + int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); - int IgnoreConditions ( void ); + int IgnoreConditions( void ); float m_flNextFlinch; @@ -58,8 +58,8 @@ public: static const char *pAttackMissSounds[]; // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } + 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 ); }; @@ -109,7 +109,7 @@ const char *CZombie::pPainSounds[] = // Classify - indicates this monster's place in the // relationship table. //========================================================= -int CZombie :: Classify ( void ) +int CZombie::Classify( void ) { return CLASS_ALIEN_MONSTER; } @@ -118,7 +118,7 @@ int CZombie :: Classify ( void ) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CZombie :: SetYawSpeed ( void ) +void CZombie::SetYawSpeed( void ) { int ys; @@ -131,10 +131,10 @@ void CZombie :: SetYawSpeed ( void ) pev->yaw_speed = ys; } -int CZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +int CZombie::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { // Take 30% damage from bullets - if ( bitsDamageType == DMG_BULLET ) + if( bitsDamageType == DMG_BULLET ) { Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; vecDir = vecDir.Normalize(); @@ -144,45 +144,45 @@ int CZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, floa } // HACK HACK -- until we fix this. - if ( IsAlive() ) + if( IsAlive() ) PainSound(); return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -void CZombie :: PainSound( void ) +void CZombie::PainSound( void ) { - int pitch = 95 + RANDOM_LONG(0,9); + 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 ); + 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 ) +void CZombie::AlertSound( void ) { - int pitch = 95 + RANDOM_LONG(0,9); + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAlertSounds[ RANDOM_LONG( 0, ARRAYSIZE( pAlertSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); } -void CZombie :: IdleSound( void ) +void CZombie::IdleSound( void ) { - int pitch = 95 + RANDOM_LONG(0,9); + int pitch = 95 + RANDOM_LONG( 0, 9 ); // 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) ); + 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 ) +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) ); + 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 ) +void CZombie::HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { @@ -191,21 +191,21 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) // do stuff for this event. //ALERT( at_console, "Slash right!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) + if( pHurt ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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) ); + 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) ); + 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)) + if( RANDOM_LONG( 0, 1 ) ) AttackSound(); } break; @@ -214,20 +214,20 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) // do stuff for this event. //ALERT( at_console, "Slash left!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) + if( pHurt ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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) ); + 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) ); + 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)) + if( RANDOM_LONG( 0, 1 ) ) AttackSound(); } break; @@ -235,19 +235,19 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgBothSlash, DMG_SLASH ); - if ( pHurt ) + if( pHurt ) { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) + 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) ); + 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) ); + 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)) + if( RANDOM_LONG( 0, 1 ) ) AttackSound(); } break; @@ -260,17 +260,17 @@ void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CZombie :: Spawn() +void CZombie::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/zombie.mdl"); + SET_MODEL( ENT(pev), "models/zombie.mdl" ); UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - pev->solid = SOLID_SLIDEBOX; + pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.zombieHealth; + 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; @@ -282,53 +282,53 @@ void CZombie :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CZombie :: Precache() +void CZombie::Precache() { int i; - PRECACHE_MODEL("models/zombie.mdl"); + PRECACHE_MODEL( "models/zombie.mdl" ); - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); + 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( pAttackMissSounds ); i++ ) + PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[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( pIdleSounds ); i++ ) + PRECACHE_SOUND( (char *)pIdleSounds[i] ); - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[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( pPainSounds ); i++ ) + PRECACHE_SOUND( (char *)pPainSounds[i] ); } //========================================================= // AI Schedules Specific to this monster //========================================================= -int CZombie::IgnoreConditions ( void ) +int CZombie::IgnoreConditions( void ) { int iIgnore = CBaseMonster::IgnoreConditions(); - if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1)) + 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); + 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); +#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_Activity == ACT_SMALL_FLINCH ) || ( m_Activity == ACT_BIG_FLINCH ) ) { - if (m_flNextFlinch < gpGlobals->time) + if( m_flNextFlinch < gpGlobals->time ) m_flNextFlinch = gpGlobals->time + ZOMBIE_FLINCH_DELAY; } diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h index 4c6b2c97..b7f5343a 100644 --- a/game_shared/bitvec.h +++ b/game_shared/bitvec.h @@ -11,23 +11,21 @@ #pragma once #endif - #include #include class CBitVecAccessor { public: - CBitVecAccessor(unsigned long *pDWords, int iBit); + CBitVecAccessor( unsigned long *pDWords, int iBit ); - void operator=(int val); - operator unsigned long(); + void operator=( int val ); + operator unsigned long(); private: - unsigned long *m_pDWords; - int m_iBit; + unsigned long *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. @@ -35,124 +33,111 @@ template class CBitVec { public: - - CBitVec(); + CBitVec(); // Set all values to the specified value (0 or 1..) - void Init(int val = 0); + void Init( int val = 0 ); // Access the bits like an array. - CBitVecAccessor operator[](int i); + CBitVecAccessor operator[]( int i ); // Operations on other bit vectors. - CBitVec& operator=(CBitVec const &other); - bool operator==(CBitVec const &other); - bool operator!=(CBitVec const &other); + CBitVec& operator=( CBitVec const &other ); + bool operator==( CBitVec const &other ); + bool operator!=( CBitVec const &other ); // Get underlying dword representations of the bits. - int GetNumDWords(); - unsigned long GetDWord(int i); - void SetDWord(int i, unsigned long val); + int GetNumDWords(); + unsigned long GetDWord( int i ); + void SetDWord( int i, unsigned long val ); - int GetNumBits(); + int GetNumBits(); private: - - enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; - unsigned long m_DWords[NUM_DWORDS]; + enum + { + NUM_DWORDS = NUM_BITS / 32 + !!( NUM_BITS & 31 ) + }; + unsigned long m_DWords[NUM_DWORDS]; }; - - // ------------------------------------------------------------------------ // // CBitVecAccessor inlines. // ------------------------------------------------------------------------ // - inline CBitVecAccessor::CBitVecAccessor(unsigned long *pDWords, int iBit) { m_pDWords = pDWords; m_iBit = iBit; } - -inline void CBitVecAccessor::operator=(int val) +inline void CBitVecAccessor::operator=( int val ) { - if(val) - m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + if( val ) + m_pDWords[m_iBit >> 5] |= ( 1 << ( m_iBit & 31 ) ); else - m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); + m_pDWords[m_iBit >> 5] &= ~(unsigned long)( 1 << ( m_iBit & 31 ) ); } inline CBitVecAccessor::operator unsigned long() { - return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); + return m_pDWords[m_iBit >> 5] & ( 1 << ( m_iBit & 31 ) ); } - - // ------------------------------------------------------------------------ // // CBitVec inlines. // ------------------------------------------------------------------------ // - template inline int CBitVec::GetNumBits() { return NUM_BITS; } - template inline CBitVec::CBitVec() { - for(int i=0; i < NUM_DWORDS; i++) + for( int i = 0; i < NUM_DWORDS; i++ ) m_DWords[i] = 0; } - template -inline void CBitVec::Init(int val) +inline void CBitVec::Init( int val ) { - for(int i=0; i < GetNumBits(); i++) + for( int i = 0; i < GetNumBits(); i++ ) { - (*this)[i] = val; + ( *this )[i] = val; } } - template -inline CBitVec& CBitVec::operator=(CBitVec const &other) +inline CBitVec& CBitVec::operator=( CBitVec const &other ) { - memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); + memcpy( m_DWords, other.m_DWords, sizeof(m_DWords) ); return *this; } - template -inline CBitVecAccessor CBitVec::operator[](int i) +inline CBitVecAccessor CBitVec::operator[]( int i ) { - assert(i >= 0 && i < GetNumBits()); - return CBitVecAccessor(m_DWords, i); + assert( i >= 0 && i < GetNumBits() ); + return CBitVecAccessor( m_DWords, i ); } - template -inline bool CBitVec::operator==(CBitVec const &other) +inline bool CBitVec::operator==( CBitVec const &other ) { - for(int i=0; i < NUM_DWORDS; i++) - if(m_DWords[i] != other.m_DWords[i]) + 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) +inline bool CBitVec::operator!=( CBitVec const &other ) { - return !(*this == other); + return !( *this == other ); } - template inline int CBitVec::GetNumDWords() { @@ -160,20 +145,16 @@ inline int CBitVec::GetNumDWords() } template -inline unsigned long CBitVec::GetDWord(int i) +inline unsigned long CBitVec::GetDWord( int i ) { - assert(i >= 0 && i < NUM_DWORDS); + assert( i >= 0 && i < NUM_DWORDS ); return m_DWords[i]; } - template -inline void CBitVec::SetDWord(int i, unsigned long val) +inline void CBitVec::SetDWord( int i, unsigned long val ) { - assert(i >= 0 && i < NUM_DWORDS); + assert( i >= 0 && i < NUM_DWORDS ); m_DWords[i] = val; } - - #endif // BITVEC_H - diff --git a/game_shared/voice_gamemgr.cpp b/game_shared/voice_gamemgr.cpp index 829368a6..403d4320 100644 --- a/game_shared/voice_gamemgr.cpp +++ b/game_shared/voice_gamemgr.cpp @@ -1,6 +1,6 @@ //========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ // -// Purpose: +// Purpose: // // $NoKeywords: $ //============================================================================= @@ -13,11 +13,8 @@ #include "cbase.h" #include "player.h" - - #define UPDATE_INTERVAL 0.3 - // These are stored off as CVoiceGameMgr is created and deleted. CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. // (If it's zero, then the server reports that the game rules are saying the @@ -40,20 +37,19 @@ cvar_t sv_alltalk = {"sv_alltalk", "0"}; // ------------------------------------------------------------------------ // // Static helpers. // ------------------------------------------------------------------------ // - // Find a player with a case-insensitive name search. -static CBasePlayer* FindPlayerByName(const char *pTestName) +static CBasePlayer* FindPlayerByName( const char *pTestName ) { - for(int i=1; i <= gpGlobals->maxClients; i++) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); - if(pEdict) + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( i ); + if( pEdict ) { - CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); - if(pEnt && pEnt->IsPlayer()) - { - const char *pNetName = STRING(pEnt->pev->netname); - if(stricmp(pNetName, pTestName) == 0) + CBaseEntity *pEnt = CBaseEntity::Instance( pEdict ); + if( pEnt && pEnt->IsPlayer() ) + { + const char *pNetName = STRING( pEnt->pev->netname ); + if( stricmp( pNetName, pTestName ) == 0 ) { return (CBasePlayer*)pEnt; } @@ -79,37 +75,30 @@ static void VoiceServerDebug( char const *pFmt, ... ) ALERT( at_console, "%s", msg ); } - - // ------------------------------------------------------------------------ // // CVoiceGameMgr. // ------------------------------------------------------------------------ // - CVoiceGameMgr::CVoiceGameMgr() { m_UpdateInterval = 0; m_nMaxPlayers = 0; } - CVoiceGameMgr::~CVoiceGameMgr() { } - -bool CVoiceGameMgr::Init( - IVoiceGameMgrHelper *pHelper, - int maxClients) +bool CVoiceGameMgr::Init( IVoiceGameMgrHelper *pHelper, int maxClients ) { m_pHelper = pHelper; m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; - g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); + g_engfuncs.pfnPrecacheModel( "sprites/voiceicon.spr" ); - m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); + m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW * 4 * 2 ); m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); // register voice_serverdebug if it hasn't been registered already - if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) + if( !CVAR_GET_POINTER( "voice_serverdebug" ) ) CVAR_REGISTER( &voice_serverdebug ); if( !CVAR_GET_POINTER( "sv_alltalk" ) ) @@ -118,73 +107,70 @@ bool CVoiceGameMgr::Init( return true; } - -void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) +void CVoiceGameMgr::SetHelper( IVoiceGameMgrHelper *pHelper ) { m_pHelper = pHelper; } - -void CVoiceGameMgr::Update(double frametime) +void CVoiceGameMgr::Update( double frametime ) { // Only update periodically. m_UpdateInterval += frametime; - if(m_UpdateInterval < UPDATE_INTERVAL) + if( m_UpdateInterval < UPDATE_INTERVAL ) return; UpdateMasks(); } - -void CVoiceGameMgr::ClientConnected(edict_t *pEdict) +void CVoiceGameMgr::ClientConnected( edict_t *pEdict ) { - int index = ENTINDEX(pEdict) - 1; + int index = ENTINDEX( pEdict ) - 1; // Clear out everything we use for deltas on this guy. g_bWantModEnable[index] = true; - g_SentGameRulesMasks[index].Init(0); - g_SentBanMasks[index].Init(0); + g_SentGameRulesMasks[index].Init( 0 ); + g_SentBanMasks[index].Init( 0 ); } // Called to determine if the Receiver has muted (blocked) the Sender // Returns true if the receiver has blocked the sender -bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) +bool CVoiceGameMgr::PlayerHasBlockedPlayer( CBasePlayer *pReceiver, CBasePlayer *pSender ) { int iReceiverIndex, iSenderIndex; - if ( !pReceiver || !pSender ) + if( !pReceiver || !pSender ) return false; iReceiverIndex = pReceiver->entindex() - 1; - iSenderIndex = pSender->entindex() - 1; + iSenderIndex = pSender->entindex() - 1; - if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) + if( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) return false; return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); } -bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) +bool CVoiceGameMgr::ClientCommand( CBasePlayer *pPlayer, const char *cmd ) { int playerClientIndex = pPlayer->entindex() - 1; - if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) + if( playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers ) { VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); return true; } - bool bBan = stricmp(cmd, "vban") == 0; - if(bBan && CMD_ARGC() >= 2) + bool bBan = stricmp( cmd, "vban" ) == 0; + if( bBan && CMD_ARGC() >= 2 ) { - for(int i=1; i < CMD_ARGC(); i++) + for( int i = 1; i < CMD_ARGC(); i++ ) { unsigned long mask = 0; - sscanf(CMD_ARGV(i), "%lx", &mask); + sscanf( CMD_ARGV(i), "%lx", &mask ); - if(i <= VOICE_MAX_PLAYERS_DW) + if( i <= VOICE_MAX_PLAYERS_DW ) { VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); - g_BanMasks[playerClientIndex].SetDWord(i-1, mask); + g_BanMasks[playerClientIndex].SetDWord( i - 1, mask ); } else { @@ -196,12 +182,12 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) //UpdateMasks(); return true; } - else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) + else if( stricmp( cmd, "VModEnable" ) == 0 && CMD_ARGC() >= 2 ) { - VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); - g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi( CMD_ARGV( 1 ) ) ); + g_PlayerModEnable[playerClientIndex] = !!atoi( CMD_ARGV( 1 ) ); g_bWantModEnable[playerClientIndex] = false; - //UpdateMasks(); + //UpdateMasks(); return true; } else @@ -210,23 +196,22 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) } } - void CVoiceGameMgr::UpdateMasks() { m_UpdateInterval = 0; bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" ); - for(int iClient=0; iClient < m_nMaxPlayers; iClient++) + for( int iClient = 0; iClient < m_nMaxPlayers; iClient++ ) { - CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); - if(!pEnt || !pEnt->IsPlayer()) + CBaseEntity *pEnt = UTIL_PlayerByIndex( iClient + 1 ); + if( !pEnt || !pEnt->IsPlayer() ) continue; // Request the state of their "VModEnable" cvar. - if(g_bWantModEnable[iClient]) + if( g_bWantModEnable[iClient] ) { - MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); + MESSAGE_BEGIN( MSG_ONE, m_msgRequestState, NULL, pEnt->pev ); MESSAGE_END(); } @@ -236,11 +221,10 @@ void CVoiceGameMgr::UpdateMasks() if( g_PlayerModEnable[iClient] ) { // Build a mask of who they can hear based on the game rules. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + for( int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++ ) { - pEnt = UTIL_PlayerByIndex(iOtherClient+1); - if(pEnt && pEnt->IsPlayer() && - (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) + pEnt = UTIL_PlayerByIndex( iOtherClient + 1 ); + if( pEnt && pEnt->IsPlayer() && ( bAllTalk || m_pHelper->CanPlayerHearPlayer( pPlayer, (CBasePlayer*)pEnt ) ) ) { gameRulesMask[iOtherClient] = true; } @@ -248,27 +232,26 @@ void CVoiceGameMgr::UpdateMasks() } // If this is different from what the client has, send an update. - if(gameRulesMask != g_SentGameRulesMasks[iClient] || - g_BanMasks[iClient] != g_SentBanMasks[iClient]) + if( gameRulesMask != g_SentGameRulesMasks[iClient] || g_BanMasks[iClient] != g_SentBanMasks[iClient] ) { g_SentGameRulesMasks[iClient] = gameRulesMask; g_SentBanMasks[iClient] = g_BanMasks[iClient]; - MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); + MESSAGE_BEGIN( MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev ); int dw; - for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + for( dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++ ) { - WRITE_LONG(gameRulesMask.GetDWord(dw)); - WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); + WRITE_LONG( gameRulesMask.GetDWord( dw ) ); + WRITE_LONG( g_BanMasks[iClient].GetDWord( dw ) ); } MESSAGE_END(); } // Tell the engine. - for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + for( int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++ ) { bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; - g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); + g_engfuncs.pfnVoice_SetClientListening( iClient + 1, iOtherClient + 1, bCanHear ); } } } diff --git a/game_shared/voice_gamemgr.h b/game_shared/voice_gamemgr.h index de5f3cdc..bc2d26a8 100644 --- a/game_shared/voice_gamemgr.h +++ b/game_shared/voice_gamemgr.h @@ -9,71 +9,59 @@ #define VOICE_GAMEMGR_H #pragma once - #include "voice_common.h" - class CGameRules; class CBasePlayer; - class IVoiceGameMgrHelper { public: - virtual ~IVoiceGameMgrHelper() {} + virtual ~IVoiceGameMgrHelper() {} // 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; + virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker ) = 0; }; - // CVoiceGameMgr manages which clients can hear which other clients. class CVoiceGameMgr { public: - CVoiceGameMgr(); - virtual ~CVoiceGameMgr(); - - bool Init( - IVoiceGameMgrHelper *m_pHelper, - int maxClients - ); + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); - void SetHelper(IVoiceGameMgrHelper *pHelper); + bool Init( IVoiceGameMgrHelper *m_pHelper, int maxClients ); + + void SetHelper( IVoiceGameMgrHelper *pHelper ); // Updates which players can hear which other players. // If gameplay mode is DM, then only players within the PVS can hear each other. // If gameplay mode is teamplay, then only players on the same team can hear each other. // Player masks are always applied. - void Update(double frametime); + void Update( double frametime ); // Called when a new client connects (unsquelches its entity for everyone). - void ClientConnected(struct edict_s *pEdict); + void ClientConnected( struct edict_s *pEdict ); // Called on ClientCommand. Checks for the squelch and unsquelch commands. // Returns true if it handled the command. - bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); + bool ClientCommand( CBasePlayer *pPlayer, const char *cmd ); // Called to determine if the Receiver has muted (blocked) the Sender // Returns true if the receiver has blocked the sender - bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); - + bool PlayerHasBlockedPlayer( CBasePlayer *pReceiver, CBasePlayer *pSender ); private: - // Force it to update the client masks. - void UpdateMasks(); - + void UpdateMasks(); private: - int m_msgPlayerVoiceMask; - int m_msgRequestState; + int m_msgPlayerVoiceMask; + int m_msgRequestState; - IVoiceGameMgrHelper *m_pHelper; - int m_nMaxPlayers; - double m_UpdateInterval; // How long since the last update. + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. }; - - #endif // VOICE_GAMEMGR_H diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index 5e48ee54..4959d165 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -16,8 +16,7 @@ #define PM_DEBUG_H 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_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//PM_DEBUG_H \ No newline at end of file +#endif//PM_DEBUG_H diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index ea54e6db..321527f2 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -16,5 +16,4 @@ #define PM_INFO_H #define MAX_PHYSINFO_STRING 256 - -#endif//PM_INFO_H \ No newline at end of file +#endif//PM_INFO_H diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index 8e3b7792..cd1051d2 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -28,5 +28,4 @@ #define CHAR_TEX_COMPUTER 'P' #define CHAR_TEX_GLASS 'Y' #define CHAR_TEX_FLESH 'F' - -#endif//PM_MATERIALS_H \ No newline at end of file +#endif//PM_MATERIALS_H diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c index 8edaa3a4..3718dc63 100644 --- a/pm_shared/pm_math.c +++ b/pm_shared/pm_math.c @@ -21,147 +21,146 @@ // up / down #define PITCH 0 // left / right -#define YAW 1 +#define YAW 1 // fall over #define ROLL 2 #pragma warning(disable : 4244) -vec3_t vec3_origin = {0,0,0}; -int nanmask = 255<<23; +vec3_t vec3_origin = { 0,0,0 }; +int nanmask = 255 << 23; -float anglemod(float a) +float anglemod( float a ) { - a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + 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) +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); + float angle; + float sr, sp, sy, cr, cp, cy; - if (forward) + 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[0] = cp * cy; + forward[1] = cp * sy; forward[2] = -sp; } - if (right) + 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; + 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) + if( up ) { - up[0] = (cr*sp*cy+-sr*-sy); - up[1] = (cr*sp*sy+-sr*cy); - up[2] = cr*cp; + 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) +void AngleVectorsTranspose( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up ) { - float angle; - float sr, sp, sy, cr, cp, cy; + 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); + 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) + if( forward ) { - forward[0] = cp*cy; - forward[1] = (sr*sp*cy+cr*-sy); - forward[2] = (cr*sp*cy+-sr*-sy); + forward[0] = cp * cy; + forward[1] = ( sr * sp * cy + cr * -sy ); + forward[2] = ( cr * sp * cy + -sr * -sy ); } - if (right) + if( right ) { - right[0] = cp*sy; - right[1] = (sr*sp*sy+cr*cy); - right[2] = (cr*sp*sy+-sr*cy); + right[0] = cp * sy; + right[1] = ( sr * sp * sy + cr * cy ); + right[2] = ( cr * sp * sy + -sr * cy ); } - if (up) + if( up ) { - up[0] = -sp; - up[1] = sr*cp; - up[2] = cr*cp; + up[0] = -sp; + up[1] = sr * cp; + up[2] = cr * cp; } } - -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) +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); + float angle; + float sr, sp, sy, cr, cp, cy; - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; + 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][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] ) +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); + float angle; + float sr, sp, sy, cr, cp, cy; - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[0][1] = cp*sy; + 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[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; @@ -171,13 +170,13 @@ void NormalizeAngles( float *angles ) { int i; // Normalize angles - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - if ( angles[i] > 180.0 ) + if( angles[i] > 180.0 ) { angles[i] -= 360.0; } - else if ( angles[i] < -180.0 ) + else if( angles[i] < -180.0 ) { angles[i] += 360.0; } @@ -198,21 +197,21 @@ 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++ ) + for( i = 0; i < 3; i++ ) { ang1 = start[i]; ang2 = end[i]; d = ang2 - ang1; - if ( d > 180 ) + if( d > 180 ) { d -= 360; } - else if ( d < -180 ) + else if( d < -180 ) { d += 360; } @@ -222,7 +221,6 @@ void InterpolateAngles( float *start, float *end, float *output, float frac ) NormalizeAngles( output ); } - /* =================== @@ -236,144 +234,139 @@ float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ) float l1 = Length( v1 ); float l2 = Length( v2 ); - if ( !l1 || !l2 ) + if( !l1 || !l2 ) return 0.0f; - angle = acos( DotProduct( v1, v2 ) ) / (l1*l2); + angle = acos( DotProduct( v1, v2 ) ) / ( l1 * l2 ); angle = ( angle * 180.0f ) / M_PI; return angle; } - -void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out) +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]; + 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 VectorCompare( const vec3_t v1, const vec3_t v2 ) { - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) + 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) +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]; + vecc[0] = veca[0] + scale * vecb[0]; + vecc[1] = veca[1] + scale * vecb[1]; + vecc[2] = veca[2] + scale * vecb[2]; } - -vec_t _DotProduct (vec3_t v1, vec3_t v2) +vec_t _DotProduct( vec3_t v1, vec3_t v2 ) { - return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) +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]; + 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) +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]; + 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) +void _VectorCopy( vec3_t in, vec3_t out ) { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } -void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross) +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]; + 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]; } -double sqrt(double x); +double sqrt( double x ); -float Length(const vec3_t v) +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 + int i; + float length = 0.0f; + + for( i = 0; i < 3; i++ ) + length += v[i] * v[i]; + length = sqrt( length ); // FIXME return length; } -float Distance(const vec3_t v1, const vec3_t v2) +float Distance( const vec3_t v1, const vec3_t v2 ) { vec3_t d; - VectorSubtract(v2,v1,d); - return Length(d); + VectorSubtract( v2, v1, d ); + return Length( d ); } -float VectorNormalize (vec3_t v) +float VectorNormalize( vec3_t v ) { - float length, ilength; + float length, ilength; - length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); // FIXME + length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + length = sqrt( length ); // FIXME - if (length) + if( length ) { - ilength = 1/length; + ilength = 1 / length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } - - return length; + return length; } -void VectorInverse (vec3_t v) +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) +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; + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; } - -int Q_log2(int val) +int Q_log2( int val ) { - int answer=0; - while (val>>=1) + int answer = 0; + while( val >>= 1 ) answer++; return answer; } -void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up) +void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up ) { vec3_t tmp; - if (forward[0] == 0 && forward[1] == 0) + if( forward[0] == 0 && forward[1] == 0 ) { right[0] = 1; right[1] = 0; @@ -391,31 +384,30 @@ void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up) VectorNormalize( up ); } - void VectorAngles( const vec3_t forward, vec3_t angles ) { - float tmp, yaw, pitch; - - if (forward[1] == 0 && forward[0] == 0) + float tmp, yaw, pitch; + + if( forward[1] == 0 && forward[0] == 0 ) { yaw = 0; - if (forward[2] > 0) + if( forward[2] > 0 ) pitch = 90; else pitch = 270; } else { - yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); - if (yaw < 0) + 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) + 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; diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h index 6360b355..35fa5b4f 100644 --- a/pm_shared/pm_movevars.h +++ b/pm_shared/pm_movevars.h @@ -50,5 +50,4 @@ struct movevars_s }; extern movevars_t movevars; - -#endif \ No newline at end of file +#endif diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 9fa5accf..2ac023a2 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -29,7 +29,7 @@ #ifdef CLIENT_DLL // Spectator Mode - int iJumpSpectator; + int iJumpSpectator; float vJumpOrigin[3]; float vJumpAngles[3]; #endif @@ -38,15 +38,21 @@ static int pm_shared_initialized = 0; #pragma warning( disable : 4305 ) -typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; +typedef enum +{ + mod_brush, + mod_sprite, + mod_alias, + mod_studio +}modtype_t; playermove_t *pmove = NULL; typedef struct { - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; + int planenum; + short children[2]; // negative numbers are contents +}dclipnode_t; typedef struct mplane_s { @@ -55,31 +61,31 @@ typedef struct mplane_s byte type; // for texture axis selection and fast side tests byte signbits; // signx + signy<<1 + signz<<1 byte pad[2]; -} mplane_t; +}mplane_t; typedef struct hull_s { dclipnode_t *clipnodes; mplane_t *planes; - int firstclipnode; - int lastclipnode; + int firstclipnode; + int lastclipnode; vec3_t clip_mins; vec3_t clip_maxs; } hull_t; // Ducking time -#define TIME_TO_DUCK 0.4 +#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 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 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 @@ -96,7 +102,7 @@ typedef struct hull_s #define CHAR_TEX_GLASS 'Y' #define CHAR_TEX_FLESH 'F' -#define STEP_CONCRETE 0 // default step sound +#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 @@ -110,31 +116,31 @@ typedef struct hull_s #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_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_LONGJUMP_SPEED 350 // how fast we longjump // double to float warning #pragma warning(disable : 4244) #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) // up / down -#define PITCH 0 +#define PITCH 0 // left / right #define YAW 1 // fall over -#define ROLL 2 +#define ROLL 2 -#define MAX_CLIENTS 32 +#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_180 -11 +#define CONTENTS_CURRENT_270 -12 #define CONTENTS_CURRENT_UP -13 -#define CONTENTS_CURRENT_DOWN -14 +#define CONTENTS_CURRENT_DOWN -14 -#define CONTENTS_TRANSLUCENT -15 +#define CONTENTS_TRANSLUCENT -15 static vec3_t rgv3tStuckTable[54]; static int rgStuckLast[MAX_CLIENTS][2]; @@ -149,16 +155,16 @@ int g_onladder = 0; void PM_SwapTextures( int i, int j ) { char chTemp; - char szTemp[ CBTEXTURENAMEMAX ]; + char szTemp[CBTEXTURENAMEMAX]; - strcpy( szTemp, grgszTextureName[ i ] ); - chTemp = grgchTextureType[ i ]; + strcpy( szTemp, grgszTextureName[i] ); + chTemp = grgchTextureType[i]; - strcpy( grgszTextureName[ i ], grgszTextureName[ j ] ); - grgchTextureType[ i ] = grgchTextureType[ j ]; + strcpy( grgszTextureName[i], grgszTextureName[j] ); + grgchTextureType[i] = grgchTextureType[j]; - strcpy( grgszTextureName[ j ], szTemp ); - grgchTextureType[ j ] = chTemp; + strcpy( grgszTextureName[j], szTemp ); + grgchTextureType[j] = chTemp; } void PM_SortTextures( void ) @@ -167,11 +173,11 @@ void PM_SortTextures( void ) // int i, j; - for ( i = 0 ; i < gcTextures; i++ ) + for( i = 0; i < gcTextures; i++ ) { - for ( j = i + 1; j < gcTextures; j++ ) + for( j = i + 1; j < gcTextures; j++ ) { - if ( stricmp( grgszTextureName[ i ], grgszTextureName[ j ] ) > 0 ) + if( stricmp( grgszTextureName[i], grgszTextureName[j] ) > 0 ) { // Swap // @@ -189,62 +195,62 @@ void PM_InitTextureTypes() int fileSize, filePos = 0; static qboolean bTextureTypeInit = false; - if ( bTextureTypeInit ) + if( bTextureTypeInit ) return; - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); + memset(&( grgszTextureName[0][0] ), 0, CTEXTURESMAX * CBTEXTURENAMEMAX ); + memset( grgchTextureType, 0, CTEXTURESMAX ); gcTextures = 0; - memset(buffer, 0, 512); + memset( buffer, 0, 512 ); fileSize = pmove->COM_FileSize( "sound/materials.txt" ); pMemFile = pmove->COM_LoadFile( "sound/materials.txt", 5, NULL ); - if ( !pMemFile ) + if( !pMemFile ) return; filePos = 0; // for each line in the file... - while ( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX) ) + while( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX ) ) { // skip whitespace i = 0; - while(buffer[i] && isspace(buffer[i])) + while( buffer[i] && isspace( buffer[i] ) ) i++; - - if (!buffer[i]) + + if( !buffer[i] ) continue; // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) + if( buffer[i] == '/' || !isalpha( buffer[i] ) ) continue; // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); + grgchTextureType[gcTextures] = toupper( buffer[i++] ); // skip whitespace - while(buffer[i] && isspace(buffer[i])) + while( buffer[i] && isspace( buffer[i] ) ) i++; - if (!buffer[i]) + if( !buffer[i] ) continue; // get sentence name j = i; - while (buffer[j] && !isspace(buffer[j])) + while( buffer[j] && !isspace( buffer[j] ) ) j++; - if (!buffer[j]) + if( !buffer[j] ) continue; // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); + j = min( j, CBTEXTURENAMEMAX - 1 + i ); buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); + strcpy( &( grgszTextureName[gcTextures++][0] ), &( buffer[i] ) ); } // Must use engine to free since we are in a .dll - pmove->COM_FreeFile ( pMemFile ); + pmove->COM_FreeFile( pMemFile ); PM_SortTextures(); @@ -261,20 +267,20 @@ char PM_FindTextureType( char *name ) left = 0; right = gcTextures - 1; - while ( left <= right ) + while( left <= right ) { pivot = ( left + right ) / 2; - val = strnicmp( name, grgszTextureName[ pivot ], CBTEXTURENAMEMAX-1 ); - if ( val == 0 ) + val = strnicmp( name, grgszTextureName[pivot], CBTEXTURENAMEMAX - 1 ); + if( val == 0 ) { - return grgchTextureType[ pivot ]; + return grgchTextureType[pivot]; } - else if ( val > 0 ) + else if( val > 0 ) { left = pivot + 1; } - else if ( val < 0 ) + else if( val < 0 ) { right = pivot - 1; } @@ -291,158 +297,239 @@ void PM_PlayStepSound( int step, float fvol ) pmove->iStepLeft = !pmove->iStepLeft; - if ( !pmove->runfuncs ) + if( !pmove->runfuncs ) { return; } - - irand = pmove->RandomLong(0,1) + ( pmove->iStepLeft * 2 ); + + irand = pmove->RandomLong( 0, 1 ) + ( pmove->iStepLeft * 2 ); // FIXME mp_footsteps needs to be a movevar - if ( pmove->multiplayer && !pmove->movevars->footsteps ) + if( pmove->multiplayer && !pmove->movevars->footsteps ) return; VectorCopy( pmove->velocity, hvel ); hvel[2] = 0.0; - if ( pmove->multiplayer && ( !g_onladder && Length( hvel ) <= 220 ) ) + 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) + switch( step ) { default: case STEP_CONCRETE: - switch (irand) + 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; + 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; + 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) + 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; + 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; + 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) + 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; + 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; + 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) + 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; + 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; + 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) + 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; + 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; + 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) ) + if( !pmove->RandomLong( 0, 4 ) ) irand = 4; - switch(irand) + 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; + 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; + 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) + 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; + 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; + 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 ) + if( iSkipStep == 0 ) { iSkipStep++; break; } - if ( iSkipStep++ == 3 ) + if( iSkipStep++ == 3 ) { iSkipStep = 0; } - switch (irand) + 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; + 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; + 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) + 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; + 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; + 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) +int PM_MapTextureTypeStepType( char chTextureType ) { - switch (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; + 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; } } @@ -469,27 +556,27 @@ void PM_CatagorizeTextureType( void ) pmove->chtexturetype = CHAR_TEX_CONCRETE; pTextureName = pmove->PM_TraceTexture( pmove->onground, start, end ); - if ( !pTextureName ) + if( !pTextureName ) return; // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') + if( *pTextureName == '-' || *pTextureName == '+' ) pTextureName += 2; - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + if( *pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ' ) pTextureName++; // '}}' strcpy( pmove->sztexturename, pTextureName); - pmove->sztexturename[ CBTEXTURENAMEMAX - 1 ] = 0; - + pmove->sztexturename[CBTEXTURENAMEMAX - 1] = 0; + // get texture type pmove->chtexturetype = PM_FindTextureType( pmove->sztexturename ); } void PM_UpdateStepSound( void ) { - int fWalking; + int fWalking; float fvol; vec3_t knee; vec3_t feet; @@ -499,13 +586,13 @@ void PM_UpdateStepSound( void ) float velrun; float velwalk; float flduck; - int fLadder; + int fLadder; int step; - if ( pmove->flTimeStepSound > 0 ) + if( pmove->flTimeStepSound > 0 ) return; - if ( pmove->flags & FL_FROZEN ) + if( pmove->flags & FL_FROZEN ) return; PM_CatagorizeTextureType(); @@ -516,7 +603,7 @@ void PM_UpdateStepSound( void ) fLadder = ( pmove->movetype == MOVETYPE_FLY );// IsOnLadder(); // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!! - if ( ( pmove->flags & FL_DUCKING) || fLadder ) + 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 @@ -532,9 +619,7 @@ void PM_UpdateStepSound( void ) // 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 ) ) + if( ( fLadder || ( pmove->onground != -1 ) ) && ( Length( pmove->velocity ) > 0.0 ) && ( speed >= velwalk || !pmove->flTimeStepSound ) ) { fWalking = speed < velrun; @@ -542,25 +627,25 @@ void PM_UpdateStepSound( void ) VectorCopy( pmove->origin, knee ); VectorCopy( pmove->origin, feet ); - height = pmove->player_maxs[ pmove->usehull ][ 2 ] - pmove->player_mins[ pmove->usehull ][ 2 ]; + 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) + if( fLadder ) { step = STEP_LADDER; fvol = 0.35; pmove->flTimeStepSound = 350; } - else if ( pmove->PM_PointContents ( knee, NULL ) == CONTENTS_WATER ) + 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 ) + else if( pmove->PM_PointContents( feet, NULL ) == CONTENTS_WATER ) { step = STEP_SLOSH; fvol = fWalking ? 0.2 : 0.5; @@ -572,51 +657,45 @@ void PM_UpdateStepSound( void ) // get material type step = PM_MapTextureTypeStepType( pmove->chtexturetype ); - switch ( 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 ) + if( pmove->flags & FL_DUCKING ) { fvol *= 0.35; } @@ -632,22 +711,22 @@ 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) +qboolean PM_AddToTouched( pmtrace_t tr, vec3_t impactvelocity ) { int i; - for (i = 0; i < pmove->numtouch; i++) + for( i = 0; i < pmove->numtouch; i++ ) { - if (pmove->touchindex[i].ent == tr.ent) + if( pmove->touchindex[i].ent == tr.ent ) break; } - if (i != pmove->numtouch) // Already in list. + 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"); + if( pmove->numtouch >= MAX_PHYSENTS ) + pmove->Con_DPrintf( "Too many entities were touched!\n" ); pmove->touchindex[pmove->numtouch++] = tr; return true; @@ -660,36 +739,36 @@ PM_CheckVelocity See if the player has a bogus velocity value. ================ */ -void PM_CheckVelocity () +void PM_CheckVelocity() { - int i; + int i; // // bound velocity // - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++ ) { // See if it's bogus. - if (IS_NAN(pmove->velocity[i])) + if( IS_NAN( pmove->velocity[i] ) ) { - pmove->Con_Printf ("PM Got a NaN velocity %i\n", i); + pmove->Con_Printf( "PM Got a NaN velocity %i\n", i ); pmove->velocity[i] = 0; } - if (IS_NAN(pmove->origin[i])) + if( IS_NAN( pmove->origin[i] ) ) { - pmove->Con_Printf ("PM Got a NaN origin on %i\n", 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) + if( pmove->velocity[i] > pmove->movevars->maxvelocity ) { - pmove->Con_DPrintf ("PM Got a velocity too high on %i\n", i); + 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) + else if( pmove->velocity[i] < -pmove->movevars->maxvelocity ) { - pmove->Con_DPrintf ("PM Got a velocity too low on %i\n", i); + pmove->Con_DPrintf( "PM Got a velocity too low on %i\n", i ); pmove->velocity[i] = -pmove->movevars->maxvelocity; } } @@ -705,74 +784,73 @@ returns the blocked flags: 0x02 == step / wall ================== */ -int PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +int PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) { - float backoff; - float change; + float backoff; + float change; float angle; - int i, blocked; + int i, blocked; - angle = normal[ 2 ]; + 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; // - + 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; + backoff = DotProduct( in, normal ) * overbounce; - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++ ) { - change = normal[i]*backoff; + 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) + if( out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON ) out[i] = 0; } - + // Return blocking flags. return blocked; } -void PM_AddCorrectGravity () +void PM_AddCorrectGravity() { - float ent_gravity; + float ent_gravity; - if ( pmove->waterjumptime ) + if( pmove->waterjumptime ) return; - if (pmove->gravity) + 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] -= ( 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 () +void PM_FixupGravityVelocity() { - float ent_gravity; + float ent_gravity; - if ( pmove->waterjumptime ) + if( pmove->waterjumptime ) return; - if (pmove->gravity) + 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 ); + pmove->velocity[2] -= ( ent_gravity * pmove->movevars->gravity * pmove->frametime * 0.5 ); PM_CheckVelocity(); } @@ -784,90 +862,90 @@ PM_FlyMove The basic solid body movement clip that slides along multiple planes ============ */ -int PM_FlyMove (void) +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 + 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); - + 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]) + if( !pmove->velocity[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++) + 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 ); + 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) + if( trace.allsolid ) { // entity is trapped in another solid - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf("Trapped 4\n"); + 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) + if( trace.fraction > 0 ) { // actually covered some distance - VectorCopy (trace.endpos, pmove->origin); - VectorCopy (pmove->velocity, original_velocity); + 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) + if( trace.fraction == 1 ) break; // moved the entire distance - //if (!trace.ent) - // Sys_Error ("PM_PlayerTrace: !trace.ent"); + //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); + 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) + if( trace.plane.normal[2] > 0.7 ) { - blocked |= 1; // floor + 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]) + if( !trace.plane.normal[2] ) { - blocked |= 2; // step / wall - //Con_DPrintf("Blocked by %i\n", trace.ent); + blocked |= 2; // step / wall + //Con_DPrintf( "Blocked by %i\n", trace.ent ); } // Reduce amount of pmove->frametime left by total time left * fraction @@ -875,34 +953,32 @@ int PM_FlyMove (void) time_left -= time_left * trace.fraction; // Did we run out of planes to clip against? - if (numplanes >= MAX_CLIP_PLANES) + 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"); - + VectorCopy( vec3_origin, pmove->velocity ); + //Con_DPrintf( "Too many planes 4\n" ); break; } // Set up next clipping plane - VectorCopy (trace.plane.normal, planes[numplanes]); + 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 + // 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++ ) + for( i = 0; i < numplanes; i++ ) { - if ( planes[i][2] > 0.7 ) - {// floor or slope + 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) ); + else + PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + pmove->movevars->bounce * ( 1 - pmove->friction ) ); } VectorCopy( new_velocity, pmove->velocity ); @@ -910,61 +986,56 @@ int PM_FlyMove (void) } else { - for (i=0 ; ivelocity, - 1); - for (j=0 ; jvelocity, 1 ); + for( j = 0; j < numplanes; j++ ) + if( j != i ) { // Are we now moving against this plane? - if (DotProduct (pmove->velocity, planes[j]) < 0) + if( DotProduct( pmove->velocity, planes[j] ) < 0 ) break; // not ok } - if (j == numplanes) // Didn't have to clip, so we're 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. - ; + 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) + if( numplanes != 2 ) { - //Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf("Trapped 4\n"); - + //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 ); + 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) + // + // 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); + //Con_DPrintf( "Back\n" ); + VectorCopy( vec3_origin, pmove->velocity ); break; } } } - if ( allFraction == 0 ) + if( allFraction == 0 ) { - VectorCopy (vec3_origin, pmove->velocity); + VectorCopy( vec3_origin, pmove->velocity ); //Con_DPrintf( "Don't stick\n" ); } @@ -976,38 +1047,38 @@ int PM_FlyMove (void) PM_Accelerate ============== */ -void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) +void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { - int i; - float addspeed, accelspeed, currentspeed; + int i; + float addspeed, accelspeed, currentspeed; // Dead player's don't accelerate - if (pmove->dead) + if( pmove->dead ) return; // If waterjumping, don't accelerate - if (pmove->waterjumptime) + if( pmove->waterjumptime ) return; // See if we are changing direction a bit - currentspeed = DotProduct (pmove->velocity, wishdir); + 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) + if( addspeed <= 0 ) return; // Determine amount of accleration. accelspeed = accel * pmove->frametime * wishspeed * pmove->friction; // Cap at addspeed - if (accelspeed > addspeed) + if( accelspeed > addspeed ) accelspeed = addspeed; // Adjust velocity. - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++ ) { pmove->velocity[i] += accelspeed * wishdir[i]; } @@ -1020,17 +1091,17 @@ PM_WalkMove Only used by players. Moves along the ground when player is a MOVETYPE_WALK. ====================== */ -void PM_WalkMove () +void PM_WalkMove() { - int clip; - int oldonground; + int clip; + int oldonground; int i; - vec3_t wishvel; - float spd; - float fmove, smove; - vec3_t wishdir; - float wishspeed; + vec3_t wishvel; + float spd; + float fmove, smove; + vec3_t wishdir; + float wishspeed; vec3_t dest, start; vec3_t original, originalvel; @@ -1038,147 +1109,146 @@ void PM_WalkMove () 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); // + 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; - 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); + VectorCopy( wishvel, wishdir ); // Determine maginitude of speed of move + wishspeed = VectorNormalize( wishdir ); -// -// Clamp to server defined max speed -// - if (wishspeed > pmove->maxspeed) + // + // Clamp to server defined max speed + // + if( wishspeed > pmove->maxspeed ) { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + VectorScale( wishvel, pmove->maxspeed / wishspeed, wishvel ); wishspeed = pmove->maxspeed; } // Set pmove velocity pmove->velocity[2] = 0; - PM_Accelerate (wishdir, wishspeed, pmove->movevars->accelerate); + 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 ); + VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity ); spd = Length( pmove->velocity ); - if (spd < 1.0f) + 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]) + //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; + // 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 ); + 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) + if( trace.fraction == 1 ) { - VectorCopy (trace.endpos, pmove->origin); + VectorCopy( trace.endpos, pmove->origin ); return; } - if (oldonground == -1 && // Don't walk up stairs if not on ground. - pmove->waterlevel == 0) + // Don't walk up stairs if not on ground. + if( oldonground == -1 && pmove->waterlevel == 0 ) return; - if (pmove->waterjumptime) // If we are jumping out of water, don't do anything more. + 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. + VectorCopy( pmove->origin, original ); // Save out original pos & + VectorCopy( pmove->velocity, originalvel ); // velocity. // Slide move - clip = PM_FlyMove (); + clip = PM_FlyMove(); // Copy the results out - VectorCopy (pmove->origin , down); - VectorCopy (pmove->velocity, downvel); + VectorCopy( pmove->origin, down ); + VectorCopy( pmove->velocity, downvel ); // Reset original values. - VectorCopy (original, pmove->origin); + VectorCopy( original, pmove->origin ); - VectorCopy (originalvel, pmove->velocity); + VectorCopy( originalvel, pmove->velocity ); // Start out up one stair height - VectorCopy (pmove->origin, dest); + VectorCopy( pmove->origin, dest ); dest[2] += pmove->movevars->stepsize; - - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); + + 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) + if( !trace.startsolid && !trace.allsolid ) { - VectorCopy (trace.endpos, pmove->origin); + VectorCopy( trace.endpos, pmove->origin ); } -// slide move the rest of the way. - clip = PM_FlyMove (); + // slide move the rest of the way. + clip = PM_FlyMove(); -// Now try going back down from the end point -// press down the stepheight - VectorCopy (pmove->origin, dest); + // 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 ); + + 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) + 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) + if( !trace.startsolid && !trace.allsolid ) { - VectorCopy (trace.endpos, pmove->origin); + VectorCopy( trace.endpos, pmove->origin ); } // Copy this origion to up. - VectorCopy (pmove->origin, pmove->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]); + 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) + if( downdist > updist ) { usedown: - VectorCopy (down , pmove->origin); - VectorCopy (downvel, pmove->velocity); + VectorCopy( down, pmove->origin ); + VectorCopy( downvel, pmove->velocity ); } else // copy z value from slide move pmove->velocity[2] = downvel[2]; - } /* @@ -1188,46 +1258,46 @@ PM_Friction Handles both ground friction and water friction ================== */ -void PM_Friction (void) +void PM_Friction( void ) { - float *vel; - float speed, newspeed, control; - float friction; - float drop; + 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) + 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]); - + speed = sqrt( vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2] ); + // If too slow, return - if (speed < 0.1f) + if( speed < 0.1f ) { return; } drop = 0; -// apply ground friction - if (pmove->onground != -1) // On an entity that is the ground + // 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[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 ); + trace = pmove->PM_PlayerTrace( start, stop, PM_NORMAL, -1 ); - if (trace.fraction == 1.0) + if( trace.fraction == 1.0 ) friction = pmove->movevars->friction*pmove->movevars->edgefriction; else friction = pmove->movevars->friction; @@ -1239,19 +1309,18 @@ void PM_Friction (void) // 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; + control = ( speed < pmove->movevars->stopspeed ) ? pmove->movevars->stopspeed : speed; // Add the amount to t'he drop amount. - drop += control*friction*pmove->frametime; + drop += control * friction * pmove->frametime; } -// apply water friction -// if (pmove->waterlevel) -// drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime; + // apply water friction + //if( pmove->waterlevel ) + // drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime; -// scale the velocity + // scale the velocity newspeed = speed - drop; - if (newspeed < 0) + if( newspeed < 0 ) newspeed = 0; // Determine proportion of old speed we are using. @@ -1265,39 +1334,39 @@ void PM_Friction (void) VectorCopy( newvel, pmove->velocity ); } -void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) +void PM_AirAccelerate( vec3_t wishdir, float wishspeed, float accel ) { - int i; - float addspeed, accelspeed, currentspeed, wishspd = wishspeed; - - if (pmove->dead) + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if( pmove->dead ) return; - if (pmove->waterjumptime) + if( pmove->waterjumptime ) return; // Cap speed - //wishspd = VectorNormalize (pmove->wishveloc); - - if (wishspd > 30) + //wishspd = VectorNormalize( pmove->wishveloc ); + + if( wishspd > 30 ) wishspd = 30; // Determine veer amount - currentspeed = DotProduct (pmove->velocity, wishdir); + currentspeed = DotProduct( pmove->velocity, wishdir ); // See how much to add addspeed = wishspd - currentspeed; // If not adding any, done. - if (addspeed <= 0) + if( addspeed <= 0 ) return; // Determine acceleration speed after acceleration accelspeed = accel * wishspeed * pmove->frametime * pmove->friction; // Cap it - if (accelspeed > addspeed) + if( accelspeed > addspeed ) accelspeed = addspeed; - + // Adjust pmove vel. - for (i=0 ; i<3 ; i++) + for( i = 0; i < 3; i++ ) { - pmove->velocity[i] += accelspeed*wishdir[i]; + pmove->velocity[i] += accelspeed * wishdir[i]; } } @@ -1307,54 +1376,55 @@ PM_WaterMove =================== */ -void PM_WaterMove (void) +void PM_WaterMove( void ) { - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - vec3_t start, dest; - vec3_t temp; - pmtrace_t trace; + 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; + 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) + 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); + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); // Cap speed. - if (wishspeed > pmove->maxspeed) + if( wishspeed > pmove->maxspeed ) { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + 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) + 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) + if( newspeed < 0 ) newspeed = 0; - VectorScale (pmove->velocity, newspeed/speed, pmove->velocity); + VectorScale( pmove->velocity, newspeed / speed, pmove->velocity ); } else newspeed = 0; @@ -1362,40 +1432,38 @@ void PM_WaterMove (void) // // water acceleration // - if ( wishspeed < 0.1f ) + if( wishspeed < 0.1f ) { return; } addspeed = wishspeed - newspeed; - if (addspeed > 0) + if( addspeed > 0 ) { - - VectorNormalize(wishvel); + VectorNormalize( wishvel ); accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction; - if (accelspeed > addspeed) + if( accelspeed > addspeed ) accelspeed = addspeed; - for (i = 0; i < 3; i++) + 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); + 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? + 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); + VectorCopy( trace.endpos, pmove->origin ); return; } - - // Try moving straight along out normal path. - PM_FlyMove (); -} + // Try moving straight along out normal path. + PM_FlyMove(); +} /* =================== @@ -1403,50 +1471,50 @@ PM_AirMove =================== */ -void PM_AirMove (void) +void PM_AirMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; + 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; + pmove->right[2] = 0; // Renormalize - VectorNormalize (pmove->forward); - VectorNormalize (pmove->right); + VectorNormalize( pmove->forward ); + VectorNormalize( pmove->right ); // Determine x and y parts of velocity - for (i=0 ; i<2 ; i++) + for( i = 0; i < 2; i++ ) { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove; } // Zero out z part of velocity - wishvel[2] = 0; + wishvel[2] = 0; // Determine maginitude of speed of move - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); // Clamp to server defined max speed - if (wishspeed > pmove->maxspeed) + if( wishspeed > pmove->maxspeed ) { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + VectorScale( wishvel, pmove->maxspeed/wishspeed, wishvel ); wishspeed = pmove->maxspeed; } - PM_AirAccelerate (wishdir, wishspeed, pmove->movevars->airaccelerate); + PM_AirAccelerate( wishdir, wishspeed, pmove->movevars->airaccelerate ); // Add in any base velocity to the current velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); + VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity ); - PM_FlyMove (); + PM_FlyMove(); } qboolean PM_InWater( void ) @@ -1461,19 +1529,19 @@ PM_CheckWater Sets pmove->waterlevel and pmove->watertype values. ============= */ -qboolean PM_CheckWater () +qboolean PM_CheckWater() { - vec3_t point; - int cont; - int truecont; - float height; - float heightover2; + 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[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; @@ -1481,7 +1549,7 @@ qboolean PM_CheckWater () // 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 ) + if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) { // Set water type pmove->watertype = cont; @@ -1489,14 +1557,14 @@ qboolean PM_CheckWater () // We are at least at level one pmove->waterlevel = 1; - height = (pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2]); + 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 ); + cont = pmove->PM_PointContents( point, NULL ); // If that point is also under water... - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) + if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) { // Set a higher water level. pmove->waterlevel = 2; @@ -1504,23 +1572,26 @@ qboolean PM_CheckWater () // 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 ) + 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 ) ) + 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} + {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); + VectorMA( pmove->basevelocity, 50.0*pmove->waterlevel, current_table[CONTENTS_CURRENT_0 - truecont], pmove->basevelocity ); } } @@ -1532,10 +1603,10 @@ qboolean PM_CheckWater () PM_CatagorizePosition ============= */ -void PM_CatagorizePosition (void) +void PM_CatagorizePosition( void ) { - vec3_t point; - pmtrace_t tr; + vec3_t point; + pmtrace_t tr; // if the player hull point one unit down is solid, the player // is on ground @@ -1553,34 +1624,34 @@ void PM_CatagorizePosition (void) point[1] = pmove->origin[1]; point[2] = pmove->origin[2] - 2; - if (pmove->velocity[2] > 180) // Shooting up really fast. Definitely not on ground. + 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 ); + 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) + 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) + 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); + 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. + if( tr.ent > 0 ) // So signal that we are touching something. { - PM_AddToTouched(tr, pmove->velocity); + PM_AddToTouched( tr, pmove->velocity ); } } } @@ -1593,18 +1664,18 @@ 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) +int PM_GetRandomStuckOffsets( int nIndex, int server, vec3_t offset ) { - // Last time we did a full + // Last time we did a full int idx; idx = rgStuckLast[nIndex][server]++; - VectorCopy(rgv3tStuckTable[idx % 54], offset); + VectorCopy( rgv3tStuckTable[idx % 54], offset ); - return (idx % 54); + return ( idx % 54 ); } -void PM_ResetStuckOffsets(int nIndex, int server) +void PM_ResetStuckOffsets( int nIndex, int server ) { rgStuckLast[nIndex][server] = 0; } @@ -1620,68 +1691,65 @@ 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) +int PM_CheckStuck( void ) { - vec3_t base; - vec3_t offset; - vec3_t test; - int hitent; - int idx; - float fTime; + 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 ) + hitent = pmove->PM_TestPlayerPosition( pmove->origin, &traceresult ); + if( hitent == -1 ) { PM_ResetStuckOffsets( pmove->player_index, pmove->server ); return 0; } - VectorCopy (pmove->origin, base); + VectorCopy( pmove->origin, base ); - // + // // Deal with precision error in network. - // - if (!pmove->server) + // + if( !pmove->server ) { // World or BSP model - if ( ( hitent == 0 ) || - ( pmove->physents[hitent].model != NULL ) ) + 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); + i = PM_GetRandomStuckOffsets( pmove->player_index, pmove->server, offset ); - VectorAdd(base, offset, test); - if (pmove->PM_TestPlayerPosition (test, &traceresult ) == -1) + VectorAdd( base, offset, test ); + if( pmove->PM_TestPlayerPosition( test, &traceresult ) == -1 ) { PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - - VectorCopy ( test, pmove->origin ); + + VectorCopy( test, pmove->origin ); return 0; } nReps++; - } while (nReps < 54); + } while( nReps < 54 ); } } // Only an issue on the client. - - if (pmove->server) + if( pmove->server ) idx = 0; else idx = 1; fTime = pmove->Sys_FloatTime(); // Too soon? - if (rgStuckCheckTime[pmove->player_index][idx] >= - ( fTime - PM_CHECKSTUCK_MINTIME ) ) + if( rgStuckCheckTime[pmove->player_index][idx] >= ( fTime - PM_CHECKSTUCK_MINTIME ) ) { return 1; } @@ -1689,41 +1757,41 @@ int PM_CheckStuck (void) pmove->PM_StuckTouch( hitent, &traceresult ); - i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); + i = PM_GetRandomStuckOffsets( pmove->player_index, pmove->server, offset ); - VectorAdd(base, offset, test); - if ( ( hitent = pmove->PM_TestPlayerPosition ( test, NULL ) ) == -1 ) + VectorAdd( base, offset, test ); + if( ( hitent = pmove->PM_TestPlayerPosition( test, NULL ) ) == -1 ) { - //Con_DPrintf("Nudged\n"); + //Con_DPrintf( "Nudged\n" ); PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - VectorCopy ( test, pmove->origin ); + 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 ) ) + 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( z = 0; z <= zminmax; z += zstep ) { - for ( x = -xyminmax; x <= xyminmax; x += xystep ) + for( x = -xyminmax; x <= xyminmax; x += xystep ) { - for ( y = -xyminmax; y <= xyminmax; y += 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 ) + if( pmove->PM_TestPlayerPosition( test, NULL ) == -1 ) { VectorCopy( test, pmove->origin ); return 0; @@ -1733,7 +1801,7 @@ int PM_CheckStuck (void) } } - //VectorCopy (base, pmove->origin); + //VectorCopy( base, pmove->origin ); return 1; } @@ -1743,27 +1811,26 @@ int PM_CheckStuck (void) PM_SpectatorMove =============== */ -void PM_SpectatorMove (void) +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; + 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) + if( pmove->iuser1 == OBS_ROAMING ) { - #ifdef CLIENT_DLL // jump only in roaming mode - if ( iJumpSpectator ) + if( iJumpSpectator ) { VectorCopy( vJumpOrigin, pmove->origin ); VectorCopy( vJumpAngles, pmove->angles ); @@ -1771,70 +1838,69 @@ void PM_SpectatorMove (void) iJumpSpectator = 0; return; } - #endif +#endif // Move around in normal spectator method - - speed = Length (pmove->velocity); - if (speed < 1) + speed = Length( pmove->velocity ); + if( speed < 1 ) { - VectorCopy (vec3_origin, pmove->velocity) + VectorCopy( vec3_origin, pmove->velocity ) } else { drop = 0; - friction = pmove->movevars->friction*1.5; // extra friction + friction = pmove->movevars->friction * 1.5; // extra friction control = speed < pmove->movevars->stopspeed ? pmove->movevars->stopspeed : speed; - drop += control*friction*pmove->frametime; + drop += control * friction*pmove->frametime; // scale the velocity newspeed = speed - drop; - if (newspeed < 0) + if( newspeed < 0 ) newspeed = 0; newspeed /= speed; - VectorScale (pmove->velocity, newspeed, pmove->velocity); + 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++) + VectorNormalize( pmove->forward ); + VectorNormalize( pmove->right ); + + for( i = 0; i < 3; i++ ) { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove; } wishvel[2] += pmove->cmd.upmove; - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); // // clamp to server defined max speed // - if (wishspeed > pmove->movevars->spectatormaxspeed) + if( wishspeed > pmove->movevars->spectatormaxspeed ) { - VectorScale (wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel); + VectorScale( wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel ); wishspeed = pmove->movevars->spectatormaxspeed; } - currentspeed = DotProduct(pmove->velocity, wishdir); + currentspeed = DotProduct( pmove->velocity, wishdir ); addspeed = wishspeed - currentspeed; - if (addspeed <= 0) + if( addspeed <= 0 ) return; - accelspeed = pmove->movevars->accelerate*pmove->frametime*wishspeed; - if (accelspeed > addspeed) + accelspeed = pmove->movevars->accelerate * pmove->frametime * wishspeed; + if( accelspeed > addspeed ) accelspeed = addspeed; - - for (i=0 ; i<3 ; i++) - pmove->velocity[i] += accelspeed*wishdir[i]; + + for( i = 0; i < 3; i++ ) + pmove->velocity[i] += accelspeed*wishdir[i]; // move - VectorMA (pmove->origin, pmove->frametime, pmove->velocity, pmove->origin); + VectorMA( pmove->origin, pmove->frametime, pmove->velocity, pmove->origin ); } else { @@ -1843,17 +1909,17 @@ void PM_SpectatorMove (void) int target; // no valid target ? - if ( pmove->iuser2 <= 0) + if( pmove->iuser2 <= 0 ) return; // Find the client this player's targeting - for (target = 0; target < pmove->numphysent; target++) + for( target = 0; target < pmove->numphysent; target++ ) { - if ( pmove->physents[target].info == pmove->iuser2 ) + if( pmove->physents[target].info == pmove->iuser2 ) break; } - if (target == pmove->numphysent) + if( target == pmove->numphysent ) return; // use targets position as own origin for PVS @@ -1886,20 +1952,20 @@ float PM_SplineFraction( float value, float scale ) void PM_FixPlayerCrouchStuck( int direction ) { - int hitent; + int hitent; int i; vec3_t test; - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) + hitent = pmove->PM_TestPlayerPosition( pmove->origin, NULL ); + if( hitent == -1 ) return; - - VectorCopy( pmove->origin, test ); - for ( i = 0; i < 36; i++ ) + + VectorCopy( pmove->origin, test ); + for( i = 0; i < 36; i++ ) { pmove->origin[2] += direction; - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) + hitent = pmove->PM_TestPlayerPosition( pmove->origin, NULL ); + if( hitent == -1 ) return; } @@ -1914,23 +1980,23 @@ void PM_UnDuck( void ) VectorCopy( pmove->origin, newOrigin ); - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { - for ( i = 0; i < 3; i++ ) + 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 ) + 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 ) + 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" ); @@ -1942,7 +2008,7 @@ void PM_UnDuck( void ) pmove->bInDuck = false; pmove->view_ofs[2] = VEC_VIEW; pmove->flDuckTime = 0; - + VectorCopy( newOrigin, pmove->origin ); // Recatagorize position since ducking can change origin @@ -1956,13 +2022,13 @@ void PM_Duck( void ) 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" + 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" - int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; - int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; + int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; + int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; - if ( pmove->cmd.buttons & IN_DUCK ) + if( pmove->cmd.buttons & IN_DUCK ) { pmove->oldbuttons |= IN_DUCK; } @@ -1972,41 +2038,40 @@ void PM_Duck( void ) } // Prevent ducking if the iuser3 variable is set - if ( pmove->iuser3 || pmove->dead ) + if( pmove->iuser3 || pmove->dead ) { // Try to unduck - if ( pmove->flags & FL_DUCKING ) + if( pmove->flags & FL_DUCKING ) { PM_UnDuck(); } return; } - if ( pmove->flags & FL_DUCKING ) + if( pmove->flags & FL_DUCKING ) { pmove->cmd.forwardmove *= 0.333; - pmove->cmd.sidemove *= 0.333; - pmove->cmd.upmove *= 0.333; + pmove->cmd.sidemove *= 0.333; + pmove->cmd.upmove *= 0.333; } - if ( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) + if( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) { - if ( pmove->cmd.buttons & IN_DUCK ) + if( pmove->cmd.buttons & IN_DUCK ) { - if ( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) ) + if( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) ) { // Use 1 second so super long jump will work pmove->flDuckTime = 1000; - pmove->bInDuck = true; + pmove->bInDuck = true; } time = max( 0.0, ( 1.0 - (float)pmove->flDuckTime / 1000.0 ) ); - - if ( pmove->bInDuck ) + + 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 ) ) + if( ( (float)pmove->flDuckTime / 1000.0 <= ( 1.0 - TIME_TO_DUCK ) ) || ( pmove->onground == -1 ) ) { pmove->usehull = 1; pmove->view_ofs[2] = VEC_DUCK_VIEW; @@ -2014,9 +2079,9 @@ void PM_Duck( void ) pmove->bInDuck = false; // HACKHACK - Fudge for collision bug - no time to fix this properly - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { - for ( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { pmove->origin[i] -= ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); } @@ -2029,11 +2094,11 @@ void PM_Duck( void ) } else { - float fMore = (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); + 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)); + pmove->view_ofs[2] = ( ( VEC_DUCK_VIEW - fMore ) * duckFraction ) + ( VEC_VIEW * ( 1 - duckFraction ) ); } } } @@ -2047,13 +2112,13 @@ void PM_Duck( void ) void PM_LadderMove( physent_t *pLadder ) { - vec3_t ladderCenter; - trace_t trace; - qboolean onFloor; - vec3_t floor; - vec3_t modelmins, modelmaxs; + vec3_t ladderCenter; + trace_t trace; + qboolean onFloor; + vec3_t floor; + vec3_t modelmins, modelmaxs; - if ( pmove->movetype == MOVETYPE_NOCLIP ) + if( pmove->movetype == MOVETYPE_NOCLIP ) return; pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs ); @@ -2064,67 +2129,63 @@ void PM_LadderMove( physent_t *pLadder ) 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 ) + 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 ) + if( trace.fraction != 1.0 ) { float forward = 0, right = 0; vec3_t vpn, v_right; AngleVectors( pmove->angles, vpn, v_right, NULL ); - if ( pmove->cmd.buttons & IN_BACK ) + if( pmove->cmd.buttons & IN_BACK ) forward -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_FORWARD ) + if( pmove->cmd.buttons & IN_FORWARD ) forward += MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVELEFT ) + if( pmove->cmd.buttons & IN_MOVELEFT ) right -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVERIGHT ) + if( pmove->cmd.buttons & IN_MOVERIGHT ) right += MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_JUMP ) + if( pmove->cmd.buttons & IN_JUMP ) { pmove->movetype = MOVETYPE_WALK; VectorScale( trace.plane.normal, 270, pmove->velocity ); } else { - if ( forward != 0 || right != 0 ) + 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); + //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); + //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(); + // 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 ); @@ -2135,11 +2196,11 @@ void PM_LadderMove( physent_t *pLadder ) // 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 + 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); + //pev->velocity = lateral - ( CrossProduct( trace.vecPlaneNormal, perp ) * normal ); } else { @@ -2151,29 +2212,29 @@ void PM_LadderMove( physent_t *pLadder ) physent_t *PM_Ladder( void ) { - int i; - physent_t *pe; - hull_t *hull; - int num; - vec3_t test; + int i; + physent_t *pe; + hull_t *hull; + int num; + vec3_t test; - for ( i = 0; i < pmove->nummoveent; i++ ) + 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 ) + + 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); + VectorSubtract( pmove->origin, test, test ); // Test the player's hull for intersection with this model - if ( pmove->PM_HullPointContents (hull, num, test) == CONTENTS_EMPTY) + if( pmove->PM_HullPointContents( hull, num, test ) == CONTENTS_EMPTY ) continue; - + return pe; } } @@ -2181,21 +2242,18 @@ physent_t *PM_Ladder( void ) return NULL; } - - -void PM_WaterJump (void) +void PM_WaterJump( void ) { - if ( pmove->waterjumptime > 10000 ) + if( pmove->waterjumptime > 10000 ) { pmove->waterjumptime = 10000; } - if ( !pmove->waterjumptime ) + if( !pmove->waterjumptime ) return; pmove->waterjumptime -= pmove->cmd.msec; - if ( pmove->waterjumptime < 0 || - !pmove->waterlevel ) + if( pmove->waterjumptime < 0 || !pmove->waterlevel ) { pmove->waterjumptime = 0; pmove->flags &= ~FL_WATERJUMP; @@ -2211,17 +2269,17 @@ PM_AddGravity ============ */ -void PM_AddGravity () +void PM_AddGravity() { - float ent_gravity; + float ent_gravity; - if (pmove->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] -= ( ent_gravity * pmove->movevars->gravity * pmove->frametime ); pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; pmove->basevelocity[2] = 0; PM_CheckVelocity(); @@ -2233,22 +2291,21 @@ PM_PushEntity Does not change the entities velocity at all ============ */ -pmtrace_t PM_PushEntity (vec3_t push) +pmtrace_t PM_PushEntity( vec3_t push ) { - pmtrace_t trace; - vec3_t end; - - VectorAdd (pmove->origin, push, end); + pmtrace_t trace; + vec3_t end; - trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); - - VectorCopy (trace.endpos, pmove->origin); + 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) + if( trace.fraction < 1.0 && !trace.allsolid ) { - PM_AddToTouched(trace, pmove->velocity); + PM_AddToTouched( trace, pmove->velocity ); } return trace; @@ -2264,75 +2321,71 @@ Dead player flying through air., e.g. void PM_Physics_Toss() { pmtrace_t trace; - vec3_t move; - float backoff; + vec3_t move; + float backoff; PM_CheckWater(); - if (pmove->velocity[2] > 0) + if( pmove->velocity[2] > 0 ) pmove->onground = -1; // If on ground and not moving, return. - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { - if (VectorCompare(pmove->basevelocity, vec3_origin) && - VectorCompare(pmove->velocity, vec3_origin)) + if( VectorCompare( pmove->basevelocity, vec3_origin ) && VectorCompare( pmove->velocity, vec3_origin ) ) return; } - PM_CheckVelocity (); + PM_CheckVelocity(); -// add gravity - if ( pmove->movetype != MOVETYPE_FLY && - pmove->movetype != MOVETYPE_BOUNCEMISSILE && - pmove->movetype != MOVETYPE_FLYMISSILE ) + // add gravity + if( pmove->movetype != MOVETYPE_FLY && pmove->movetype != MOVETYPE_BOUNCEMISSILE && pmove->movetype != MOVETYPE_FLYMISSILE ) PM_AddGravity (); -// move origin + // 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); + VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity ); - trace = PM_PushEntity (move); // Should this clear basevelocity + 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) + if( trace.allsolid ) { // entity is trapped in another solid pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); + VectorCopy( vec3_origin, pmove->velocity ); return; } - if (trace.fraction == 1) + if( trace.fraction == 1 ) { PM_CheckWater(); return; } - - if (pmove->movetype == MOVETYPE_BOUNCE) + if( pmove->movetype == MOVETYPE_BOUNCE ) backoff = 2.0 - pmove->friction; - else if (pmove->movetype == MOVETYPE_BOUNCEMISSILE) + else if( pmove->movetype == MOVETYPE_BOUNCEMISSILE ) backoff = 2.0; else backoff = 1; - PM_ClipVelocity (pmove->velocity, trace.plane.normal, pmove->velocity, backoff); + PM_ClipVelocity( pmove->velocity, trace.plane.normal, pmove->velocity, backoff ); // stop if on ground - if (trace.plane.normal[2] > 0.7) - { + if( trace.plane.normal[2] > 0.7 ) + { float vel; vec3_t base; VectorClear( base ); - if (pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime) + if( pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime ) { // we're rolling on the ground, add static friction. pmove->onground = trace.ent; @@ -2341,22 +2394,22 @@ void PM_Physics_Toss() 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] ); + // 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)) + if( vel < ( 30 * 30 ) || ( pmove->movetype != MOVETYPE_BOUNCE && pmove->movetype != MOVETYPE_BOUNCEMISSILE ) ) { pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); + VectorCopy( vec3_origin, pmove->velocity ); } else { - VectorScale (pmove->velocity, (1.0 - trace.fraction) * pmove->frametime * 0.9, move); - trace = PM_PushEntity (move); + 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 + + // check for in water PM_CheckWater(); } @@ -2368,30 +2421,29 @@ PM_NoClip */ void PM_NoClip() { - int i; - vec3_t wishvel; - float fmove, smove; -// float currentspeed, addspeed, accelspeed; + 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 + 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[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 ); + 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 @@ -2415,12 +2467,12 @@ void PM_PreventMegaBunnyJumping( void ) maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * pmove->maxspeed; // Don't divide by zero - if ( maxscaledspeed <= 0.0f ) + if( maxscaledspeed <= 0.0f ) return; spd = Length( pmove->velocity ); - if ( spd <= maxscaledspeed ) + if( spd <= maxscaledspeed ) return; fraction = ( maxscaledspeed / spd ) * 0.65; //Returns the modifier for the velocity @@ -2433,33 +2485,32 @@ void PM_PreventMegaBunnyJumping( void ) PM_Jump ============= */ -void PM_Jump (void) +void PM_Jump( void ) { int i; qboolean tfc = false; qboolean cansuperjump = false; - if (pmove->dead) + if( pmove->dead ) { - pmove->oldbuttons |= IN_JUMP ; // don't jump again until released + 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 ) ) ) + if( tfc && ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) { return; } // See if we are waterjumping. If so, decrement count and return. - if ( pmove->waterjumptime ) + if( pmove->waterjumptime ) { pmove->waterjumptime -= pmove->cmd.msec; - if (pmove->waterjumptime < 0) + if( pmove->waterjumptime < 0 ) { pmove->waterjumptime = 0; } @@ -2467,24 +2518,25 @@ void PM_Jump (void) } // If we are in the water most of the way... - if (pmove->waterlevel >= 2) - { // swimming, not jumping + if( pmove->waterlevel >= 2 ) + { + // swimming, not jumping pmove->onground = -1; - if (pmove->watertype == CONTENTS_WATER) // We move up a certain amount + if( pmove->watertype == CONTENTS_WATER ) // We move up a certain amount pmove->velocity[2] = 100; - else if (pmove->watertype == CONTENTS_SLIME) + else if( pmove->watertype == CONTENTS_SLIME ) pmove->velocity[2] = 80; - else // LAVA + else // LAVA pmove->velocity[2] = 50; // play swiming sound - if ( pmove->flSwimTime <= 0 ) + if( pmove->flSwimTime <= 0 ) { // Don't play sound again for 1 second pmove->flSwimTime = 1000; - switch ( pmove->RandomLong( 0, 3 ) ) - { + switch( pmove->RandomLong( 0, 3 ) ) + { case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); break; @@ -2504,7 +2556,7 @@ void PM_Jump (void) } // No more effect - if ( pmove->onground == -1 ) + if( pmove->onground == -1 ) { // Flag that we jumped. // HACK HACK HACK @@ -2513,15 +2565,15 @@ void PM_Jump (void) return; // in air, so no effect } - if ( pmove->oldbuttons & IN_JUMP ) + if( pmove->oldbuttons & IN_JUMP ) return; // don't pogo stick // In the air now. - pmove->onground = -1; + pmove->onground = -1; PM_PreventMegaBunnyJumping(); - if ( tfc ) + if( tfc ) { pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); } @@ -2535,32 +2587,30 @@ void PM_Jump (void) // Acclerate upward // If we are ducking... - if ( ( pmove->bInDuck ) || ( pmove->flags & FL_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 ) && + if( cansuperjump && ( pmove->cmd.buttons & IN_DUCK ) && ( pmove->flDuckTime > 0 ) && Length( pmove->velocity ) > 50 ) { pmove->punchangle[0] = -5; - for (i =0; i < 2; i++) + 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); + + pmove->velocity[2] = sqrt( 2 * 800 * 56.0 ); } else { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); + pmove->velocity[2] = sqrt( 2 * 800 * 45.0 ); } } else { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); + pmove->velocity[2] = sqrt( 2 * 800 * 45.0 ); } // Decay it for simulation @@ -2576,21 +2626,21 @@ PM_CheckWaterJump ============= */ #define WJ_HEIGHT 8 -void PM_CheckWaterJump (void) +void PM_CheckWaterJump( void ) { - vec3_t vecStart, vecEnd; - vec3_t flatforward; - vec3_t flatvelocity; + vec3_t vecStart, vecEnd; + vec3_t flatforward; + vec3_t flatvelocity; float curspeed; pmtrace_t tr; - int savehull; + int savehull; // Already water jumping. - if ( pmove->waterjumptime ) + if( pmove->waterjumptime ) return; // Don't hop out if we just jumped in - if ( pmove->velocity[2] < -180 ) + if( pmove->velocity[2] < -180 ) return; // only hop out if we are moving up // See if we are backing up @@ -2600,34 +2650,34 @@ void PM_CheckWaterJump (void) // 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); + 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 ) ) + if( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) ) return; VectorCopy( pmove->origin, vecStart ); vecStart[2] += WJ_HEIGHT; - VectorMA ( vecStart, 24, flatforward, vecEnd ); - + 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? + 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; + 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 ) + if( tr.fraction == 1.0 ) { pmove->waterjumptime = 2000; pmove->velocity[2] = 225; @@ -2642,20 +2692,18 @@ void PM_CheckWaterJump (void) void PM_CheckFalling( void ) { - if ( pmove->onground != -1 && - !pmove->dead && - pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) + if( pmove->onground != -1 && !pmove->dead && pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) { float fvol = 0.5; - if ( pmove->waterlevel > 0 ) + if( pmove->waterlevel > 0 ) { } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) + 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 + // 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) ) + //switch( RandomLong( 0, 1 ) ) //{ //case 0: //pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); @@ -2666,45 +2714,45 @@ void PM_CheckFalling( void ) //} fvol = 1.0; } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) + 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 ) + 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 ) + else if( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED ) { fvol = 0; } - if ( fvol > 0.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 + pmove->punchangle[2] = pmove->flFallVelocity * 0.013; // punch z axis - if ( pmove->punchangle[ 0 ] > 8 ) + if( pmove->punchangle[0] > 8 ) { - pmove->punchangle[ 0 ] = 8; + pmove->punchangle[0] = 8; } } } - if ( pmove->onground != -1 ) - { + if( pmove->onground != -1 ) + { pmove->flFallVelocity = 0; } } @@ -2718,10 +2766,9 @@ 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 ) ) + if( ( pmove->oldwaterlevel == 0 && pmove->waterlevel != 0 ) || ( pmove->oldwaterlevel != 0 && pmove->waterlevel == 0 ) ) { - switch ( pmove->RandomLong(0,3) ) + switch( pmove->RandomLong( 0, 3 ) ) { case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); @@ -2745,32 +2792,32 @@ PM_CalcRoll =============== */ -float PM_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +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); - + 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); - + + side = fabs( side ); + value = rollangle; - - if (side < rollspeed) + + if( side < rollspeed ) { side = side * value / rollspeed; } - else + else { side = value; } - + return side * sign; } @@ -2780,14 +2827,14 @@ PM_DropPunchAngle ============= */ -void PM_DropPunchAngle ( vec3_t punchangle ) +void PM_DropPunchAngle( vec3_t punchangle ) { - float len; + float len; - len = VectorNormalize ( punchangle ); - len -= (10.0 + len * 0.5) * pmove->frametime; + len = VectorNormalize( punchangle ); + len -= ( 10.0 + len * 0.5 ) * pmove->frametime; len = max( len, 0.0 ); - VectorScale ( punchangle, len, punchangle); + VectorScale( punchangle, len, punchangle ); } /* @@ -2800,50 +2847,45 @@ void PM_CheckParamters( void ) { float spd; float maxspeed; - vec3_t v_angle; + vec3_t v_angle; - spd = ( pmove->cmd.forwardmove * pmove->cmd.forwardmove ) + - ( pmove->cmd.sidemove * pmove->cmd.sidemove ) + - ( pmove->cmd.upmove * pmove->cmd.upmove ); + 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 ) + if( maxspeed != 0.0 ) { pmove->maxspeed = min( maxspeed, pmove->maxspeed ); } - if ( ( spd != 0.0 ) && - ( spd > 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; + pmove->cmd.sidemove *= fRatio; + pmove->cmd.upmove *= fRatio; } - if ( pmove->flags & FL_FROZEN || - pmove->flags & FL_ONTRAIN || - pmove->dead ) + if( pmove->flags & FL_FROZEN || pmove->flags & FL_ONTRAIN || pmove->dead ) { pmove->cmd.forwardmove = 0; - pmove->cmd.sidemove = 0; - pmove->cmd.upmove = 0; + pmove->cmd.sidemove = 0; + pmove->cmd.upmove = 0; } - PM_DropPunchAngle( pmove->punchangle ); // Take angles from command. - if ( !pmove->dead ) + if( !pmove->dead ) { - VectorCopy ( pmove->cmd.viewangles, v_angle ); + 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]; + 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 { @@ -2851,41 +2893,40 @@ void PM_CheckParamters( void ) } // Set dead player view_offset - if ( pmove->dead ) + 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) + if( pmove->angles[YAW] > 180.0f ) { pmove->angles[YAW] -= 360.0f; } - } void PM_ReduceTimers( void ) { - if ( pmove->flTimeStepSound > 0 ) + if( pmove->flTimeStepSound > 0 ) { pmove->flTimeStepSound -= pmove->cmd.msec; - if ( pmove->flTimeStepSound < 0 ) + if( pmove->flTimeStepSound < 0 ) { pmove->flTimeStepSound = 0; } } - if ( pmove->flDuckTime > 0 ) + if( pmove->flDuckTime > 0 ) { pmove->flDuckTime -= pmove->cmd.msec; - if ( pmove->flDuckTime < 0 ) + if( pmove->flDuckTime < 0 ) { pmove->flDuckTime = 0; } } - if ( pmove->flSwimTime > 0 ) + if( pmove->flSwimTime > 0 ) { pmove->flSwimTime -= pmove->cmd.msec; - if ( pmove->flSwimTime < 0 ) + if( pmove->flSwimTime < 0 ) { pmove->flSwimTime = 0; } @@ -2902,7 +2943,7 @@ Numtouch and touchindex[] will be set if any of the physents were contacted during the move. ============= */ -void PM_PlayerMove ( qboolean server ) +void PM_PlayerMove( qboolean server ) { physent_t *pLadder = NULL; @@ -2921,12 +2962,12 @@ void PM_PlayerMove ( qboolean server ) PM_ReduceTimers(); // Convert view angles to vectors - AngleVectors (pmove->angles, pmove->forward, pmove->right, pmove->up); + 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 ) + if( pmove->spectator || pmove->iuser1 > 0 ) { PM_SpectatorMove(); PM_CatagorizePosition(); @@ -2934,9 +2975,9 @@ void PM_PlayerMove ( qboolean server ) } // Always try and unstick us unless we are in NOCLIP mode - if ( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE ) + if( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE ) { - if ( PM_CheckStuck() ) + if( PM_CheckStuck() ) { return; // Can't move, we're stuck } @@ -2949,17 +2990,17 @@ void PM_PlayerMove ( qboolean server ) pmove->oldwaterlevel = pmove->waterlevel; // If we are not on ground, store off how fast we are moving down - if ( pmove->onground == -1 ) + 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) ) + if( !pmove->dead && !( pmove->flags & FL_ONTRAIN ) ) { pLadder = PM_Ladder(); - if ( pLadder ) + if( pLadder ) { g_onladder = 1; } @@ -2970,14 +3011,13 @@ void PM_PlayerMove ( qboolean server ) PM_Duck(); // Don't run ladder code if dead or on a train - if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) + if( !pmove->dead && !( pmove->flags & FL_ONTRAIN ) ) { - if ( pLadder ) + if( pLadder ) { PM_LadderMove( pLadder ); } - else if ( pmove->movetype != MOVETYPE_WALK && - pmove->movetype != MOVETYPE_NOCLIP ) + 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 @@ -2986,63 +3026,57 @@ void PM_PlayerMove ( qboolean server ) } // 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) ) + if( ( pmove->onground != -1 ) && ( pmove->cmd.buttons & IN_USE ) ) { VectorScale( pmove->velocity, 0.3, pmove->velocity ); } // Handle movement - switch ( pmove->movetype ) + switch( pmove->movetype ) { default: - pmove->Con_DPrintf("Bogus pmove player movetype %i on (%i) 0=cl 1=sv\n", pmove->movetype, pmove->server); + 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( pmove->cmd.buttons & IN_JUMP ) { - if ( !pLadder ) + if( !pLadder ) { - PM_Jump (); + 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; + // 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() ) + if( !PM_InWater() ) { PM_AddCorrectGravity(); } // If we are leaping out of the water, just update the counters. - if ( pmove->waterjumptime ) + if( pmove->waterjumptime ) { PM_WaterJump(); PM_FlyMove(); @@ -3054,23 +3088,23 @@ void PM_PlayerMove ( qboolean server ) // 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 ) { - 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 ) + if( pmove->velocity[2] < 0 && pmove->waterjumptime ) { pmove->waterjumptime = 0; } // Was jump button pressed? - if (pmove->cmd.buttons & IN_JUMP) + if( pmove->cmd.buttons & IN_JUMP ) { - PM_Jump (); + PM_Jump(); } else { @@ -3079,22 +3113,21 @@ void PM_PlayerMove ( qboolean server ) // Perform regular water movement PM_WaterMove(); - - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); + + 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( pmove->cmd.buttons & IN_JUMP ) { - if ( !pLadder ) + if( !pLadder ) { - PM_Jump (); + PM_Jump(); } } else @@ -3104,7 +3137,7 @@ void PM_PlayerMove ( qboolean server ) // 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 ) + if( pmove->onground != -1 ) { pmove->velocity[2] = 0.0; PM_Friction(); @@ -3114,7 +3147,7 @@ void PM_PlayerMove ( qboolean server ) PM_CheckVelocity(); // Are we on ground now - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { PM_WalkMove(); } @@ -3129,19 +3162,19 @@ void PM_PlayerMove ( qboolean server ) // 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 ); - + VectorSubtract( pmove->velocity, pmove->basevelocity, pmove->velocity ); + // Make sure velocity is valid. PM_CheckVelocity(); // Add any remaining gravitational component. - if ( !PM_InWater() ) + if( !PM_InWater() ) { PM_FixupGravityVelocity(); } // If we are on ground, no downward velocity. - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { pmove->velocity[2] = 0; } @@ -3164,13 +3197,13 @@ void PM_CreateStuckTable( void ) int i; float zi[3]; - memset(rgv3tStuckTable, 0, 54 * sizeof(vec3_t)); + 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) + for( z = -0.125; z <= 0.125; z += 0.125 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3179,7 +3212,7 @@ void PM_CreateStuckTable( void ) } x = z = 0; // Y moves - for (y = -0.125 ; y <= 0.125 ; y += 0.125) + for( y = -0.125; y <= 0.125; y += 0.125 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3188,7 +3221,7 @@ void PM_CreateStuckTable( void ) } y = z = 0; // X moves - for (x = -0.125 ; x <= 0.125 ; x += 0.125) + for( x = -0.125; x <= 0.125; x += 0.125 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3197,11 +3230,11 @@ void PM_CreateStuckTable( void ) } // Remaining multi axis nudges. - for ( x = - 0.125; x <= 0.125; x += 0.250 ) + for( x = - 0.125; x <= 0.125; x += 0.250 ) { - for ( y = - 0.125; y <= 0.125; y += 0.250 ) + for( y = - 0.125; y <= 0.125; y += 0.250 ) { - for ( z = - 0.125; z <= 0.125; z += 0.250 ) + for( z = - 0.125; z <= 0.125; z += 0.250 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3217,7 +3250,7 @@ void PM_CreateStuckTable( void ) zi[1] = 1.0f; zi[2] = 6.0f; - for (i = 0; i < 3; i++) + for( i = 0; i < 3; i++ ) { // Z moves z = zi[i]; @@ -3230,7 +3263,7 @@ void PM_CreateStuckTable( void ) x = z = 0; // Y moves - for (y = -2.0f ; y <= 2.0f ; y += 2.0) + for( y = -2.0f ; y <= 2.0f ; y += 2.0 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3239,7 +3272,7 @@ void PM_CreateStuckTable( void ) } y = z = 0; // X moves - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) + for( x = -2.0f ; x <= 2.0f ; x += 2.0f ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3248,13 +3281,13 @@ void PM_CreateStuckTable( void ) } // Remaining multi axis nudges. - for (i = 0 ; i < 3; i++) + for( i = 0 ; i < 3; i++ ) { z = zi[i]; - - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) + + for( x = -2.0f; x <= 2.0f; x += 2.0f ) { - for (y = -2.0f ; y <= 2.0f ; y += 2.0) + for( y = -2.0f; y <= 2.0f; y += 2.0 ) { rgv3tStuckTable[idx][0] = x; rgv3tStuckTable[idx][1] = y; @@ -3265,8 +3298,6 @@ void PM_CreateStuckTable( void ) } } - - /* 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 @@ -3274,17 +3305,17 @@ invoked by each side as appropriate. There should be no distinction, internally and client. This will ensure that prediction behaves appropriately. */ -void PM_Move ( struct playermove_s *ppmove, int server ) +void PM_Move( struct playermove_s *ppmove, int server ) { assert( pm_shared_initialized ); pmove = ppmove; -// pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground ); + //pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground ); PM_PlayerMove( ( server != 0 ) ? true : false ); - if ( pmove->onground != -1 ) + if( pmove->onground != -1 ) { pmove->flags |= FL_ONGROUND; } @@ -3294,7 +3325,7 @@ void PM_Move ( struct playermove_s *ppmove, int server ) } // In single player, reset friction after each movement to FrictionModifier Triggers work still. - if ( !pmove->multiplayer && ( pmove->movetype == MOVETYPE_WALK ) ) + if( !pmove->multiplayer && ( pmove->movetype == MOVETYPE_WALK ) ) { pmove->friction = 1.0f; } @@ -3302,18 +3333,18 @@ void PM_Move ( struct playermove_s *ppmove, int server ) int PM_GetVisEntInfo( int ent ) { - if ( ent >= 0 && ent <= pmove->numvisent ) + if( ent >= 0 && ent <= pmove->numvisent ) { - return pmove->visents[ ent ].info; + return pmove->visents[ent].info; } return -1; } int PM_GetPhysEntInfo( int ent ) { - if ( ent >= 0 && ent <= pmove->numphysent) + if( ent >= 0 && ent <= pmove->numphysent ) { - return pmove->physents[ ent ].info; + return pmove->physents[ent].info; } return -1; } diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index 9743044c..124d37ba 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -23,10 +23,9 @@ 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_CHASE_FREE 2 #define OBS_ROAMING 3 #define OBS_IN_EYE 4 -#define OBS_MAP_FREE 5 -#define OBS_MAP_CHASE 6 - -#endif//PM_SHARED_H \ No newline at end of file +#define OBS_MAP_FREE 5 +#define OBS_MAP_CHASE 6 +#endif//PM_SHARED_H From 327bf79e7416de9583bd77c76ff35d3809709c00 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 31 Jul 2016 19:52:15 +0500 Subject: [PATCH 051/227] Remove h_cine.cpp from Android.mk. --- dlls/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index ac887f8b..e61ca6fc 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -65,7 +65,6 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ gman.cpp \ h_ai.cpp \ h_battery.cpp \ - h_cine.cpp \ h_cycler.cpp \ h_export.cpp \ handgrenade.cpp \ From 07347addc2a039212189eabfba311fbf4c8203fc Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 31 Jul 2016 19:54:54 +0500 Subject: [PATCH 052/227] Move h_cine.cpp to dlls/legacy directory. --- dlls/{ => legacy}/h_cine.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dlls/{ => legacy}/h_cine.cpp (100%) diff --git a/dlls/h_cine.cpp b/dlls/legacy/h_cine.cpp similarity index 100% rename from dlls/h_cine.cpp rename to dlls/legacy/h_cine.cpp From 3b8bc0a417a3a199ace944f93641cb433ad13892 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 1 Aug 2016 16:13:13 +0500 Subject: [PATCH 053/227] Reformat some files yet. --- cl_dll/StudioModelRenderer.cpp | 814 +++++++++++----------- cl_dll/StudioModelRenderer.h | 72 +- dlls/decals.h | 4 +- dlls/extdll.h | 7 +- dlls/leech.cpp | 290 ++++---- dlls/monsterevent.h | 9 +- dlls/monsters.h | 53 +- dlls/mp5.cpp | 143 ++-- dlls/plats.cpp | 1164 ++++++++++++++++---------------- dlls/prop.cpp | 575 ++++++++-------- dlls/soundent.cpp | 154 ++--- dlls/weapons.cpp | 503 +++++++------- 12 files changed, 1898 insertions(+), 1890 deletions(-) diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index d4644408..b7c3c1c6 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -39,14 +39,14 @@ engine_studio_api_t IEngineStudio; // enumerate all the bones that used for gait animation const char *legs_bones[] = { - "Bip01" , - "Bip01 Pelvis" , - "Bip01 L Leg" , - "Bip01 L Leg1" , - "Bip01 L Foot" , - "Bip01 R Leg" , - "Bip01 R Leg1" , - "Bip01 R Foot" + "Bip01", + "Bip01 Pelvis", + "Bip01 L Leg", + "Bip01 L Leg1", + "Bip01 L Foot", + "Bip01 R Leg", + "Bip01 R Leg1", + "Bip01 R Foot" }; /* @@ -81,7 +81,7 @@ CStudioModelRenderer */ CStudioModelRenderer::CStudioModelRenderer( void ) { - m_fDoInterp = 1; + m_fDoInterp = 1; m_fGaitEstimation = 1; m_pCurrentEntity = NULL; m_pCvarHiModels = NULL; @@ -95,8 +95,8 @@ CStudioModelRenderer::CStudioModelRenderer( void ) m_pbonetransform = NULL; m_plighttransform = NULL; m_pStudioHeader = NULL; - m_pBodyPart = NULL; - m_pSubModel = NULL; + m_pBodyPart = NULL; + m_pSubModel = NULL; m_pPlayerInfo = NULL; m_pRenderModel = NULL; } @@ -119,54 +119,54 @@ StudioCalcBoneAdj */ void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) { - int i, j; - float value; + int i, j; + float value; mstudiobonecontroller_t *pbonecontroller; - - pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); - for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + pbonecontroller = (mstudiobonecontroller_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex ); + + for( j = 0; j < m_pStudioHeader->numbonecontrollers; j++ ) { i = pbonecontroller[j].index; - if (i <= 3) + if( i <= 3 ) { // check for 360% wrapping - if (pbonecontroller[j].type & STUDIO_RLOOP) + if( pbonecontroller[j].type & STUDIO_RLOOP ) { - if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + if( abs( pcontroller1[i] - pcontroller2[i] ) > 128) { int a, b; - a = (pcontroller1[j] + 128) % 256; - b = (pcontroller2[j] + 128) % 256; - value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + a = ( pcontroller1[j] + 128 ) % 256; + b = ( pcontroller2[j] + 128 ) % 256; + value = ( ( a * dadt ) + ( b * ( 1 - dadt ) ) - 128 ) * ( 360.0 / 256.0 ) + pbonecontroller[j].start; } - else + else { - value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + value = ( ( pcontroller1[i] * dadt + ( pcontroller2[i] ) * ( 1.0 - dadt ) ) ) * ( 360.0 / 256.0 ) + pbonecontroller[j].start; } } - else + else { - value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; - if (value < 0) value = 0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + value = ( pcontroller1[i] * dadt + pcontroller2[i] * ( 1.0 - dadt ) ) / 255.0; + if( value < 0 ) value = 0; + if( value > 1.0 ) value = 1.0; + value = ( 1.0 - value ) * pbonecontroller[j].start + value * pbonecontroller[j].end; } // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); } else { value = mouthopen / 64.0; - if (value > 1.0) value = 1.0; - value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; - // Con_DPrintf("%d %f\n", mouthopen, value ); + if( value > 1.0 ) value = 1.0; + value = ( 1.0 - value ) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Con_DPrintf( "%d %f\n", mouthopen, value ); } - switch(pbonecontroller[j].type & STUDIO_TYPES) + switch( pbonecontroller[j].type & STUDIO_TYPES ) { case STUDIO_XR: case STUDIO_YR: case STUDIO_ZR: - adj[j] = value * (M_PI / 180.0); + adj[j] = value * ( M_PI / 180.0 ); break; case STUDIO_X: case STUDIO_Y: @@ -186,53 +186,53 @@ StudioCalcBoneQuaterion */ void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) { - int j, k; - vec4_t q1, q2; - vec3_t angle1, angle2; - mstudioanimvalue_t *panimvalue; + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; - for (j = 0; j < 3; j++) + for( j = 0; j < 3; j++ ) { - if (panim->offset[j+3] == 0) + if( panim->offset[j + 3] == 0 ) { - angle2[j] = angle1[j] = pbone->value[j+3]; // default; + angle2[j] = angle1[j] = pbone->value[ j + 3]; // default; } else { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + panimvalue = (mstudioanimvalue_t *)( (byte *)panim + panim->offset[j + 3] ); k = frame; // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) + if( panimvalue->num.total < panimvalue->num.valid ) k = 0; - while (panimvalue->num.total <= k) + while( panimvalue->num.total <= k ) { k -= panimvalue->num.total; panimvalue += panimvalue->num.valid + 1; // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) + if( panimvalue->num.total < panimvalue->num.valid ) k = 0; } // Bah, missing blend! - if (panimvalue->num.valid > k) + if( panimvalue->num.valid > k ) { - angle1[j] = panimvalue[k+1].value; + angle1[j] = panimvalue[k + 1].value; - if (panimvalue->num.valid > k + 1) + if( panimvalue->num.valid > k + 1 ) { - angle2[j] = panimvalue[k+2].value; + angle2[j] = panimvalue[k + 2].value; } else { - if (panimvalue->num.total > k + 1) + if( panimvalue->num.total > k + 1 ) angle2[j] = angle1[j]; else - angle2[j] = panimvalue[panimvalue->num.valid+2].value; + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; } } else { angle1[j] = panimvalue[panimvalue->num.valid].value; - if (panimvalue->num.total > k + 1) + if( panimvalue->num.total > k + 1 ) { angle2[j] = angle1[j]; } @@ -241,18 +241,18 @@ void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiob angle2[j] = panimvalue[panimvalue->num.valid + 2].value; } } - angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; - angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j + 3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j + 3]; } - if (pbone->bonecontroller[j+3] != -1) + if( pbone->bonecontroller[j + 3] != -1 ) { - angle1[j] += adj[pbone->bonecontroller[j+3]]; - angle2[j] += adj[pbone->bonecontroller[j+3]]; + angle1[j] += adj[pbone->bonecontroller[j + 3]]; + angle2[j] += adj[pbone->bonecontroller[j + 3]]; } } - if (!VectorCompare( angle1, angle2 )) + if( !VectorCompare( angle1, angle2 ) ) { AngleQuaternion( angle1, q1 ); AngleQuaternion( angle2, q2 ); @@ -272,52 +272,52 @@ StudioCalcBonePosition */ void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) { - int j, k; - mstudioanimvalue_t *panimvalue; + int j, k; + mstudioanimvalue_t *panimvalue; - for (j = 0; j < 3; j++) + for( j = 0; j < 3; j++ ) { pos[j] = pbone->value[j]; // default; - if (panim->offset[j] != 0) + if( panim->offset[j] != 0 ) { - panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + panimvalue = (mstudioanimvalue_t *)( (byte *)panim + panim->offset[j] ); /* - if (i == 0 && j == 0) - Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + if( i == 0 && j == 0 ) + Con_DPrintf( "%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); */ k = frame; // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) + if( panimvalue->num.total < panimvalue->num.valid ) k = 0; // find span of values that includes the frame we want - while (panimvalue->num.total <= k) + while( panimvalue->num.total <= k ) { k -= panimvalue->num.total; panimvalue += panimvalue->num.valid + 1; // DEBUG - if (panimvalue->num.total < panimvalue->num.valid) + if( panimvalue->num.total < panimvalue->num.valid ) k = 0; } // if we're inside the span - if (panimvalue->num.valid > k) + if( panimvalue->num.valid > k ) { // and there's more data in the span - if (panimvalue->num.valid > k + 1) + if( panimvalue->num.valid > k + 1 ) { - pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + pos[j] += ( panimvalue[k + 1].value * ( 1.0 - s ) + s * panimvalue[k + 2].value ) * pbone->scale[j]; } else { - pos[j] += panimvalue[k+1].value * pbone->scale[j]; + pos[j] += panimvalue[k + 1].value * pbone->scale[j]; } } else { // are we at the end of the repeating values section and there's another section with data? - if (panimvalue->num.total <= k + 1) + if( panimvalue->num.total <= k + 1 ) { - pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + pos[j] += ( panimvalue[panimvalue->num.valid].value * ( 1.0 - s ) + s * panimvalue[panimvalue->num.valid + 2].value ) * pbone->scale[j]; } else { @@ -325,7 +325,7 @@ void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobo } } } - if ( pbone->bonecontroller[j] != -1 && adj ) + if( pbone->bonecontroller[j] != -1 && adj ) { pos[j] += adj[pbone->bonecontroller[j]]; } @@ -340,16 +340,18 @@ StudioSlerpBones */ void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) { - int i; - vec4_t q3; - float s1; + int i; + vec4_t q3; + float s1; - if (s < 0) s = 0; - else if (s > 1.0) s = 1.0; + if( s < 0 ) + s = 0; + else if( s > 1.0 ) + s = 1.0; s1 = 1.0 - s; - for (i = 0; i < m_pStudioHeader->numbones; i++) + for( i = 0; i < m_pStudioHeader->numbones; i++ ) { QuaternionSlerp( q1[i], q2[i], s, q3 ); q1[i][0] = q3[0]; @@ -370,30 +372,30 @@ StudioGetAnim */ mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) { - mstudioseqgroup_t *pseqgroup; + mstudioseqgroup_t *pseqgroup; cache_user_t *paSequences; - pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + pseqgroup = (mstudioseqgroup_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex ) + pseqdesc->seqgroup; - if (pseqdesc->seqgroup == 0) + if( pseqdesc->seqgroup == 0 ) { - return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqdesc->animindex); + return (mstudioanim_t *)( (byte *)m_pStudioHeader + pseqdesc->animindex ); } paSequences = (cache_user_t *)m_pSubModel->submodels; - if (paSequences == NULL) + if( paSequences == NULL ) { - paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! + paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof(cache_user_t) ); // UNDONE: leak! m_pSubModel->submodels = (dmodel_t *)paSequences; } - if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) + if( !IEngineStudio.Cache_Check( (struct cache_user_s *)&( paSequences[pseqdesc->seqgroup] ) ) ) { gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); } - return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); + return (mstudioanim_t *)( (byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex ); } /* @@ -405,23 +407,23 @@ StudioPlayerBlend void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) { // calc up/down pointing - *pBlend = (*pPitch * 3); - if (*pBlend < pseqdesc->blendstart[0]) + *pBlend = ( *pPitch * 3 ); + if( *pBlend < pseqdesc->blendstart[0] ) { *pPitch -= pseqdesc->blendstart[0] / 3.0; *pBlend = 0; } - else if (*pBlend > pseqdesc->blendend[0]) + else if( *pBlend > pseqdesc->blendend[0] ) { *pPitch -= pseqdesc->blendend[0] / 3.0; *pBlend = 255; } else { - if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error + if( pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1 ) // catch qc error *pBlend = 127; else - *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pBlend = 255 * ( *pBlend - pseqdesc->blendstart[0] ) / ( pseqdesc->blendend[0] - pseqdesc->blendstart[0] ); *pPitch = 0; } } @@ -432,14 +434,14 @@ StudioSetUpTransform ==================== */ -void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) +void CStudioModelRenderer::StudioSetUpTransform( int trivial_accept ) { - int i; - vec3_t angles; - vec3_t modelpos; + int i; + vec3_t angles; + vec3_t modelpos; -// tweek model origin - //for (i = 0; i < 3; i++) + // tweek model origin + //for( i = 0; i < 3; i++ ) // modelpos[i] = m_pCurrentEntity->origin[i]; VectorCopy( m_pCurrentEntity->origin, modelpos ); @@ -451,26 +453,26 @@ void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; - //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); - //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) + //Con_DPrintf( "Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index ); + //Con_DPrintf( "movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); + if( m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP ) { - float f = 0; - float d; + float f = 0; + float d; // don't do it if the goalstarttime hasn't updated in a while. // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit // was increased to 1.0 s., which is 2x the max lag we are accounting for. - if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && - ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) + if( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && + ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) { - f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); - //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); + f = ( m_clTime - m_pCurrentEntity->curstate.animtime ) / ( m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime ); + //Con_DPrintf( "%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime ); } - if (m_fDoInterp) + if( m_fDoInterp ) { // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set f = f - 1.0; @@ -480,17 +482,16 @@ void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) f = 0; } - for (i = 0; i < 3; i++) + for( i = 0; i < 3; i++ ) { - modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; + modelpos[i] += ( m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i] ) * f; } // NOTE: Because multiplayer lag can be relatively large, we don't want to cap // f at 1.5 anymore. - //if (f > -1.0 && f < 1.5) {} - -// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); - for (i = 0; i < 3; i++) + //if( f > -1.0 && f < 1.5 ) {} + //Con_DPrintf( "%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); + for( i = 0; i < 3; i++ ) { float ang1, ang2; @@ -498,60 +499,57 @@ void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) ang2 = m_pCurrentEntity->latched.prevangles[i]; d = ang1 - ang2; - if (d > 180) + if( d > 180 ) { d -= 360; } - else if (d < -180) - { + else if( d < -180 ) + { d += 360; } angles[i] += d * f; } - //Con_DPrintf("%.3f \n", f ); + //Con_DPrintf( "%.3f \n", f ); } - else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) + else if( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) { VectorCopy( m_pCurrentEntity->angles, angles ); } - //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); - //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); + //Con_DPrintf( "%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); + //Con_DPrintf( "%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); angles[PITCH] = -angles[PITCH]; - AngleMatrix (angles, (*m_protationmatrix)); + AngleMatrix( angles, ( *m_protationmatrix ) ); - if ( !IEngineStudio.IsHardware() ) + if( !IEngineStudio.IsHardware() ) { static float viewmatrix[3][4]; - VectorCopy (m_vRight, viewmatrix[0]); - VectorCopy (m_vUp, viewmatrix[1]); - VectorInverse (viewmatrix[1]); - VectorCopy (m_vNormal, viewmatrix[2]); + VectorCopy( m_vRight, viewmatrix[0] ); + VectorCopy( m_vUp, viewmatrix[1] ); + VectorInverse( viewmatrix[1] ); + VectorCopy( m_vNormal, viewmatrix[2] ); (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; - ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); + ConcatTransforms( viewmatrix, (*m_protationmatrix), (*m_paliastransform) ); // do the scaling up of x and y to screen coordinates as part of the transform // for the unclipped case (it would mess up clipping in the clipped case). // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y // correspondingly so the projected x and y come out right // FIXME: make this work for clipped case too? - if (trivial_accept) + if( trivial_accept ) { - for (i=0 ; i<4 ; i++) + for( i = 0; i < 4; i++ ) { - (*m_paliastransform)[0][i] *= m_fSoftwareXScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[1][i] *= m_fSoftwareYScale * - (1.0 / (ZISCALE * 0x10000)); - (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); - + (*m_paliastransform)[0][i] *= m_fSoftwareXScale * ( 1.0 / ( ZISCALE * 0x10000 ) ); + (*m_paliastransform)[1][i] *= m_fSoftwareYScale * ( 1.0 / ( ZISCALE * 0x10000 ) ); + (*m_paliastransform)[2][i] *= 1.0 / ( ZISCALE * 0x10000 ); } } } @@ -561,7 +559,6 @@ void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) (*m_protationmatrix)[2][3] = modelpos[2]; } - /* ==================== StudioEstimateInterpolant @@ -572,10 +569,10 @@ float CStudioModelRenderer::StudioEstimateInterpolant( void ) { float dadt = 1.0; - if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) + if( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) { - dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; - if (dadt > 2.0) + dadt = ( m_clTime - m_pCurrentEntity->curstate.animtime ) / 0.1; + if( dadt > 2.0 ) { dadt = 2.0; } @@ -589,78 +586,77 @@ StudioCalcRotations ==================== */ -void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +void CStudioModelRenderer::StudioCalcRotations( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) { - int i; - int frame; - mstudiobone_t *pbone; + int i; + int frame; + mstudiobone_t *pbone; - float s; - float adj[MAXSTUDIOCONTROLLERS]; - float dadt; + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; - if (f > pseqdesc->numframes - 1) + if( f > pseqdesc->numframes - 1 ) { f = 0; // bah, fix this bug with changing sequences too fast } // BUG ( somewhere else ) but this code should validate this data. // This could cause a crash if the frame # is negative, so we'll go ahead // and clamp it here - else if ( f < -0.01 ) + else if( f < -0.01 ) { f = -0.01; } frame = (int)f; - // Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + // Con_DPrintf( "%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); // Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); - // Con_DPrintf("frame %d %d\n", frame1, frame2 ); + // Con_DPrintf( "frame %d %d\n", frame1, frame2 ); - - dadt = StudioEstimateInterpolant( ); - s = (f - frame); + dadt = StudioEstimateInterpolant(); + s = ( f - frame ); // add in programtic controllers - pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbone = (mstudiobone_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->boneindex ); StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); - for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + for( i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++ ) { StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); - // if (0 && i == 0) - // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); + // if( 0 && i == 0 ) + // Con_DPrintf( "%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); } - if (pseqdesc->motiontype & STUDIO_X) + if( pseqdesc->motiontype & STUDIO_X ) { pos[pseqdesc->motionbone][0] = 0.0; } - if (pseqdesc->motiontype & STUDIO_Y) + if( pseqdesc->motiontype & STUDIO_Y ) { pos[pseqdesc->motionbone][1] = 0.0; } - if (pseqdesc->motiontype & STUDIO_Z) + if( pseqdesc->motiontype & STUDIO_Z ) { pos[pseqdesc->motionbone][2] = 0.0; } - s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; + s = 0 * ( ( 1.0 - ( f - (int)( f ) ) ) / ( pseqdesc->numframes ) ) * m_pCurrentEntity->curstate.framerate; - if (pseqdesc->motiontype & STUDIO_LX) + if( pseqdesc->motiontype & STUDIO_LX ) { pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; } - if (pseqdesc->motiontype & STUDIO_LY) + if( pseqdesc->motiontype & STUDIO_LY ) { pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; } - if (pseqdesc->motiontype & STUDIO_LZ) + if( pseqdesc->motiontype & STUDIO_LZ ) { pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; } @@ -678,36 +674,35 @@ void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[ { case kRenderFxDistort: case kRenderFxHologram: - if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + if( gEngfuncs.pfnRandomLong( 0, 49 ) == 0 ) { - int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z + int axis = gEngfuncs.pfnRandomLong( 0, 1 ); + if( axis == 1 ) // Choose between x & z axis = 2; - VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat( 1, 1.484 ), transform[axis] ); } - else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + else if( gEngfuncs.pfnRandomLong( 0, 49 ) == 0 ) { float offset; int axis = gEngfuncs.pfnRandomLong(0,1); - if ( axis == 1 ) // Choose between x & z + if( axis == 1 ) // Choose between x & z axis = 2; - offset = gEngfuncs.pfnRandomFloat(-10,10); - transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + offset = gEngfuncs.pfnRandomFloat( -10, 10 ); + transform[gEngfuncs.pfnRandomLong( 0, 2 )][3] += offset; } break; case kRenderFxExplode: { float scale; - scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; - if ( scale > 2 ) // Don't blow up more than 200% + scale = 1.0 + ( m_clTime - ent->curstate.animtime ) * 10.0; + if( scale > 2 ) // Don't blow up more than 200% scale = 2; transform[0][1] *= scale; transform[1][1] *= scale; transform[2][1] *= scale; } break; - } } @@ -719,18 +714,17 @@ StudioEstimateFrame */ float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) { - double dfdt, f; + double dfdt, f; - if ( m_fDoInterp ) + if( m_fDoInterp ) { - if ( m_clTime < m_pCurrentEntity->curstate.animtime ) + if( m_clTime < m_pCurrentEntity->curstate.animtime ) { dfdt = 0; } else { - dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; - + dfdt = ( m_clTime - m_pCurrentEntity->curstate.animtime ) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; } } else @@ -738,35 +732,35 @@ float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) dfdt = 0; } - if (pseqdesc->numframes <= 1) + if( pseqdesc->numframes <= 1 ) { f = 0; } else { - f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; + f = ( m_pCurrentEntity->curstate.frame * ( pseqdesc->numframes - 1 ) ) / 256.0; } - + f += dfdt; - if (pseqdesc->flags & STUDIO_LOOPING) + if( pseqdesc->flags & STUDIO_LOOPING ) { - if (pseqdesc->numframes > 1) + if( pseqdesc->numframes > 1 ) { - f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + f -= (int)( f / ( pseqdesc->numframes - 1 ) ) * ( pseqdesc->numframes - 1 ); } - if (f < 0) + if( f < 0 ) { - f += (pseqdesc->numframes - 1); + f += ( pseqdesc->numframes - 1 ); } } else { - if (f >= pseqdesc->numframes - 1.001) + if( f >= pseqdesc->numframes - 1.001 ) { f = pseqdesc->numframes - 1.001; } - if (f < 0.0) + if( f < 0.0 ) { f = 0.0; } @@ -780,57 +774,57 @@ StudioSetupBones ==================== */ -void CStudioModelRenderer::StudioSetupBones ( void ) +void CStudioModelRenderer::StudioSetupBones( void ) { - int i, j; - double f; + int i, j; + double f; - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; - static float pos[MAXSTUDIOBONES][3]; - static vec4_t q[MAXSTUDIOBONES]; - float bonematrix[3][4]; + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; - static float pos2[MAXSTUDIOBONES][3]; - static vec4_t q2[MAXSTUDIOBONES]; - static float pos3[MAXSTUDIOBONES][3]; - static vec4_t q3[MAXSTUDIOBONES]; - static float pos4[MAXSTUDIOBONES][3]; - static vec4_t q4[MAXSTUDIOBONES]; + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + if( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) { m_pCurrentEntity->curstate.sequence = 0; } - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame( pseqdesc ); - if (m_pCurrentEntity->latched.prevframe > f) + if( m_pCurrentEntity->latched.prevframe > f ) { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + //Con_DPrintf( "%f %f\n", m_pCurrentEntity->prevframe, f ); } panim = StudioGetAnim( m_pRenderModel, pseqdesc ); StudioCalcRotations( pos, q, pseqdesc, panim, f ); - if (pseqdesc->numblends > 1) + if( pseqdesc->numblends > 1 ) { - float s; - float dadt; + float s; + float dadt; panim += m_pStudioHeader->numbones; StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); dadt = StudioEstimateInterpolant(); - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + s = ( m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * ( 1.0 - dadt ) ) / 255.0; StudioSlerpBones( q, pos, q2, pos2, s ); - if (pseqdesc->numblends == 4) + if( pseqdesc->numblends == 4 ) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); @@ -838,30 +832,29 @@ void CStudioModelRenderer::StudioSetupBones ( void ) panim += m_pStudioHeader->numbones; StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); - s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + s = ( m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * ( 1.0 - dadt ) ) / 255.0; StudioSlerpBones( q3, pos3, q4, pos4, s ); - s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; + s = ( m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * ( 1.0 - dadt ) ) / 255.0; StudioSlerpBones( q, pos, q3, pos3, s ); } } - if (m_fDoInterp && - m_pCurrentEntity->latched.sequencetime && + if( m_fDoInterp && m_pCurrentEntity->latched.sequencetime && ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && - ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq ) ) { // blend from last sequence - static float pos1b[MAXSTUDIOBONES][3]; - static vec4_t q1b[MAXSTUDIOBONES]; - float s; + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pCurrentEntity->latched.prevsequence; panim = StudioGetAnim( m_pRenderModel, pseqdesc ); // clip prevframe StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - if (pseqdesc->numblends > 1) + if( pseqdesc->numblends > 1 ) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); @@ -869,7 +862,7 @@ void CStudioModelRenderer::StudioSetupBones ( void ) s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; StudioSlerpBones( q1b, pos1b, q2, pos2, s ); - if (pseqdesc->numblends == 4) + if( pseqdesc->numblends == 4 ) { panim += m_pStudioHeader->numbones; StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); @@ -877,15 +870,15 @@ void CStudioModelRenderer::StudioSetupBones ( void ) panim += m_pStudioHeader->numbones; StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); - s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + s = ( m_pCurrentEntity->latched.prevseqblending[0] ) / 255.0; StudioSlerpBones( q3, pos3, q4, pos4, s ); - s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; + s = ( m_pCurrentEntity->latched.prevseqblending[1] ) / 255.0; StudioSlerpBones( q1b, pos1b, q3, pos3, s ); } } - s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + s = 1.0 - ( m_clTime - m_pCurrentEntity->latched.sequencetime ) / 0.2; StudioSlerpBones( q, pos, q1b, pos1b, s ); } else @@ -894,39 +887,39 @@ void CStudioModelRenderer::StudioSetupBones ( void ) m_pCurrentEntity->latched.prevframe = f; } - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbones = (mstudiobone_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->boneindex ); // calc gait animation - if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) + if( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) { - if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) + if( m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq ) { m_pPlayerInfo->gaitsequence = 0; } - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pPlayerInfo->gaitsequence; panim = StudioGetAnim( m_pRenderModel, pseqdesc ); StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); - for (i = 0; i < m_pStudioHeader->numbones; i++) + for( i = 0; i < m_pStudioHeader->numbones; i++ ) { for( j = 0; j < LEGS_BONES_COUNT; j++ ) { - if( !strcmp( pbones[i].name, legs_bones[j] )) + if( !strcmp( pbones[i].name, legs_bones[j] ) ) break; } if( j == LEGS_BONES_COUNT ) continue; // not used for legs - memcpy( pos[i], pos2[i], sizeof( pos[i] )); - memcpy( q[i], q2[i], sizeof( q[i] )); + memcpy( pos[i], pos2[i], sizeof(pos[i]) ); + memcpy( q[i], q2[i], sizeof(q[i]) ); } } - for (i = 0; i < m_pStudioHeader->numbones; i++) + for( i = 0; i < m_pStudioHeader->numbones; i++ ) { QuaternionMatrix( q[i], bonematrix ); @@ -934,20 +927,20 @@ void CStudioModelRenderer::StudioSetupBones ( void ) bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; - if (pbones[i].parent == -1) + if( pbones[i].parent == -1 ) { - if ( IEngineStudio.IsHardware() ) + if( IEngineStudio.IsHardware() ) { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_pbonetransform)[i] ); // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + //ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_plighttransform)[i] ); MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); } else { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + ConcatTransforms( (*m_paliastransform), bonematrix, (*m_pbonetransform)[i] ); + ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_plighttransform)[i] ); } // Apply client-side effects to the transformation matrix @@ -955,13 +948,12 @@ void CStudioModelRenderer::StudioSetupBones ( void ) } else { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + ConcatTransforms( (*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i] ); + ConcatTransforms( (*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i] ); } } } - /* ==================== StudioSaveBones @@ -970,14 +962,14 @@ StudioSaveBones */ void CStudioModelRenderer::StudioSaveBones( void ) { - int i; + int i; - mstudiobone_t *pbones; - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + mstudiobone_t *pbones; + pbones = (mstudiobone_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->boneindex ); m_nCachedBones = m_pStudioHeader->numbones; - for (i = 0; i < m_pStudioHeader->numbones; i++) + for( i = 0; i < m_pStudioHeader->numbones; i++ ) { strcpy( m_nCachedBoneNames[i], pbones[i].name ); MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); @@ -985,59 +977,57 @@ void CStudioModelRenderer::StudioSaveBones( void ) } } - /* ==================== StudioMergeBones ==================== */ -void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) +void CStudioModelRenderer::StudioMergeBones( model_t *m_pSubModel ) { - int i, j; - double f; - int do_hunt = true; + int i, j; + double f; + int do_hunt = true; - mstudiobone_t *pbones; - mstudioseqdesc_t *pseqdesc; - mstudioanim_t *panim; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; - static float pos[MAXSTUDIOBONES][3]; - float bonematrix[3][4]; - static vec4_t q[MAXSTUDIOBONES]; + static float pos[MAXSTUDIOBONES][3]; + float bonematrix[3][4]; + static vec4_t q[MAXSTUDIOBONES]; - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + if( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) { m_pCurrentEntity->curstate.sequence = 0; } - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame( pseqdesc ); - if (m_pCurrentEntity->latched.prevframe > f) + if( m_pCurrentEntity->latched.prevframe > f ) { - //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + //Con_DPrintf( "%f %f\n", m_pCurrentEntity->prevframe, f ); } panim = StudioGetAnim( m_pSubModel, pseqdesc ); StudioCalcRotations( pos, q, pseqdesc, panim, f ); - pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + pbones = (mstudiobone_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->boneindex ); - - for (i = 0; i < m_pStudioHeader->numbones; i++) + for( i = 0; i < m_pStudioHeader->numbones; i++ ) { - for (j = 0; j < m_nCachedBones; j++) + for( j = 0; j < m_nCachedBones; j++ ) { - if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) + if( stricmp( pbones[i].name, m_nCachedBoneNames[j] ) == 0 ) { MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); break; } } - if (j >= m_nCachedBones) + if( j >= m_nCachedBones ) { QuaternionMatrix( q[i], bonematrix ); @@ -1045,20 +1035,20 @@ void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; - if (pbones[i].parent == -1) + if( pbones[i].parent == -1 ) { - if ( IEngineStudio.IsHardware() ) + if( IEngineStudio.IsHardware() ) { - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_pbonetransform)[i] ); // MatrixCopy should be faster... - //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + //ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_plighttransform)[i] ); MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); } else { - ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + ConcatTransforms( (*m_paliastransform), bonematrix, (*m_pbonetransform)[i] ); + ConcatTransforms( (*m_protationmatrix), bonematrix, (*m_plighttransform)[i] ); } // Apply client-side effects to the transformation matrix @@ -1066,8 +1056,8 @@ void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) } else { - ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); - ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + ConcatTransforms( (*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i] ); + ConcatTransforms( (*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i] ); } } } @@ -1089,18 +1079,18 @@ int CStudioModelRenderer::StudioDrawModel( int flags ) IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) + if( m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer ) { entity_state_t deadplayer; int result; int save_interp; - if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) + if( m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) return 0; // get copy of player - deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; + deadplayer = *( IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 ) ); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt - 1]; // clear weapon, movement state deadplayer.number = m_pCurrentEntity->curstate.renderamt; @@ -1122,65 +1112,65 @@ int CStudioModelRenderer::StudioDrawModel( int flags ) } m_pRenderModel = m_pCurrentEntity->model; - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( m_pRenderModel ); IEngineStudio.StudioSetHeader( m_pStudioHeader ); IEngineStudio.SetRenderModel( m_pRenderModel ); StudioSetUpTransform( 0 ); - if (flags & STUDIO_RENDER) + if( flags & STUDIO_RENDER ) { // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) + if( !IEngineStudio.StudioCheckBBox() ) return 0; - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie + ( *m_pModelsDrawn )++; + ( *m_pStudioModelCount )++; // render data cache cookie - if (m_pStudioHeader->numbodyparts == 0) + if( m_pStudioHeader->numbodyparts == 0 ) return 1; } - if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + if( m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW ) { StudioMergeBones( m_pRenderModel ); } else { - StudioSetupBones( ); + StudioSetupBones(); } - StudioSaveBones( ); + StudioSaveBones(); - if (flags & STUDIO_EVENTS) + if( flags & STUDIO_EVENTS ) { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); + StudioCalcAttachments(); + IEngineStudio.StudioClientEvents(); // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) + if( m_pCurrentEntity->index > 0 ) { cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4 ); } } - if (flags & STUDIO_RENDER) + if( flags & STUDIO_RENDER ) { lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + IEngineStudio.StudioDynamicLight( m_pCurrentEntity, &lighting ); IEngineStudio.StudioEntityLight( &lighting ); // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); + IEngineStudio.StudioSetupLighting( &lighting ); // get remap colors m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; - m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + m_nBottomColor = ( m_pCurrentEntity->curstate.colormap & 0xFF00 ) >> 8; IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - StudioRenderModel( ); + StudioRenderModel(); } return 1; @@ -1197,25 +1187,25 @@ void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) float dt; vec3_t est_velocity; - dt = (m_clTime - m_clOldTime); - if (dt < 0) + dt = ( m_clTime - m_clOldTime ); + if( dt < 0 ) dt = 0; - else if (dt > 1.0) + else if( dt > 1.0 ) dt = 1; - if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + if( dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount ) { m_flGaitMovement = 0; return; } // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); - if ( m_fGaitEstimation ) + if( m_fGaitEstimation ) { VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); m_flGaitMovement = Length( est_velocity ); - if (dt <= 0 || m_flGaitMovement / dt < 5) + if( dt <= 0 || m_flGaitMovement / dt < 5 ) { m_flGaitMovement = 0; est_velocity[0] = 0; @@ -1228,34 +1218,33 @@ void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) m_flGaitMovement = Length( est_velocity ) * dt; } - if (est_velocity[1] == 0 && est_velocity[0] == 0) + if( est_velocity[1] == 0 && est_velocity[0] == 0 ) { float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) + flYawDiff = flYawDiff - (int)( flYawDiff / 360 ) * 360; + if( flYawDiff > 180 ) flYawDiff -= 360; - if (flYawDiff < -180) + if( flYawDiff < -180 ) flYawDiff += 360; - if (dt < 0.25) + if( dt < 0.25 ) flYawDiff *= dt * 4; else flYawDiff *= dt; m_pPlayerInfo->gaityaw += flYawDiff; - m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)( m_pPlayerInfo->gaityaw / 360 ) * 360; m_flGaitMovement = 0; } else { - m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = ( atan2( est_velocity[1], est_velocity[0] ) * 180 / M_PI ); + if( m_pPlayerInfo->gaityaw > 180 ) m_pPlayerInfo->gaityaw = 180; - if (m_pPlayerInfo->gaityaw < -180) + if( m_pPlayerInfo->gaityaw < -180 ) m_pPlayerInfo->gaityaw = -180; } - } /* @@ -1266,17 +1255,17 @@ StudioProcessGait */ void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) { - mstudioseqdesc_t *pseqdesc; + mstudioseqdesc_t *pseqdesc; float dt; int iBlend; float flYaw; // view direction relative to movement - if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + if( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) { m_pCurrentEntity->curstate.sequence = 0; } - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + m_pCurrentEntity->curstate.sequence; StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); @@ -1285,33 +1274,33 @@ void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; - // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + // Con_DPrintf( "%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); - dt = (m_clTime - m_clOldTime); - if (dt < 0) + dt = ( m_clTime - m_clOldTime ); + if( dt < 0 ) dt = 0; - else if (dt > 1.0) + else if( dt > 1.0 ) dt = 1; StudioEstimateGait( pplayer ); - // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + // Con_DPrintf( "%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); // calc side to side turning flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; - flYaw = flYaw - (int)(flYaw / 360) * 360; - if (flYaw < -180) + flYaw = flYaw - (int)( flYaw / 360 ) * 360; + if( flYaw < -180 ) flYaw = flYaw + 360; - if (flYaw > 180) + if( flYaw > 180 ) flYaw = flYaw - 360; - if (flYaw > 120) + if( flYaw > 120 ) { m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; m_flGaitMovement = -m_flGaitMovement; flYaw = flYaw - 180; } - else if (flYaw < -120) + else if( flYaw < -120 ) { m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; m_flGaitMovement = -m_flGaitMovement; @@ -1319,31 +1308,31 @@ void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) } // adjust torso - m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); - m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[0] = ( ( flYaw / 4.0 ) + 30 ) / ( 60.0 / 255.0 ); + m_pCurrentEntity->curstate.controller[1] = ( ( flYaw / 4.0 ) + 30 ) / ( 60.0 / 255.0 ); + m_pCurrentEntity->curstate.controller[2] = ( ( flYaw / 4.0 ) + 30 ) / ( 60.0 / 255.0 ); + m_pCurrentEntity->curstate.controller[3] = ( ( flYaw / 4.0 ) + 30 ) / ( 60.0 / 255.0 ); m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; - if (m_pCurrentEntity->angles[YAW] < -0) + if( m_pCurrentEntity->angles[YAW] < -0 ) m_pCurrentEntity->angles[YAW] += 360; m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; - if (pplayer->gaitsequence >= m_pStudioHeader->numseq) + if( pplayer->gaitsequence >= m_pStudioHeader->numseq ) { pplayer->gaitsequence = 0; } - pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + pseqdesc = (mstudioseqdesc_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->seqindex ) + pplayer->gaitsequence; // calc gait frame - if (pseqdesc->linearmovement[0] > 0) + if( pseqdesc->linearmovement[0] > 0 ) { - m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + m_pPlayerInfo->gaitframe += ( m_flGaitMovement / pseqdesc->linearmovement[0] ) * pseqdesc->numframes; } else { @@ -1352,7 +1341,7 @@ void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) // do modulo m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; - if (m_pPlayerInfo->gaitframe < 0) + if( m_pPlayerInfo->gaitframe < 0 ) m_pPlayerInfo->gaitframe += pseqdesc->numframes; } @@ -1372,32 +1361,32 @@ int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); - // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + // Con_DPrintf( "DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); - // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); + // Con_DPrintf( "DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); m_nPlayerIndex = pplayer->number - 1; - if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + if( m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients() ) return 0; m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); - if (m_pRenderModel == NULL) + if( m_pRenderModel == NULL ) return 0; - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( m_pRenderModel ); IEngineStudio.StudioSetHeader( m_pStudioHeader ); IEngineStudio.SetRenderModel( m_pRenderModel ); - if (pplayer->gaitsequence) + if( pplayer->gaitsequence ) { vec3_t orig_angles; m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); VectorCopy( m_pCurrentEntity->angles, orig_angles ); - + StudioProcessGait( pplayer ); m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; @@ -1416,102 +1405,102 @@ int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; - + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); m_pPlayerInfo->gaitsequence = 0; StudioSetUpTransform( 0 ); } - if (flags & STUDIO_RENDER) + if( flags & STUDIO_RENDER ) { // see if the bounding box lets us trivially reject, also sets - if (!IEngineStudio.StudioCheckBBox ()) + if( !IEngineStudio.StudioCheckBBox () ) return 0; - (*m_pModelsDrawn)++; - (*m_pStudioModelCount)++; // render data cache cookie + ( *m_pModelsDrawn )++; + ( *m_pStudioModelCount )++; // render data cache cookie - if (m_pStudioHeader->numbodyparts == 0) + if( m_pStudioHeader->numbodyparts == 0 ) return 1; } m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); - StudioSetupBones( ); - StudioSaveBones( ); + StudioSetupBones(); + StudioSaveBones(); m_pPlayerInfo->renderframe = m_nFrameCount; m_pPlayerInfo = NULL; - if (flags & STUDIO_EVENTS) + if( flags & STUDIO_EVENTS ) { - StudioCalcAttachments( ); - IEngineStudio.StudioClientEvents( ); + StudioCalcAttachments(); + IEngineStudio.StudioClientEvents(); // copy attachments into global entity array - if ( m_pCurrentEntity->index > 0 ) + if( m_pCurrentEntity->index > 0 ) { cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); - memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4 ); } } - if (flags & STUDIO_RENDER) + if( flags & STUDIO_RENDER ) { - if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + if( m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) { // show highest resolution multiplayer model m_pCurrentEntity->curstate.body = 255; } - if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + if( !( m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) { m_pCurrentEntity->curstate.body = 1; // force helmet } lighting.plightvec = dir; - IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + IEngineStudio.StudioDynamicLight( m_pCurrentEntity, &lighting ); IEngineStudio.StudioEntityLight( &lighting ); // model and frame independant - IEngineStudio.StudioSetupLighting (&lighting); + IEngineStudio.StudioSetupLighting( &lighting ); m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); // get remap colors m_nTopColor = m_pPlayerInfo->topcolor; m_nBottomColor = m_pPlayerInfo->bottomcolor; - if (m_nTopColor < 0) + if( m_nTopColor < 0 ) m_nTopColor = 0; - if (m_nTopColor > 360) + if( m_nTopColor > 360 ) m_nTopColor = 360; - if (m_nBottomColor < 0) + if( m_nBottomColor < 0 ) m_nBottomColor = 0; - if (m_nBottomColor > 360) + if( m_nBottomColor > 360 ) m_nBottomColor = 360; IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - StudioRenderModel( ); + StudioRenderModel(); m_pPlayerInfo = NULL; - if (pplayer->weaponmodel) + if( pplayer->weaponmodel ) { cl_entity_t saveent = *m_pCurrentEntity; model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); - m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( pweaponmodel ); IEngineStudio.StudioSetHeader( m_pStudioHeader ); - StudioMergeBones( pweaponmodel); + StudioMergeBones( pweaponmodel ); - IEngineStudio.StudioSetupLighting (&lighting); + IEngineStudio.StudioSetupLighting( &lighting ); - StudioRenderModel( ); + StudioRenderModel(); - StudioCalcAttachments( ); + StudioCalcAttachments(); *m_pCurrentEntity = saveent; } @@ -1531,17 +1520,17 @@ void CStudioModelRenderer::StudioCalcAttachments( void ) int i; mstudioattachment_t *pattachment; - if ( m_pStudioHeader->numattachments > 4 ) + if( m_pStudioHeader->numattachments > 4 ) { gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); exit( -1 ); } // calculate attachment points - pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); - for (i = 0; i < m_pStudioHeader->numattachments; i++) + pattachment = (mstudioattachment_t *)( (byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex ); + for( i = 0; i < m_pStudioHeader->numattachments; i++ ) { - VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); + VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); } } @@ -1556,12 +1545,12 @@ void CStudioModelRenderer::StudioRenderModel( void ) IEngineStudio.SetChromeOrigin(); IEngineStudio.SetForceFaceFlags( 0 ); - if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) + if( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) { m_pCurrentEntity->curstate.renderfx = kRenderFxNone; - StudioRenderFinal( ); - - if ( !IEngineStudio.IsHardware() ) + StudioRenderFinal(); + + if( !IEngineStudio.IsHardware() ) { gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); } @@ -1571,15 +1560,15 @@ void CStudioModelRenderer::StudioRenderModel( void ) gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; - StudioRenderFinal( ); - if ( !IEngineStudio.IsHardware() ) + StudioRenderFinal(); + if( !IEngineStudio.IsHardware() ) { gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); } } else { - StudioRenderFinal( ); + StudioRenderFinal(); } } @@ -1596,35 +1585,35 @@ void CStudioModelRenderer::StudioRenderFinal_Software( void ) // Note, rendermode set here has effect in SW IEngineStudio.SetupRenderer( 0 ); - if (m_pCvarDrawEntities->value == 2) + if( m_pCvarDrawEntities->value == 2 ) { - IEngineStudio.StudioDrawBones( ); + IEngineStudio.StudioDrawBones(); } - else if (m_pCvarDrawEntities->value == 3) + else if( m_pCvarDrawEntities->value == 3 ) { - IEngineStudio.StudioDrawHulls( ); + IEngineStudio.StudioDrawHulls(); } else { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) { IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - IEngineStudio.StudioDrawPoints( ); + IEngineStudio.StudioDrawPoints(); } } - if (m_pCvarDrawEntities->value == 4) + if( m_pCvarDrawEntities->value == 4 ) { gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); + IEngineStudio.StudioDrawHulls(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); } - if (m_pCvarDrawEntities->value == 5) + if( m_pCvarDrawEntities->value == 5 ) { - IEngineStudio.StudioDrawAbsBBox( ); + IEngineStudio.StudioDrawAbsBBox(); } - + IEngineStudio.RestoreRenderer(); } @@ -1641,22 +1630,22 @@ void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; IEngineStudio.SetupRenderer( rendermode ); - - if (m_pCvarDrawEntities->value == 2) + + if( m_pCvarDrawEntities->value == 2 ) { IEngineStudio.StudioDrawBones(); } - else if (m_pCvarDrawEntities->value == 3) + else if( m_pCvarDrawEntities->value == 3 ) { IEngineStudio.StudioDrawHulls(); } else { - for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) { IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); - if (m_fDoInterp) + if( m_fDoInterp ) { // interpolation messes up bounding boxes. m_pCurrentEntity->trivial_accept = 0; @@ -1668,16 +1657,16 @@ void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) } } - if ( m_pCvarDrawEntities->value == 4 ) + if( m_pCvarDrawEntities->value == 4 ) { gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - IEngineStudio.StudioDrawHulls( ); + IEngineStudio.StudioDrawHulls(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); } - if (m_pCvarDrawEntities->value == 5) + if( m_pCvarDrawEntities->value == 5 ) { - IEngineStudio.StudioDrawAbsBBox( ); + IEngineStudio.StudioDrawAbsBBox(); } IEngineStudio.RestoreRenderer(); @@ -1689,9 +1678,9 @@ StudioRenderFinal ==================== */ -void CStudioModelRenderer::StudioRenderFinal(void) +void CStudioModelRenderer::StudioRenderFinal( void ) { - if ( IEngineStudio.IsHardware() ) + if( IEngineStudio.IsHardware() ) { StudioRenderFinal_Hardware(); } @@ -1700,4 +1689,3 @@ void CStudioModelRenderer::StudioRenderFinal(void) StudioRenderFinal_Software(); } } - diff --git a/cl_dll/StudioModelRenderer.h b/cl_dll/StudioModelRenderer.h index 8f1427ff..0a56b731 100644 --- a/cl_dll/StudioModelRenderer.h +++ b/cl_dll/StudioModelRenderer.h @@ -27,76 +27,76 @@ public: // Initialization virtual void Init( void ); -public: +public: // Public Interfaces - virtual int StudioDrawModel ( int flags ); - virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); + virtual int StudioDrawModel( int flags ); + virtual int StudioDrawPlayer( int flags, struct entity_state_s *pplayer ); public: // Local interfaces // // Look up animation data for sequence - virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); + virtual mstudioanim_t *StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); // Interpolate model position and angles and set up matrices - virtual void StudioSetUpTransform (int trivial_accept); + virtual void StudioSetUpTransform( int trivial_accept ); // Set up model bone positions - virtual void StudioSetupBones ( void ); + virtual void StudioSetupBones( void ); // Find final attachment points - virtual void StudioCalcAttachments ( void ); + virtual void StudioCalcAttachments( void ); // Save bone matrices and names virtual void StudioSaveBones( void ); // Merge cached bones with current bones for model - virtual void StudioMergeBones ( model_t *m_pSubModel ); + virtual void StudioMergeBones( model_t *m_pSubModel ); // Determine interpolation fraction virtual float StudioEstimateInterpolant( void ); // Determine current frame for rendering - virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); + virtual float StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ); // Apply special effects to transform matrix virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); // Spherical interpolation of bones - virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); + virtual void StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); - // Compute bone adjustments ( bone controllers ) - virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); + // Compute bone adjustments( bone controllers ) + virtual void StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); // Get bone quaternions - virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); + virtual void StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); // Get bone positions - virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); + virtual void StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); // Compute rotations - virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); + virtual void StudioCalcRotations( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); // Send bones and verts to renderer - virtual void StudioRenderModel ( void ); + virtual void StudioRenderModel( void ); // Finalize rendering - virtual void StudioRenderFinal (void); + virtual void StudioRenderFinal( void ); // GL&D3D vs. Software renderer finishing functions - virtual void StudioRenderFinal_Software ( void ); - virtual void StudioRenderFinal_Hardware ( void ); + virtual void StudioRenderFinal_Software( void ); + virtual void StudioRenderFinal_Hardware( void ); // Player specific data // Determine pitch and blending amounts for players - virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); + virtual void StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); // Estimate gait frame for player - virtual void StudioEstimateGait ( entity_state_t *pplayer ); + virtual void StudioEstimateGait( entity_state_t *pplayer ); // Process movement of player - virtual void StudioProcessGait ( entity_state_t *pplayer ); + virtual void StudioProcessGait( entity_state_t *pplayer ); public: @@ -145,7 +145,7 @@ public: mstudiomodel_t *m_pSubModel; // Palette substition for top and bottom of model - int m_nTopColor; + int m_nTopColor; int m_nBottomColor; // @@ -156,34 +156,34 @@ public: // Number of bones in bone cache int m_nCachedBones; // Names of cached bones - char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; + char m_nCachedBoneNames[MAXSTUDIOBONES][32]; // Cached bone & light transformation matrices - float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float m_rgCachedBoneTransform[MAXSTUDIOBONES][3][4]; + float m_rgCachedLightTransform[MAXSTUDIOBONES][3][4]; // Software renderer scale factors float m_fSoftwareXScale, m_fSoftwareYScale; // Current view vectors and render origin - float m_vUp[ 3 ]; - float m_vRight[ 3 ]; - float m_vNormal[ 3 ]; + float m_vUp[3]; + float m_vRight[3]; + float m_vNormal[3]; + + float m_vRenderOrigin[3]; - float m_vRenderOrigin[ 3 ]; - // Model render counters ( from engine ) int *m_pStudioModelCount; int *m_pModelsDrawn; // Matrices // Model to world transformation - float (*m_protationmatrix)[ 3 ][ 4 ]; + float (*m_protationmatrix)[3][4]; // Model to view transformation - float (*m_paliastransform)[ 3 ][ 4 ]; + float (*m_paliastransform)[3][4]; // Concatenated bone and light transforms - float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; - float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float (*m_pbonetransform)[MAXSTUDIOBONES][3][4]; + float (*m_plighttransform)[MAXSTUDIOBONES][3][4]; }; -#endif // STUDIOMODELRENDERER_H \ No newline at end of file +#endif // STUDIOMODELRENDERER_H diff --git a/dlls/decals.h b/dlls/decals.h index dd13fafe..ce5a2b53 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -66,8 +66,8 @@ enum decal_e typedef struct { - char *name; - int index; + char *name; + int index; } DLL_DECALLIST; extern DLL_DECALLIST gDecals[]; diff --git a/dlls/extdll.h b/dlls/extdll.h index 659f9a0a..be2df7e8 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -15,7 +15,6 @@ #ifndef EXTDLL_H #define EXTDLL_H - // // Global header file for extension DLLs // @@ -57,15 +56,14 @@ typedef int BOOL; #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif - // 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 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 @@ -84,5 +82,4 @@ typedef float vec_t; // needed before including progdefs.h // Shared header between the client DLL and the game DLLs #include "cdll_dll.h" - #endif //EXTDLL_H diff --git a/dlls/leech.cpp b/dlls/leech.cpp index 8bb9b0c5..ea524aaa 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -46,14 +46,14 @@ // 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 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 @@ -71,10 +71,10 @@ public: void EXPORT DeadThink( void ); void Touch( CBaseEntity *pOther ) { - if ( pOther->IsPlayer() ) + if( pOther->IsPlayer() ) { // If the client is pushing me, give me some base velocity - if ( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) + if( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) { pev->basevelocity = pOther->pev->velocity; pev->flags |= FL_BASEVELOCITY; @@ -84,8 +84,8 @@ public: void SetObjectCollisionBox( void ) { - pev->absmin = pev->origin + Vector(-8,-8,0); - pev->absmax = pev->origin + Vector(8,8,2); + pev->absmin = pev->origin + Vector( -8, -8, 0 ); + pev->absmax = pev->origin + Vector( 8, 8, 2 ); } void AttackSound( void ); @@ -98,38 +98,38 @@ public: // Base entity functions void HandleAnimEvent( MonsterEvent_t *pEvent ); - int BloodColor( void ) { return DONT_BLEED; } + 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 Classify( void ) { return CLASS_INSECT; } int IRelationship( CBaseEntity *pTarget ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + 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; + 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; + CBeam *m_pb; + CBeam *m_pt; #endif }; @@ -169,20 +169,20 @@ const char *CLeech::pAlertSounds[] = void CLeech::Spawn( void ) { Precache(); - SET_MODEL(ENT(pev), "models/leech.mdl"); + SET_MODEL( ENT( pev ), "models/leech.mdl" ); // Just for fun - // SET_MODEL(ENT(pev), "models/icky.mdl"); + // 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)); + 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; + 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; + m_flFieldOfView = -0.5; // 180 degree FOV + m_flDistLook = 750; MonsterInit(); SetThink( &CLeech::SwimThink ); SetUse( NULL ); @@ -204,12 +204,12 @@ void CLeech::Activate( void ) void CLeech::RecalculateWaterlevel( void ) { // Calculate boundaries - Vector vecTest = pev->origin - Vector(0,0,400); + Vector vecTest = pev->origin - Vector( 0, 0, 400 ); TraceResult tr; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if ( tr.flFraction != 1.0 ) + UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); + if( tr.flFraction != 1.0 ) m_bottom = tr.vecEndPos.z + 1; else m_bottom = vecTest.z; @@ -227,7 +227,7 @@ void CLeech::RecalculateWaterlevel( void ) void CLeech::SwitchLeechState( void ) { m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); - if ( m_MonsterState == MONSTERSTATE_COMBAT ) + if( m_MonsterState == MONSTERSTATE_COMBAT ) { m_hEnemy = NULL; SetState( MONSTERSTATE_IDLE ); @@ -238,7 +238,7 @@ void CLeech::SwitchLeechState( void ) { Look( m_flDistLook ); CBaseEntity *pEnemy = BestVisibleEnemy(); - if ( pEnemy && pEnemy->pev->waterlevel != 0 ) + if( pEnemy && pEnemy->pev->waterlevel != 0 ) { m_hEnemy = pEnemy; SetState( MONSTERSTATE_COMBAT ); @@ -250,36 +250,36 @@ void CLeech::SwitchLeechState( void ) int CLeech::IRelationship( CBaseEntity *pTarget ) { - if ( pTarget->IsPlayer() ) + if( pTarget->IsPlayer() ) return R_DL; return CBaseMonster::IRelationship( pTarget ); } void CLeech::AttackSound( void ) { - if ( gpGlobals->time > m_attackSoundTime ) + 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 ); + 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 ); + 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 ) { int i; - //PRECACHE_MODEL("models/icky.mdl"); - PRECACHE_MODEL("models/leech.mdl"); + //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]); + 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 ) @@ -287,9 +287,9 @@ int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float f pev->velocity = g_vecZero; // Nudge the leech away from the damage - if ( pevInflictor ) + if( pevInflictor ) { - pev->velocity = (pev->origin - pevInflictor->origin).Normalize() * 25; + pev->velocity = ( pev->origin - pevInflictor->origin ).Normalize() * 25; } return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); @@ -304,7 +304,7 @@ void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) CBaseEntity *pEnemy; pEnemy = m_hEnemy; - if ( pEnemy != NULL ) + if( pEnemy != NULL ) { Vector dir, face; @@ -315,7 +315,7 @@ void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) dir = dir.Normalize(); face = face.Normalize(); - if ( DotProduct(dir, face) > 0.9 ) // Only take damage if the leech is facing the prey + 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; @@ -333,7 +333,7 @@ void CLeech::MakeVectors( void ) { Vector tmp = pev->angles; tmp.x = -tmp.x; - UTIL_MakeVectors ( tmp ); + UTIL_MakeVectors( tmp ); } // @@ -341,8 +341,8 @@ void CLeech::MakeVectors( void ) // float CLeech::ObstacleDistance( CBaseEntity *pTarget ) { - TraceResult tr; - Vector vecTest; + TraceResult tr; + Vector vecTest; // use VELOCITY, not angles, not all boids point the direction they are flying //Vector vecDir = UTIL_VecToAngles( pev->velocity ); @@ -350,58 +350,58 @@ float CLeech::ObstacleDistance( CBaseEntity *pTarget ) // check for obstacle ahead vecTest = pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); + UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - if ( tr.fStartSolid ) + 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 ); + //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( tr.flFraction != 1.0 ) { - if ( (pTarget == NULL || tr.pHit != pTarget->edict()) ) + if( ( pTarget == NULL || tr.pHit != pTarget->edict() ) ) { return tr.flFraction; } else { - if ( fabs(m_height - pev->origin.z) > 10 ) + if( fabs( m_height - pev->origin.z ) > 10 ) return tr.flFraction; } } - if ( m_sideTime < gpGlobals->time ) + 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) + 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) + 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); + m_sideTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); } return 1.0; } void CLeech::DeadThink( void ) { - if ( m_fSequenceFinished ) + if( m_fSequenceFinished ) { - if ( m_Activity == ACT_DIEFORWARD ) + if( m_Activity == ACT_DIEFORWARD ) { SetThink( NULL ); StopAnimation(); return; } - else if ( pev->flags & FL_ONGROUND ) + else if( pev->flags & FL_ONGROUND ) { pev->solid = SOLID_NOT; SetActivity(ACT_DIEFORWARD); @@ -411,13 +411,13 @@ void CLeech::DeadThink( void ) pev->nextthink = gpGlobals->time + 0.1; // Apply damage velocity, but keep out of the walls - if ( pev->velocity.x != 0 || pev->velocity.y != 0 ) + 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) + 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; @@ -427,27 +427,27 @@ void CLeech::DeadThink( void ) void CLeech::UpdateMotion( void ) { - float flapspeed = (pev->speed - m_flAccelerate) / LEECH_ACCELERATE; + float flapspeed = ( pev->speed - m_flAccelerate ) / LEECH_ACCELERATE; m_flAccelerate = m_flAccelerate * 0.8 + pev->speed * 0.2; - if (flapspeed < 0) + if( flapspeed < 0 ) flapspeed = -flapspeed; flapspeed += 1.0; - if (flapspeed < 0.5) + if( flapspeed < 0.5 ) flapspeed = 0.5; - if (flapspeed > 1.9) + if( flapspeed > 1.9 ) flapspeed = 1.9; pev->framerate = flapspeed; - if ( !m_fPathBlocked ) + if( !m_fPathBlocked ) pev->avelocity.y = pev->ideal_yaw; else pev->avelocity.y = pev->ideal_yaw * m_obstacle; - if ( pev->avelocity.y > 150 ) + if( pev->avelocity.y > 150 ) m_IdealActivity = ACT_TURN_LEFT; - else if ( pev->avelocity.y < -150 ) + else if( pev->avelocity.y < -150 ) m_IdealActivity = ACT_TURN_RIGHT; else m_IdealActivity = ACT_SWIM; @@ -456,9 +456,9 @@ void CLeech::UpdateMotion( void ) float targetPitch, delta; delta = m_height - pev->origin.z; - if ( delta < -10 ) + if( delta < -10 ) targetPitch = -30; - else if ( delta > 10 ) + else if( delta > 10 ) targetPitch = 30; else targetPitch = 0; @@ -466,13 +466,13 @@ void CLeech::UpdateMotion( void ) pev->angles.x = UTIL_Approach( targetPitch, pev->angles.x, 60 * LEECH_FRAMETIME ); // bank - pev->avelocity.z = - (pev->angles.z + (pev->avelocity.y * 0.25)); + pev->avelocity.z = -( pev->angles.z + ( pev->avelocity.y * 0.25 ) ); - if ( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + if( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) m_IdealActivity = ACT_MELEE_ATTACK1; // Out of water check - if ( !pev->waterlevel ) + if( !pev->waterlevel ) { pev->movetype = MOVETYPE_TOSS; m_IdealActivity = ACT_TWITCH; @@ -482,10 +482,10 @@ void CLeech::UpdateMotion( void ) pev->angles.z = 0; pev->angles.x = 0; - if ( pev->framerate < 1.0 ) + if( pev->framerate < 1.0 ) pev->framerate = 1.0; } - else if ( pev->movetype == MOVETYPE_TOSS ) + else if( pev->movetype == MOVETYPE_TOSS ) { pev->movetype = MOVETYPE_FLY; pev->flags &= ~FL_ONGROUND; @@ -493,25 +493,25 @@ void CLeech::UpdateMotion( void ) m_waterTime = gpGlobals->time + 2; // Recalc again soon, water may be rising } - if ( m_Activity != m_IdealActivity ) + if( m_Activity != m_IdealActivity ) { - SetActivity ( m_IdealActivity ); + SetActivity( m_IdealActivity ); } float flInterval = StudioFrameAdvance(); - DispatchAnimEvents ( flInterval ); + DispatchAnimEvents( flInterval ); #if DEBUG_BEAMS - if ( !m_pb ) + if( !m_pb ) m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - if ( !m_pt ) + 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 ) + 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 ) + if( m_obstacle == 1.0 ) color = 0; - if ( color > 255 ) + if( color > 255 ) color = 255; m_pb->SetColor( 255, (int)color, (int)color ); } @@ -523,16 +523,16 @@ void CLeech::UpdateMotion( void ) void CLeech::SwimThink( void ) { - TraceResult tr; - float flLeftSide; - float flRightSide; - float targetSpeed; - float targetYaw = 0; - CBaseEntity *pTarget; + TraceResult tr; + float flLeftSide; + float flRightSide; + float targetSpeed; + float targetYaw = 0; + CBaseEntity *pTarget; - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) + if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) { - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 1, 1.5 ); pev->velocity = g_vecZero; return; } @@ -541,10 +541,10 @@ void CLeech::SwimThink( void ) targetSpeed = LEECH_SWIM_SPEED; - if ( m_waterTime < gpGlobals->time ) + if( m_waterTime < gpGlobals->time ) RecalculateWaterlevel(); - if ( m_stateTime < gpGlobals->time ) + if( m_stateTime < gpGlobals->time ) SwitchLeechState(); ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); @@ -552,47 +552,47 @@ void CLeech::SwimThink( void ) { case MONSTERSTATE_COMBAT: pTarget = m_hEnemy; - if ( !pTarget ) + 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 ) + if( m_height < m_bottom ) m_height = m_bottom; - else if ( m_height > m_top ) + 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 ) + 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); + 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 ) + 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 ) + if( RANDOM_LONG( 0, 100 ) < 10 ) targetYaw = RANDOM_LONG( -30, 30 ); pTarget = NULL; // oldorigin test - if ( (pev->origin - pev->oldorigin).Length() < 1 ) + 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; @@ -602,14 +602,14 @@ void CLeech::SwimThink( void ) m_obstacle = ObstacleDistance( pTarget ); pev->oldorigin = pev->origin; - if ( m_obstacle < 0.1 ) + if( m_obstacle < 0.1 ) m_obstacle = 0.1; // is the way ahead clear? - if ( m_obstacle == 1.0 ) + if( m_obstacle == 1.0 ) { // if the leech is turning, stop the trend. - if ( m_flTurning != 0 ) + if( m_flTurning != 0 ) { m_flTurning = 0; } @@ -625,55 +625,55 @@ void CLeech::SwimThink( void ) // 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 + 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); + 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); + 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) ) + 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->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) +void CLeech::Killed( entvars_t *pevAttacker, int iGib ) { - Vector vecSplatDir; - TraceResult tr; + 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); + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); + if( pOwner ) + pOwner->DeathNotice( pev ); // When we hit the ground, play the "death_end" activity - if ( pev->waterlevel ) + 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 ) + if( RANDOM_LONG( 0, 99 ) < 70 ) pev->avelocity.y = RANDOM_LONG( -720, 720 ); pev->gravity = 0.02; - ClearBits(pev->flags, FL_ONGROUND); + ClearBits( pev->flags, FL_ONGROUND ); SetActivity( ACT_DIESIMPLE ); } else diff --git a/dlls/monsterevent.h b/dlls/monsterevent.h index 5d144750..ab54b687 100644 --- a/dlls/monsterevent.h +++ b/dlls/monsterevent.h @@ -18,9 +18,9 @@ typedef struct { - int event; - char *options; -} MonsterEvent_t; + int event; + char *options; +}MonsterEvent_t; #define EVENT_SPECIFIC 0 #define EVENT_SCRIPTED 1000 @@ -30,6 +30,5 @@ typedef struct #define MONSTER_EVENT_BODYDROP_LIGHT 2001 #define MONSTER_EVENT_BODYDROP_HEAVY 2002 -#define MONSTER_EVENT_SWISHSOUND 2010 - +#define MONSTER_EVENT_SWISHSOUND 2010 #endif //MONSTEREVENT_H diff --git a/dlls/monsters.h b/dlls/monsters.h index bf30ffcc..6f2df294 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -41,10 +41,10 @@ // 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_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. +#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 @@ -58,27 +58,27 @@ #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. +#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 +#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; +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 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 ); +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. @@ -140,20 +140,20 @@ class CGib : public CBaseEntity { public: void Spawn( const char *szGibModel ); - void EXPORT BounceGibTouch ( CBaseEntity *pOther ); - void EXPORT StickyGibTouch ( CBaseEntity *pOther ); + void EXPORT BounceGibTouch( CBaseEntity *pOther ); + void EXPORT StickyGibTouch( CBaseEntity *pOther ); void EXPORT WaitTillLand( void ); - void LimitVelocity( 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 ); + 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; + int m_bloodColor; + int m_cBloodDecals; + int m_material; + float m_lifeTime; }; #define CUSTOM_SCHEDULES\ @@ -166,10 +166,9 @@ public: #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);\ + Schedule_t *pSchedule = ScheduleInList( pName, m_scheduleList, ARRAYSIZE( m_scheduleList ) );\ + if( !pSchedule )\ + return baseClass::ScheduleFromName( pName );\ return pSchedule;\ } - #endif //MONSTERS_H diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 850bf549..7d05d5e1 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -45,11 +45,11 @@ int CMP5::SecondaryAmmoIndex( void ) return m_iSecondaryAmmoType; } -void CMP5::Spawn( ) +void CMP5::Spawn() { - pev->classname = MAKE_STRING("weapon_9mmAR"); // hack to allow for old names - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmAR.mdl"); + 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; @@ -59,36 +59,36 @@ void CMP5::Spawn( ) void CMP5::Precache( void ) { - PRECACHE_MODEL("models/v_9mmAR.mdl"); - PRECACHE_MODEL("models/w_9mmAR.mdl"); - PRECACHE_MODEL("models/p_9mmAR.mdl"); + 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 + m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shellTE_MODEL - PRECACHE_MODEL("models/grenade.mdl"); // grenade + PRECACHE_MODEL( "models/grenade.mdl" ); // grenade - PRECACHE_MODEL("models/w_9mmARclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_MODEL( "models/w_9mmARclip.mdl" ); + PRECACHE_SOUND( "items/9mmclip1.wav" ); - PRECACHE_SOUND("items/clipinsert1.wav"); - PRECACHE_SOUND("items/cliprelease1.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/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"); + 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) +int CMP5::GetItemInfo( ItemInfo *p ) { - p->pszName = STRING(pev->classname); + p->pszName = STRING( pev->classname ); p->pszAmmo1 = "9mm"; p->iMaxAmmo1 = _9MM_MAX_CARRY; p->pszAmmo2 = "ARgrenades"; @@ -105,7 +105,7 @@ int CMP5::GetItemInfo(ItemInfo *p) int CMP5::AddToPlayer( CBasePlayer *pPlayer ) { - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); @@ -115,7 +115,7 @@ int CMP5::AddToPlayer( CBasePlayer *pPlayer ) return FALSE; } -BOOL CMP5::Deploy( ) +BOOL CMP5::Deploy() { return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); } @@ -123,14 +123,14 @@ BOOL CMP5::Deploy( ) void CMP5::PrimaryAttack() { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { - PlayEmptySound( ); + PlayEmptySound(); m_flNextPrimaryAttack = 0.15; return; } - if (m_iClip <= 0) + if( m_iClip <= 0 ) { PlayEmptySound(); m_flNextPrimaryAttack = 0.15; @@ -142,18 +142,18 @@ void CMP5::PrimaryAttack() m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + 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 vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; #ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) + if( !bIsMultiplayer() ) #else - if ( !g_pGameRules->IsMultiplayer() ) + if( !g_pGameRules->IsMultiplayer() ) #endif { // optimized multiplayer. Widened to make it easier to hit a moving player @@ -173,13 +173,13 @@ void CMP5::PrimaryAttack() #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) + 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_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) + if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); @@ -188,16 +188,16 @@ void CMP5::PrimaryAttack() void CMP5::SecondaryAttack( void ) { // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) + if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound( ); m_flNextPrimaryAttack = 0.15; return; } - if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0) + if( m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0 ) { - PlayEmptySound( ); + PlayEmptySound(); return; } @@ -206,7 +206,7 @@ void CMP5::SecondaryAttack( void ) m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; - + m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; // player "shoot" animation @@ -215,9 +215,9 @@ void CMP5::SecondaryAttack( void ) 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 ); + 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 ) @@ -226,19 +226,19 @@ void CMP5::SecondaryAttack( void ) flags = 0; #endif PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. - if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]) + if( !m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] ) // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); } void CMP5::Reload( void ) { - if ( m_pPlayer->ammo_9mm <= 0 ) + if( m_pPlayer->ammo_9mm <= 0 ) return; DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); @@ -246,20 +246,19 @@ void CMP5::Reload( void ) void CMP5::WeaponIdle( void ) { - ResetEmptySound( ); + ResetEmptySound(); m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; - switch ( RANDOM_LONG( 0, 1 ) ) + switch( RANDOM_LONG( 0, 1 ) ) { case 0: iAnim = MP5_LONGIDLE; break; - default: case 1: iAnim = MP5_IDLE1; @@ -274,22 +273,22 @@ void CMP5::WeaponIdle( void ) class CMP5AmmoClip : public CBasePlayerAmmo { void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl"); - CBasePlayerAmmo::Spawn( ); + { + 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"); + 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) + 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); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); } return bResult; } @@ -302,21 +301,21 @@ class CMP5Chainammo : public CBasePlayerAmmo { void Spawn( void ) { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); + 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"); + 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) + 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); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); } return bResult; } @@ -327,23 +326,23 @@ 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( ); + { + 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"); + 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); + int bResult = ( pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1 ); - if (bResult) + if( bResult ) { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); } return bResult; } diff --git a/dlls/plats.cpp b/dlls/plats.cpp index e4e30ef1..93fb22fe 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -33,20 +33,20 @@ static void PlatSpawnInsideTrigger(entvars_t* pevPlatform); class CBasePlatTrain : public CBaseToggle { public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + 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 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[]; + 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 + 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[] = @@ -58,41 +58,41 @@ TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ) -void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) +void CBasePlatTrain::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "lip")) + if( FStrEq( pkvd->szKeyName, "lip" ) ) { - m_flLip = atof(pkvd->szValue); + m_flLip = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "wait")) + else if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_flWait = atof(pkvd->szValue); + m_flWait = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "height")) + else if( FStrEq( pkvd->szKeyName, "height" ) ) { - m_flHeight = atof(pkvd->szValue); + m_flHeight = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "rotation")) + else if( FStrEq( pkvd->szKeyName, "rotation" ) ) { - m_vecFinalAngle.x = atof(pkvd->szValue); + m_vecFinalAngle.x = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "movesnd")) + else if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof(pkvd->szValue); + m_bMoveSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) + else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) { - m_bStopSnd = atof(pkvd->szValue); + m_bStopSnd = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "volume")) + else if( FStrEq( pkvd->szKeyName, "volume" ) ) { - m_volume = atof(pkvd->szValue); + m_volume = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -105,109 +105,108 @@ void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) void CBasePlatTrain::Precache( void ) { // set the plat's "in-motion" sound - switch (m_bMoveSnd) + switch( m_bMoveSnd ) { - case 0: - pev->noiseMoving = MAKE_STRING("common/null.wav"); + case 0: + pev->noiseMoving = MAKE_STRING( "common/null.wav" ); break; - case 1: - PRECACHE_SOUND ("plats/bigmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove1.wav"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + case 13: + PRECACHE_SOUND( "plats/talkmove2.wav" ); + pev->noiseMoving = MAKE_STRING( "plats/talkmove2.wav" ); break; default: - pev->noiseMoving = MAKE_STRING("common/null.wav"); + pev->noiseMoving = MAKE_STRING( "common/null.wav" ); break; } // set the plat's 'reached destination' stop sound - switch (m_bStopSnd) + switch( m_bStopSnd ) { - case 0: - pev->noiseArrived = MAKE_STRING("common/null.wav"); + case 0: + pev->noiseArrived = MAKE_STRING( "common/null.wav" ); break; - case 1: - PRECACHE_SOUND ("plats/bigstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop1.wav"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + case 8: + PRECACHE_SOUND( "plats/talkstop1.wav" ); + pev->noiseArrived = MAKE_STRING( "plats/talkstop1.wav" ); break; - default: - pev->noiseArrived = MAKE_STRING("common/null.wav"); + pev->noiseArrived = MAKE_STRING( "common/null.wav" ); break; } } @@ -230,9 +229,9 @@ public: 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(); } + void EXPORT CallGoDown( void ) { GoDown(); } + void EXPORT CallHitTop( void ) { HitTop(); } + void EXPORT CallHitBottom( void ) { HitBottom(); } virtual void GoUp( void ); virtual void GoDown( void ); @@ -246,7 +245,7 @@ LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ) class CPlatTrigger : public CBaseEntity { public: - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } + virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } void SpawnInsideTrigger( CFuncPlat *pPlatform ); void Touch( CBaseEntity *pOther ); CFuncPlat *m_pPlatform; @@ -268,49 +267,49 @@ Set "sounds" to one of the following: 2) chain slow */ -void CFuncPlat :: Setup( void ) +void CFuncPlat::Setup( void ) { - //pev->noiseMovement = MAKE_STRING("plats/platmove1.wav"); - //pev->noiseStopMoving = MAKE_STRING("plats/platstop1.wav"); + //pev->noiseMovement = MAKE_STRING( "plats/platmove1.wav" ); + //pev->noiseStopMoving = MAKE_STRING( "plats/platstop1.wav" ); - if (m_flTLength == 0) + if( m_flTLength == 0 ) m_flTLength = 80; - if (m_flTWidth == 0) + if( m_flTWidth == 0 ) m_flTWidth = 10; - pev->angles = g_vecZero; + pev->angles = g_vecZero; - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + 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) ); + 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) + 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) + if( pev->speed == 0 ) pev->speed = 150; - if ( m_volume == 0 ) + if( m_volume == 0 ) m_volume = 0.85; } -void CFuncPlat :: Precache( ) +void CFuncPlat::Precache() { CBasePlatTrain::Precache(); - //PRECACHE_SOUND("plats/platmove1.wav"); - //PRECACHE_SOUND("plats/platstop1.wav"); - if ( !IsTogglePlat() ) + //PRECACHE_SOUND( "plats/platmove1.wav" ); + //PRECACHE_SOUND( "plats/platstop1.wav" ); + if( !IsTogglePlat() ) PlatSpawnInsideTrigger( pev ); // the "start moving" trigger } -void CFuncPlat :: Spawn( ) +void CFuncPlat::Spawn() { Setup(); @@ -318,70 +317,70 @@ void CFuncPlat :: Spawn( ) // 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) ) + if( !FStringNull( pev->targetname ) ) { - UTIL_SetOrigin (pev, m_vecPosition1); + UTIL_SetOrigin( pev, m_vecPosition1 ); m_toggle_state = TS_AT_TOP; SetUse( &CFuncPlat::PlatUse ); } else { - UTIL_SetOrigin (pev, m_vecPosition2); + UTIL_SetOrigin( pev, m_vecPosition2 ); m_toggle_state = TS_AT_BOTTOM; } } -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) +static void PlatSpawnInsideTrigger( entvars_t *pevPlatform ) { - GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); + GetClassPtr( (CPlatTrigger *)NULL )->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); } // // Create a trigger entity for a platform. // -void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) +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->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 ); + 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) + if( m_pPlatform->pev->size.x <= 50 ) { - vecTMin.x = (m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x) / 2; + 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) + if( m_pPlatform->pev->size.y <= 50 ) { - vecTMin.y = (m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y) / 2; + vecTMin.y = ( m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y ) / 2; vecTMax.y = vecTMin.y + 1; } - UTIL_SetSize ( pev, vecTMin, vecTMax ); + UTIL_SetSize( pev, vecTMin, vecTMax ); } // // When the platform's trigger field is touched, the platform ??? // -void CPlatTrigger :: Touch( CBaseEntity *pOther ) +void CPlatTrigger::Touch( CBaseEntity *pOther ) { // Ignore touches by non-players - entvars_t* pevToucher = pOther->pev; - if ( !FClassnameIs (pevToucher, "player") ) + entvars_t *pevToucher = pOther->pev; + if( !FClassnameIs( pevToucher, "player" ) ) return; // Ignore touches by corpses - if (!pOther->IsAlive()) + if( !pOther->IsAlive() ) return; - + // Make linked platform go up/down. - if (m_pPlatform->m_toggle_state == TS_AT_BOTTOM) + if( m_pPlatform->m_toggle_state == TS_AT_BOTTOM ) m_pPlatform->GoUp(); - else if (m_pPlatform->m_toggle_state == TS_AT_TOP) + else if( m_pPlatform->m_toggle_state == TS_AT_TOP ) m_pPlatform->pev->nextthink = m_pPlatform->pev->ltime + 1;// delay going down } @@ -389,26 +388,26 @@ void CPlatTrigger :: Touch( CBaseEntity *pOther ) // 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 ) +void CFuncPlat::PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( IsTogglePlat() ) + if( IsTogglePlat() ) { // Top is off, bottom is on - BOOL on = (m_toggle_state == TS_AT_BOTTOM) ? TRUE : FALSE; + BOOL on = ( m_toggle_state == TS_AT_BOTTOM ) ? TRUE : FALSE; - if ( !ShouldToggle( useType, on ) ) + if( !ShouldToggle( useType, on ) ) return; - if (m_toggle_state == TS_AT_TOP) + if( m_toggle_state == TS_AT_TOP ) GoDown(); - else if ( m_toggle_state == TS_AT_BOTTOM ) + else if( m_toggle_state == TS_AT_BOTTOM ) GoUp(); } else { SetUse( NULL ); - if (m_toggle_state == TS_AT_TOP) + if( m_toggle_state == TS_AT_TOP ) GoDown(); } } @@ -416,61 +415,61 @@ void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY // // Platform is at top, now starts moving down. // -void CFuncPlat :: GoDown( void ) +void CFuncPlat::GoDown( void ) { - if(pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); + 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); + 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); + SetMoveDone( &CFuncPlat::CallHitBottom ); + LinearMove( m_vecPosition2, pev->speed ); } // // Platform has hit bottom. Stops and waits forever. // -void CFuncPlat :: HitBottom( void ) +void CFuncPlat::HitBottom( void ) { - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); + 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); + if( pev->noiseStopMoving ) + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); - ASSERT(m_toggle_state == TS_GOING_DOWN); + 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 ) +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); + 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); + SetMoveDone( &CFuncPlat::CallHitTop ); LinearMove(m_vecPosition1, pev->speed); } // // Platform has hit top. Pauses, then starts back down again. // -void CFuncPlat :: HitTop( void ) +void CFuncPlat::HitTop( void ) { - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); + 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); + 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() ) + if( !IsTogglePlat() ) { // After a delay, the platform will automatically start going down again. SetThink( &CFuncPlat::CallGoDown ); @@ -478,20 +477,20 @@ void CFuncPlat :: HitTop( void ) } } -void CFuncPlat :: Blocked( CBaseEntity *pOther ) +void CFuncPlat::Blocked( CBaseEntity *pOther ) { - ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); + 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); + pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); + + if( pev->noiseMovement ) + STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); - 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) + 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) + else if( m_toggle_state == TS_GOING_DOWN ) GoUp (); } @@ -501,17 +500,17 @@ 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[]; + virtual void GoUp( void ); + virtual void GoDown( void ); + virtual void HitTop( void ); + virtual void HitBottom( void ); - Vector m_end, m_start; + 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 ) @@ -523,11 +522,11 @@ TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ) -void CFuncPlatRot :: SetupRotation( void ) +void CFuncPlatRot::SetupRotation( void ) { - if ( m_vecFinalAngle.x != 0 ) // This plat rotates too! + if( m_vecFinalAngle.x != 0 ) // This plat rotates too! { - CBaseToggle :: AxisDir( pev ); + CBaseToggle::AxisDir( pev ); m_start = pev->angles; m_end = pev->angles + pev->movedir * m_vecFinalAngle.x; } @@ -536,30 +535,30 @@ void CFuncPlatRot :: SetupRotation( void ) m_start = g_vecZero; m_end = g_vecZero; } - if ( !FStringNull(pev->targetname) ) // Start at top + if( !FStringNull( pev->targetname ) ) // Start at top { pev->angles = m_end; } } -void CFuncPlatRot :: Spawn( void ) +void CFuncPlatRot::Spawn( void ) { - CFuncPlat :: Spawn(); + CFuncPlat::Spawn(); SetupRotation(); } -void CFuncPlatRot :: GoDown( void ) +void CFuncPlatRot::GoDown( void ) { - CFuncPlat :: GoDown(); + CFuncPlat::GoDown(); RotMove( m_start, pev->nextthink - pev->ltime ); } // // Platform has hit bottom. Stops and waits forever. // -void CFuncPlatRot :: HitBottom( void ) +void CFuncPlatRot::HitBottom( void ) { - CFuncPlat :: HitBottom(); + CFuncPlat::HitBottom(); pev->avelocity = g_vecZero; pev->angles = m_start; } @@ -567,29 +566,29 @@ void CFuncPlatRot :: HitBottom( void ) // // Platform is at bottom, now starts moving up // -void CFuncPlatRot :: GoUp( void ) +void CFuncPlatRot::GoUp( void ) { - CFuncPlat :: GoUp(); + CFuncPlat::GoUp(); RotMove( m_end, pev->nextthink - pev->ltime ); } // // Platform has hit top. Pauses, then starts back down again. // -void CFuncPlatRot :: HitTop( void ) +void CFuncPlatRot::HitTop( void ) { - CFuncPlat :: HitTop(); + CFuncPlat::HitTop(); pev->avelocity = g_vecZero; pev->angles = m_end; } -void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) +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) + if( time >= 0.1 ) pev->avelocity = vecDestDelta / time; else { @@ -601,7 +600,6 @@ void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) // //====================== TRAIN code ================================================== // - class CFuncTrain : public CBasePlatTrain { public: @@ -614,16 +612,15 @@ public: 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[]; + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - entvars_t *m_pevCurrentTarget; - int m_sounds; - BOOL m_activated; + entvars_t *m_pevCurrentTarget; + int m_sounds; + BOOL m_activated; }; LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ) @@ -637,30 +634,30 @@ TYPEDESCRIPTION CFuncTrain::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ) -void CFuncTrain :: KeyValue( KeyValueData *pkvd ) +void CFuncTrain::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "sounds")) + if( FStrEq( pkvd->szKeyName, "sounds" ) ) { - m_sounds = atoi(pkvd->szValue); + m_sounds = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else CBasePlatTrain::KeyValue( pkvd ); } -void CFuncTrain :: Blocked( CBaseEntity *pOther ) +void CFuncTrain::Blocked( CBaseEntity *pOther ) { - if ( gpGlobals->time < m_flActivateFinished) + if( gpGlobals->time < m_flActivateFinished ) return; m_flActivateFinished = gpGlobals->time + 0.5; - - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); + + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); } -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncTrain::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) + if( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) { // Move toward my target pev->spawnflags &= ~SF_TRAIN_WAIT_RETRIGGER; @@ -670,49 +667,48 @@ void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE { pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; // Pop back to last target if it's available - if ( pev->enemy ) + 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); + if( pev->noiseStopMoving ) + EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); } } -void CFuncTrain :: Wait( void ) +void CFuncTrain::Wait( void ) { // Fire the pass target if there is one - if ( m_pevCurrentTarget->message ) + if( m_pevCurrentTarget->message ) { - FireTargets( STRING(m_pevCurrentTarget->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pevCurrentTarget->spawnflags, SF_CORNER_FIREONCE ) ) + 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 ) ) + 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); + 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) + // 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); + 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 @@ -724,21 +720,20 @@ void CFuncTrain :: Wait( void ) // // Train next - path corner needs to change to next target // -void CFuncTrain :: Next( void ) +void CFuncTrain::Next( void ) { - CBaseEntity *pTarg; + CBaseEntity *pTarg; - // now find our next target pTarg = GetNextTarget(); if( !pTarg ) { - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); + 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); + if( pev->noiseStopMoving ) + EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); return; } @@ -782,20 +777,20 @@ void CFuncTrain :: Next( void ) } } -void CFuncTrain :: Activate( void ) +void CFuncTrain::Activate( void ) { // Not yet active, so teleport to first target - if ( !m_activated ) + if( !m_activated ) { m_activated = TRUE; - entvars_t *pevTarg = VARS( FIND_ENTITY_BY_TARGETNAME (NULL, STRING(pev->target) ) ); - + 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) ) + 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 ); @@ -815,58 +810,57 @@ dmg default 2 sounds 1) ratchet metal */ - -void CFuncTrain :: Spawn( void ) +void CFuncTrain::Spawn( void ) { Precache(); - if (pev->speed == 0) + if( pev->speed == 0 ) pev->speed = 100; - if ( FStringNull(pev->target) ) - ALERT(at_console, "FuncTrain with no target"); + if( FStringNull(pev->target) ) + ALERT( at_console, "FuncTrain with no target" ); - if (pev->dmg == 0) + if( pev->dmg == 0 ) pev->dmg = 2; pev->movetype = MOVETYPE_PUSH; - if ( FBitSet (pev->spawnflags, SF_TRACKTRAIN_PASSABLE) ) - pev->solid = SOLID_NOT; + if( FBitSet( pev->spawnflags, SF_TRACKTRAIN_PASSABLE ) ) + pev->solid = SOLID_NOT; else - pev->solid = SOLID_BSP; + pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetSize (pev, pev->mins, pev->maxs); - UTIL_SetOrigin(pev, pev->origin); + 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 ) + if( m_volume == 0 ) m_volume = 0.85; } void CFuncTrain::Precache( void ) { CBasePlatTrain::Precache(); -#if 0 // obsolete +#if 0 // obsolete // otherwise use preset sound - switch (m_sounds) + 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"); + 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"); + 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 @@ -874,15 +868,15 @@ void CFuncTrain::Precache( void ) void CFuncTrain::OverrideReset( void ) { - CBaseEntity *pTarg; + CBaseEntity *pTarg; // Are we moving? - if ( pev->velocity != g_vecZero && pev->nextthink != 0 ) + if( pev->velocity != g_vecZero && pev->nextthink != 0 ) { pev->target = pev->message; // now find our next target pTarg = GetNextTarget(); - if ( !pTarg ) + if( !pTarg ) { pev->nextthink = 0; pev->velocity = g_vecZero; @@ -920,46 +914,46 @@ TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ) LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ) -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) +void CFuncTrackTrain::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "wheels")) + if( FStrEq( pkvd->szKeyName, "wheels" ) ) { - m_length = atof(pkvd->szValue); + m_length = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "height")) + else if( FStrEq( pkvd->szKeyName, "height" ) ) { m_height = atof(pkvd->szValue); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "startspeed")) + else if( FStrEq( pkvd->szKeyName, "startspeed" ) ) { m_startSpeed = atof(pkvd->szValue); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "sounds")) + else if( FStrEq( pkvd->szKeyName, "sounds" ) ) { m_sounds = atoi(pkvd->szValue); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "volume")) + else if( FStrEq( pkvd->szKeyName, "volume" ) ) { - m_flVolume = (float) (atoi(pkvd->szValue)); + m_flVolume = (float)atoi( pkvd->szValue ); m_flVolume *= 0.1; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "bank")) + else if( FStrEq( pkvd->szKeyName, "bank" ) ) { - m_flBank = atof(pkvd->szValue); + m_flBank = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else CBaseEntity::KeyValue( pkvd ); } -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) +void CFuncTrackTrain::NextThink( float thinkTime, BOOL alwaysThink ) { - if ( alwaysThink ) + if( alwaysThink ) pev->flags |= FL_ALWAYSTHINK; else pev->flags &= ~FL_ALWAYSTHINK; @@ -967,38 +961,38 @@ void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) pev->nextthink = thinkTime; } -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) +void CFuncTrackTrain::Blocked( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + entvars_t *pevOther = pOther->pev; // Blocker is on-ground on the train - if ( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS(pevOther->groundentity) == pev ) + if( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS( pevOther->groundentity ) == pev ) { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) + float deltaSpeed = fabs( pev->speed ); + if( deltaSpeed > 50 ) deltaSpeed = 50; - if ( !pevOther->velocity.z ) + if( !pevOther->velocity.z ) pevOther->velocity.z += deltaSpeed; return; } else - pevOther->velocity = (pevOther->origin - pev->origin ).Normalize() * pev->dmg; + 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 ) + 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); + pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); } -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncTrackTrain::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( useType != USE_SET ) + if( useType != USE_SET ) { - if ( !ShouldToggle( useType, (pev->speed != 0) ) ) + if( !ShouldToggle( useType, ( pev->speed != 0 ) ) ) return; - if ( pev->speed == 0 ) + if( pev->speed == 0 ) { pev->speed = m_speed * m_dir; @@ -1017,27 +1011,27 @@ void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ { float delta = value; - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) + 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( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) { - if ( delta < 0 ) + 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 ); + ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING( pev->targetname ), pev->speed ); } } static float Fix( float angle ) { - while ( angle < 0 ) + while( angle < 0 ) angle += 360; - while ( angle > 360 ) + while( angle > 360 ) angle -= 360; return angle; @@ -1054,23 +1048,22 @@ static void FixupAngles( Vector &v ) #define TRAIN_MAXPITCH 200 #define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation -void CFuncTrackTrain :: StopSound( void ) +void CFuncTrackTrain::StopSound( void ) { // if sound playing, stop it - if (m_soundPlaying && pev->noise) + if( m_soundPlaying && pev->noise ) { unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; + 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)); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 ); } m_soundPlaying = 0; @@ -1079,28 +1072,27 @@ void CFuncTrackTrain :: StopSound( void ) // 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 ) +void CFuncTrackTrain::UpdateSound( void ) { float flpitch; - if (!pev->noise) + if( !pev->noise ) return; - flpitch = TRAIN_STARTPITCH + (fabs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); + flpitch = TRAIN_STARTPITCH + ( fabs( pev->speed ) * ( TRAIN_MAXPITCH - TRAIN_STARTPITCH ) / TRAIN_MAXSPEED ); - if (!m_soundPlaying) + 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); + 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); + 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 @@ -1114,27 +1106,27 @@ void CFuncTrackTrain :: UpdateSound( void ) us_encode = us_sound | us_pitch | us_volume; - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, + 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 ) +void CFuncTrackTrain::Next( void ) { float time = 0.5; - if ( !pev->speed ) + if( !pev->speed ) { - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); + 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 ) + //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) ); + ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING( pev->targetname ) ); StopSound(); return; } @@ -1147,11 +1139,11 @@ void CFuncTrackTrain :: Next( void ) CPathTrack *pnext = m_ppath->LookAhead( &nextPos, pev->speed * 0.1, 1 ); nextPos.z += m_height; - pev->velocity = (nextPos - pev->origin) * 10; + pev->velocity = ( nextPos - pev->origin ) * 10; Vector nextFront = pev->origin; nextFront.z -= m_height; - if ( m_length > 0 ) + if( m_length > 0 ) m_ppath->LookAhead( &nextFront, m_length, 0 ); else m_ppath->LookAhead( &nextFront, 100, 0 ); @@ -1166,11 +1158,11 @@ void CFuncTrackTrain :: Next( void ) FixupAngles( angles ); FixupAngles( pev->angles ); - if ( !pnext || (delta.x == 0 && delta.y == 0) ) + if( !pnext || ( delta.x == 0 && delta.y == 0 ) ) angles = pev->angles; float vy, vx; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) + if( !( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) ) vx = UTIL_AngleDistance( angles.x, pev->angles.x ); else vx = 0; @@ -1179,46 +1171,46 @@ void CFuncTrackTrain :: Next( void ) pev->avelocity.y = vy * 10; pev->avelocity.x = vx * 10; - if ( m_flBank != 0 ) + 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); + 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; + pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank * 4 ), pev->angles.z ) * 4; } - - if ( pnext ) + + if( pnext ) { - if ( pnext != m_ppath ) + if( pnext != m_ppath ) { CPathTrack *pFire; - if ( pev->speed >= 0 ) + 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 ) + if( pFire->pev->message ) { - FireTargets( STRING(pFire->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) + 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 ) + 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( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) { - if ( pFire->pev->speed != 0 ) + 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 ); + ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f\n", STRING( pev->targetname ), pev->speed ); } } @@ -1229,7 +1221,7 @@ void CFuncTrackTrain :: Next( void ) else // end of path, stop { StopSound(); - pev->velocity = (nextPos - pev->origin); + pev->velocity = nextPos - pev->origin; pev->avelocity = g_vecZero; float distance = pev->velocity.Length(); m_oldSpeed = pev->speed; @@ -1239,11 +1231,11 @@ void CFuncTrackTrain :: Next( void ) // Move to the dead end // Are we there yet? - if ( distance > 0 ) + if( distance > 0 ) { // no, how long to get there? time = distance / m_oldSpeed; - pev->velocity = pev->velocity * (m_oldSpeed / distance); + pev->velocity = pev->velocity * ( m_oldSpeed / distance ); SetThink( &CFuncTrackTrain::DeadEnd ); NextThink( pev->ltime + time, FALSE ); } @@ -1261,45 +1253,45 @@ void CFuncTrackTrain::DeadEnd( void ) pTrack = m_ppath; - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); + 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( pTrack ) { - if ( m_oldSpeed < 0 ) + if( m_oldSpeed < 0 ) { do { pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); - if ( pNext ) + if( pNext ) pTrack = pNext; - } while ( pNext ); + } while( pNext ); } else { do { pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) + if( pNext ) pTrack = pNext; - } while ( pNext ); + } while( pNext ); } } pev->velocity = g_vecZero; pev->avelocity = g_vecZero; - if ( pTrack ) + 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 ); + 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 ) +void CFuncTrackTrain::SetControls( entvars_t *pevControls ) { Vector offset = pevControls->origin - pev->oldorigin; @@ -1307,11 +1299,11 @@ void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) m_controlMaxs = pevControls->maxs + offset; } -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) +BOOL CFuncTrackTrain::OnControls( entvars_t *pevTest ) { Vector offset = pevTest->origin - pev->origin; - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) + if( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) return FALSE; // Transform offset into local coordinates @@ -1321,21 +1313,21 @@ BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) 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 && + 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 ) +void CFuncTrackTrain::Find( void ) { - m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) + 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" ) ) + if( !FClassnameIs( pevTarget, "path_track" ) ) { ALERT( at_error, "func_track_train must be on a path of path_track\n" ); m_ppath = NULL; @@ -1354,7 +1346,7 @@ void CFuncTrackTrain :: Find( void ) // The train actually points west pev->angles.y += 180; - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) + if( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) pev->angles.x = 0; UTIL_SetOrigin( pev, nextPos ); NextThink( pev->ltime + 0.1, FALSE ); @@ -1364,7 +1356,7 @@ void CFuncTrackTrain :: Find( void ) UpdateSound(); } -void CFuncTrackTrain :: NearestPath( void ) +void CFuncTrackTrain::NearestPath( void ) { CBaseEntity *pTrack = NULL; CBaseEntity *pNearest = NULL; @@ -1372,13 +1364,13 @@ void CFuncTrackTrain :: NearestPath( void ) closest = 1024; - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) + 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" ) ) + if( !( pTrack->pev->flags & ( FL_CLIENT | FL_MONSTER ) ) && FClassnameIs( pTrack->pev, "path_track" ) ) { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) + dist = ( pev->origin - pTrack->pev->origin ).Length(); + if( dist < closest ) { closest = dist; pNearest = pTrack; @@ -1386,25 +1378,25 @@ void CFuncTrackTrain :: NearestPath( void ) } } - if ( !pNearest ) + 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) ); + 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 ) + pTrack = ( (CPathTrack *)pNearest )->GetNext(); + if( pTrack ) { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) + if( ( pev->origin - pTrack->pev->origin ).Length() < ( pev->origin - pNearest->pev->origin ).Length() ) pNearest = pTrack; } m_ppath = (CPathTrack *)pNearest; - if ( pev->speed != 0 ) + if( pev->speed != 0 ) { NextThink( pev->ltime + 0.1, FALSE ); SetThink( &CFuncTrackTrain::Next ); @@ -1419,8 +1411,8 @@ void CFuncTrackTrain::OverrideReset( void ) CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) { - if ( FClassnameIs( pent, "func_tracktrain" ) ) - return (CFuncTrackTrain *)GET_PRIVATE(pent); + if( FClassnameIs( pent, "func_tracktrain" ) ) + return (CFuncTrackTrain *)GET_PRIVATE( pent ); return NULL; } @@ -1435,9 +1427,9 @@ sounds 1) ratchet metal */ -void CFuncTrackTrain :: Spawn( void ) +void CFuncTrackTrain::Spawn( void ) { - if ( pev->speed == 0 ) + if( pev->speed == 0 ) m_speed = 100; else m_speed = pev->speed; @@ -1449,16 +1441,16 @@ void CFuncTrackTrain :: Spawn( void ) m_dir = 1; - if ( FStringNull(pev->target) ) + if( FStringNull( pev->target ) ) ALERT( at_console, "FuncTrain with no target" ); - if ( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) + 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) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); @@ -1477,27 +1469,45 @@ void CFuncTrackTrain :: Spawn( void ) Precache(); } -void CFuncTrackTrain :: Precache( void ) +void CFuncTrackTrain::Precache( void ) { - if (m_flVolume == 0.0) + if( m_flVolume == 0.0 ) m_flVolume = 1.0; - switch (m_sounds) + 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; + 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"); + PRECACHE_SOUND( "plats/ttrain_brake1.wav" ); + PRECACHE_SOUND( "plats/ttrain_start1.wav" ); m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); } @@ -1506,38 +1516,38 @@ void CFuncTrackTrain :: Precache( void ) class CFuncTrainControls : public CBaseEntity { public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + 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 ) +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") ); + pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING( pev->target ) ); + } while( !FNullEnt(pTarget) && !FClassnameIs( pTarget, "func_tracktrain" ) ); - if ( FNullEnt( pTarget ) ) + if( FNullEnt( pTarget ) ) { - ALERT( at_console, "No train %s\n", STRING(pev->target) ); + ALERT( at_console, "No train %s\n", STRING( pev->target ) ); return; } - CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance(pTarget); + CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance( pTarget ); ptrain->SetControls( pev ); UTIL_Remove( this ); } -void CFuncTrainControls :: Spawn( void ) +void CFuncTrainControls::Spawn( void ) { pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; - SET_MODEL( ENT(pev), STRING(pev->model) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); @@ -1551,11 +1561,10 @@ void CFuncTrainControls :: Spawn( void ) // Track changer / Train elevator // // ---------------------------------------------------------------------------- - -#define SF_TRACK_ACTIVATETRAIN 0x00000001 +#define SF_TRACK_ACTIVATETRAIN 0x00000001 #define SF_TRACK_RELINK 0x00000002 #define SF_TRACK_ROTMOVE 0x00000004 -#define SF_TRACK_STARTBOTTOM 0x00000008 +#define SF_TRACK_STARTBOTTOM 0x00000008 #define SF_TRACK_DONT_MOVE 0x00000010 // @@ -1563,8 +1572,12 @@ void CFuncTrainControls :: Spawn( void ) // 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; +typedef enum +{ + TRAIN_SAFE, + TRAIN_BLOCKING, + TRAIN_FOLLOWING +}TRAIN_CODE; class CFuncTrackChange : public CFuncPlatRot { @@ -1572,42 +1585,42 @@ public: void Spawn( void ); void Precache( void ); - //virtual void Blocked( void ); - virtual void EXPORT GoUp( void ); - virtual void EXPORT GoDown( 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 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; } + 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 int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; - virtual void OverrideReset( void ); + virtual void OverrideReset( void ); - CPathTrack *m_trackTop; - CPathTrack *m_trackBottom; + 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; + 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 ) @@ -1627,24 +1640,24 @@ TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ) -void CFuncTrackChange :: Spawn( void ) +void CFuncTrackChange::Spawn( void ) { Setup(); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) + if( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) m_vecPosition2.z = pev->origin.z; SetupRotation(); - if ( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) + if( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) { - UTIL_SetOrigin (pev, m_vecPosition2); + 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); + UTIL_SetOrigin( pev, m_vecPosition1 ); m_toggle_state = TS_AT_TOP; pev->angles = m_end; m_targetState = TS_AT_BOTTOM; @@ -1656,7 +1669,7 @@ void CFuncTrackChange :: Spawn( void ) Precache(); } -void CFuncTrackChange :: Precache( void ) +void CFuncTrackChange::Precache( void ) { // Can't trigger sound PRECACHE_SOUND( "buttons/button11.wav" ); @@ -1665,7 +1678,7 @@ void CFuncTrackChange :: Precache( void ) } // UNDONE: Filter touches before re-evaluating the train. -void CFuncTrackChange :: Touch( CBaseEntity *pOther ) +void CFuncTrackChange::Touch( CBaseEntity *pOther ) { #if 0 TRAIN_CODE code; @@ -1673,19 +1686,19 @@ void CFuncTrackChange :: Touch( CBaseEntity *pOther ) #endif } -void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) +void CFuncTrackChange::KeyValue( KeyValueData *pkvd ) { - if ( FStrEq(pkvd->szKeyName, "train") ) + if( FStrEq( pkvd->szKeyName, "train" ) ) { m_trainName = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "toptrack") ) + else if( FStrEq( pkvd->szKeyName, "toptrack" ) ) { m_trackTopName = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if ( FStrEq(pkvd->szKeyName, "bottomtrack") ) + else if( FStrEq( pkvd->szKeyName, "bottomtrack" ) ) { m_trackBottomName = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -1702,29 +1715,29 @@ void CFuncTrackChange::OverrideReset( void ) SetThink( &CFuncTrackChange::Find ); } -void CFuncTrackChange :: Find( void ) +void CFuncTrackChange::Find( void ) { // Find track entities edict_t *target; - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackTopName) ); - if ( !FNullEnt(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) ) + 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) ) + 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 ) + 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) ); + ALERT( at_error, "Can't find train for track change! %s\n", STRING( m_trainName ) ); return; } - Vector center = (pev->absmin + pev->absmax) * 0.5; + Vector center = ( pev->absmin + pev->absmax ) * 0.5; m_trackBottom = m_trackBottom->Nearest( center ); m_trackTop = m_trackTop->Nearest( center ); UpdateAutoTargets( m_toggle_state ); @@ -1733,34 +1746,34 @@ void CFuncTrackChange :: Find( void ) } 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) ); + 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) ); + 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) ); + ALERT( at_error, "Can't find top track for track change! %s\n", STRING( m_trackTopName ) ); } -TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) +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 ) + 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->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 ) + 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 + if( length < m_train->m_length ) // Empirically determined close distance return TRAIN_FOLLOWING; - else if ( length > (150 + m_train->m_length) ) + else if( length > ( 150 + m_train->m_length ) ) return TRAIN_SAFE; return TRAIN_BLOCKING; @@ -1769,16 +1782,16 @@ TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) return TRAIN_SAFE; } -void CFuncTrackChange :: UpdateTrain( Vector &dest ) +void CFuncTrackChange::UpdateTrain( Vector &dest ) { - float time = (pev->nextthink - pev->ltime); + 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 ) + if( time <= 0 ) return; Vector offset = m_train->pev->origin - pev->origin; @@ -1791,12 +1804,12 @@ void CFuncTrackChange :: UpdateTrain( Vector &dest ) local.z = DotProduct( offset, gpGlobals->v_up ); local = local - offset; - m_train->pev->velocity = pev->velocity + (local * (1.0/time)); + m_train->pev->velocity = pev->velocity + ( local * ( 1.0 / time ) ); } -void CFuncTrackChange :: GoDown( void ) +void CFuncTrackChange::GoDown( void ) { - if ( m_code == TRAIN_BLOCKING ) + if( m_code == TRAIN_BLOCKING ) return; // HitBottom may get called during CFuncPlat::GoDown(), so set up for that @@ -1804,7 +1817,7 @@ void CFuncTrackChange :: GoDown( void ) UpdateAutoTargets( TS_GOING_DOWN ); // If ROTMOVE, move & rotate - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) + if( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { SetMoveDone( &CFuncPlat::CallHitBottom ); m_toggle_state = TS_GOING_DOWN; @@ -1812,14 +1825,14 @@ void CFuncTrackChange :: GoDown( void ) } else { - CFuncPlat :: GoDown(); + CFuncPlat::GoDown(); SetMoveDone( &CFuncPlat::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 ) + if( m_code == TRAIN_FOLLOWING ) { UpdateTrain( m_start ); m_train->m_ppath = NULL; @@ -1829,16 +1842,15 @@ void CFuncTrackChange :: GoDown( void ) // // Platform is at bottom, now starts moving up // -void CFuncTrackChange :: GoUp( void ) +void CFuncTrackChange::GoUp( void ) { - if ( m_code == TRAIN_BLOCKING ) + 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 ) ) + if( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) { m_toggle_state = TS_GOING_UP; SetMoveDone( &CFuncPlat::CallHitTop ); @@ -1847,7 +1859,7 @@ void CFuncTrackChange :: GoUp( void ) else { // If ROTMOVE, move & rotate - CFuncPlat :: GoUp(); + CFuncPlat::GoUp(); SetMoveDone( &CFuncPlat::CallHitTop ); RotMove( m_end, pev->nextthink - pev->ltime ); } @@ -1855,7 +1867,7 @@ void CFuncTrackChange :: GoUp( void ) // Otherwise, move first, rotate second // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) + if( m_code == TRAIN_FOLLOWING ) { UpdateTrain( m_end ); m_train->m_ppath = NULL; @@ -1863,47 +1875,46 @@ void CFuncTrackChange :: GoUp( void ) } // Normal track change -void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) +void CFuncTrackChange::UpdateAutoTargets( int toggleState ) { - if ( !m_trackTop || !m_trackBottom ) + if( !m_trackTop || !m_trackBottom ) return; - if ( toggleState == TS_AT_TOP ) + 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 ) + 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 ) +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 ) + 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 ) + if( m_toggle_state == TS_AT_TOP ) m_code = EvaluateTrain( m_trackTop ); - else if ( m_toggle_state == TS_AT_BOTTOM ) + else if( m_toggle_state == TS_AT_BOTTOM ) m_code = EvaluateTrain( m_trackBottom ); else m_code = TRAIN_BLOCKING; - if ( 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); + 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) + if( m_toggle_state == TS_AT_TOP ) GoDown(); else GoUp(); @@ -1912,10 +1923,10 @@ void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE // // Platform has hit bottom. Stops and waits forever. // -void CFuncTrackChange :: HitBottom( void ) +void CFuncTrackChange::HitBottom( void ) { - CFuncPlatRot :: HitBottom(); - if ( m_code == TRAIN_FOLLOWING ) + CFuncPlatRot::HitBottom(); + if( m_code == TRAIN_FOLLOWING ) { //UpdateTrain(); m_train->SetTrack( m_trackBottom ); @@ -1931,10 +1942,10 @@ void CFuncTrackChange :: HitBottom( void ) // // Platform has hit bottom. Stops and waits forever. // -void CFuncTrackChange :: HitTop( void ) +void CFuncTrackChange::HitTop( void ) { - CFuncPlatRot :: HitTop(); - if ( m_code == TRAIN_FOLLOWING ) + CFuncPlatRot::HitTop(); + if( m_code == TRAIN_FOLLOWING ) { //UpdateTrain(); m_train->SetTrack( m_trackTop ); @@ -1957,14 +1968,14 @@ public: LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ) // Auto track change -void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) +void CFuncTrackAuto::UpdateAutoTargets( int toggleState ) { CPathTrack *pTarget, *pNextTarget; - if ( !m_trackTop || !m_trackBottom ) + if( !m_trackTop || !m_trackBottom ) return; - if ( m_targetState == TS_AT_TOP ) + if( m_targetState == TS_AT_TOP ) { pTarget = m_trackTop->GetNext(); pNextTarget = m_trackBottom->GetNext(); @@ -1974,40 +1985,40 @@ void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) pTarget = m_trackBottom->GetNext(); pNextTarget = m_trackTop->GetNext(); } - if ( pTarget ) + if( pTarget ) { ClearBits( pTarget->pev->spawnflags, SF_PATH_DISABLED ); - if ( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) + if( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) m_train->Use( this, this, USE_ON, 0 ); } - if ( pNextTarget ) + if( pNextTarget ) SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); } -void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +void CFuncTrackAuto::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CPathTrack *pTarget; - if ( !UseEnabled() ) + if( !UseEnabled() ) return; - if ( m_toggle_state == TS_AT_TOP ) + if( m_toggle_state == TS_AT_TOP ) pTarget = m_trackTop; - else if ( m_toggle_state == TS_AT_BOTTOM ) + else if( m_toggle_state == TS_AT_BOTTOM ) pTarget = m_trackBottom; else pTarget = NULL; - if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) + if( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) { m_code = EvaluateTrain( pTarget ); // Safe to fire? - if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) + if( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) { DisableUse(); - if (m_toggle_state == TS_AT_TOP) + if( m_toggle_state == TS_AT_TOP ) GoDown(); else GoUp(); @@ -2015,11 +2026,11 @@ void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T } else { - if ( pTarget ) + if( pTarget ) pTarget = pTarget->GetNext(); - if ( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) + if( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) { - if ( m_targetState == TS_AT_TOP ) + if( m_targetState == TS_AT_TOP ) m_targetState = TS_AT_BOTTOM; else m_targetState = TS_AT_TOP; @@ -2041,27 +2052,27 @@ void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T 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 ); + 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; } + 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 ); + virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; + static TYPEDESCRIPTION m_SaveData[]; private: - BOOL m_on; + BOOL m_on; }; LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ) @@ -2075,13 +2086,13 @@ IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ) void CGunTarget::Spawn( void ) { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); + UTIL_SetOrigin( pev, pev->origin ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); - if ( pev->speed == 0 ) + if( pev->speed == 0 ) pev->speed = 100; // Don't take damage until "on" @@ -2091,7 +2102,7 @@ void CGunTarget::Spawn( void ) m_on = FALSE; pev->max_health = pev->health; - if ( pev->spawnflags & FGUNTARGET_START_ON ) + if( pev->spawnflags & FGUNTARGET_START_ON ) { SetThink( &CGunTarget::Start ); pev->nextthink = pev->ltime + 0.3; @@ -2100,14 +2111,14 @@ void CGunTarget::Spawn( void ) void CGunTarget::Activate( void ) { - CBaseEntity *pTarg; + CBaseEntity *pTarg; // now find our next target pTarg = GetNextTarget(); - if ( pTarg ) + if( pTarg ) { m_hTargetEnt = pTarg; - UTIL_SetOrigin( pev, pTarg->pev->origin - (pev->mins + pev->maxs) * 0.5 ); + UTIL_SetOrigin( pev, pTarg->pev->origin - ( pev->mins + pev->maxs ) * 0.5 ); } } @@ -2123,38 +2134,38 @@ void CGunTarget::Next( void ) m_hTargetEnt = GetNextTarget(); CBaseEntity *pTarget = m_hTargetEnt; - if ( !pTarget ) + if( !pTarget ) { Stop(); return; } SetMoveDone( &CGunTarget::Wait ); - LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); + LinearMove( pTarget->pev->origin - ( pev->mins + pev->maxs ) * 0.5, pev->speed ); } void CGunTarget::Wait( void ) { CBaseEntity *pTarget = m_hTargetEnt; - if ( !pTarget ) + if( !pTarget ) { Stop(); return; } // Fire the pass target if there is one - if ( pTarget->pev->message ) + if( pTarget->pev->message ) { FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pTarget->pev->spawnflags, SF_CORNER_FIREONCE ) ) + 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) + if( m_flWait != 0 ) { // -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; @@ -2172,18 +2183,17 @@ void CGunTarget::Stop( void ) pev->takedamage = DAMAGE_NO; } - int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - if ( pev->health > 0 ) + if( pev->health > 0 ) { pev->health -= flDamage; - if ( pev->health <= 0 ) + if( pev->health <= 0 ) { pev->health = 0; Stop(); - if ( pev->message ) - FireTargets( STRING(pev->message), this, this, USE_TOGGLE, 0 ); + if( pev->message ) + FireTargets( STRING( pev->message ), this, this, USE_TOGGLE, 0 ); } } return 0; @@ -2191,10 +2201,10 @@ int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !ShouldToggle( useType, m_on ) ) + if( !ShouldToggle( useType, m_on ) ) return; - if ( m_on ) + if( m_on ) { Stop(); } @@ -2202,7 +2212,7 @@ void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us { pev->takedamage = DAMAGE_AIM; m_hTargetEnt = GetNextTarget(); - if ( m_hTargetEnt == NULL ) + if( m_hTargetEnt == NULL ) return; pev->health = pev->max_health; Next(); diff --git a/dlls/prop.cpp b/dlls/prop.cpp index 0c3cbc8f..c6c4017e 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -31,35 +31,53 @@ #include "gamerules.h" #define SF_PROP_RESPAWN 8 // enable autorespawn -#define SF_PROP_BREAKABLE 16 // enable break/explode +#define SF_PROP_BREAKABLE 16 // enable break/explode #define SF_PROP_FIXED 32 // don't move untill touch -typedef enum { expRandom, expDirected} Explosions; -typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; +typedef enum +{ + expRandom, + expDirected +}Explosions; -//extern "C" void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -Vector UTIL_AngleVectorsF(const Vector &angles) +typedef enum +{ + matGlass = 0, + matWood, + matMetal, + matFlesh, + matCinderBlock, + matCeilingTile, + matComputer, + matUnbreakableGlass, + matRocks, + matNone, + matLastMaterial +}Materials; + +//extern "C" void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +Vector UTIL_AngleVectorsF( const Vector &angles ) { float rgflVecOut[3]; float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, rgflVecOut, NULL, NULL); - return Vector(rgflVecOut); + angles.CopyToArray( rgflVecIn ); + g_engfuncs.pfnAngleVectors( rgflVecIn, rgflVecOut, NULL, NULL ); + return Vector( rgflVecOut ); } -Vector UTIL_AngleVectorsR(const Vector &angles) +Vector UTIL_AngleVectorsR( const Vector &angles ) { float rgflVecOut[3]; float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); - return Vector(rgflVecOut); + angles.CopyToArray( rgflVecIn ); + g_engfuncs.pfnAngleVectors( rgflVecIn, NULL, rgflVecOut, NULL ); + return Vector( rgflVecOut ); } -Vector UTIL_AngleVectorsU(const Vector &angles) +Vector UTIL_AngleVectorsU( const Vector &angles ) { float rgflVecOut[3]; float rgflVecIn[3]; - angles.CopyToArray(rgflVecIn); - g_engfuncs.pfnAngleVectors(rgflVecIn, NULL, rgflVecOut, NULL); - return Vector(rgflVecOut); + angles.CopyToArray( rgflVecIn ); + g_engfuncs.pfnAngleVectors( rgflVecIn, NULL, rgflVecOut, NULL ); + return Vector( rgflVecOut ); } //===================grenade @@ -76,18 +94,18 @@ enum PropShape class CProp : public CBaseEntity { public: - void Spawn(void); + void Spawn( void ); void Precache(); - void EXPORT BounceTouch(CBaseEntity *pOther); - //void EXPORT SlideTouch(CBaseEntity *pOther); - virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - virtual void Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual int ObjectCaps(void) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE; } - virtual void BounceSound(void); - virtual int BloodColor(void) { return DONT_BLEED; } - virtual void Killed(entvars_t *pevAttacker, int iGib); + void EXPORT BounceTouch( CBaseEntity *pOther ); + //void EXPORT SlideTouch( CBaseEntity *pOther ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Force( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int TakeDamage( entvars_t *pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + virtual int ObjectCaps( void ) { return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE; } + virtual void BounceSound( void ); + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void Killed( entvars_t *pevAttacker, int iGib ); void CheckRotate(); void EXPORT RespawnThink(); void EXPORT AngleThink(); @@ -95,7 +113,7 @@ public: void EXPORT DieThink(); void DamageSound( void ); void PropRespawn(); - void KeyValue( KeyValueData* pkvd); + void KeyValue( KeyValueData *pkvd ); static const char *pSoundsWood[]; static const char *pSoundsFlesh[]; @@ -104,15 +122,14 @@ public: static const char *pSoundsConcrete[]; static const char *pSpawnObjects[]; - inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } - inline int ExplosionMagnitude( void ) { return pev->impulse; } - inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } - + 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 ); - void EXPORT Die( void ); + void EXPORT Die( void ); BOOL m_bBarrel; float m_flFloorFriction; @@ -134,16 +151,16 @@ public: PropShape m_oldshape; CBasePlayer *m_pHolstered; float m_flSpawnHealth; - int m_idShard; - float m_angle; - int m_iszGibModel; - Materials m_Material; - Explosions m_Explosion; + int m_idShard; + float m_angle; + int m_iszGibModel; + Materials m_Material; + Explosions m_Explosion; int m_iaCustomAnglesX[10]; int m_iaCustomAnglesZ[10]; }; -LINK_ENTITY_TO_CLASS(prop, CProp) +LINK_ENTITY_TO_CLASS( prop, CProp ) const char *CProp::pSoundsWood[] = { @@ -185,33 +202,32 @@ const char *CProp::pSoundsGlass[] = const char **CProp::MaterialSoundList( Materials precacheMaterial, int &soundCount ) { - const char **pSoundList = NULL; + const char **pSoundList = NULL; - switch ( precacheMaterial ) + switch( precacheMaterial ) { case matWood: pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); + soundCount = ARRAYSIZE( pSoundsWood ); break; case matFlesh: pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); + soundCount = ARRAYSIZE( pSoundsFlesh ); break; case matComputer: case matUnbreakableGlass: case matGlass: pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); + soundCount = ARRAYSIZE( pSoundsGlass ); break; - case matMetal: pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); + soundCount = ARRAYSIZE( pSoundsMetal ); break; case matCinderBlock: case matRocks: pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); + soundCount = ARRAYSIZE( pSoundsConcrete ); break; case matCeilingTile: case matNone: @@ -225,12 +241,12 @@ const char **CProp::MaterialSoundList( Materials precacheMaterial, int &soundCou void CProp::MaterialSoundPrecache( Materials precacheMaterial ) { - const char **pSoundList; - int i, soundCount = 0; + const char **pSoundList; + int i, soundCount = 0; pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - for ( i = 0; i < soundCount; i++ ) + for( i = 0; i < soundCount; i++ ) { PRECACHE_SOUND( (char *)pSoundList[i] ); } @@ -238,13 +254,13 @@ void CProp::MaterialSoundPrecache( Materials precacheMaterial ) void CProp::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) { - const char **pSoundList; - int soundCount = 0; + 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 ); + if( soundCount ) + EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[RANDOM_LONG( 0, soundCount - 1 )], volume, 1.0 ); } void CProp::Precache( void ) @@ -254,65 +270,65 @@ void CProp::Precache( void ) if( !pev->model ) pev->model = MAKE_STRING( "models/xash/barrel_brown.mdl" ); - switch (m_Material) + switch( m_Material ) { case matWood: pGibName = "models/woodgibs.mdl"; - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); + 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"); + PRECACHE_SOUND( "debris/bustflesh1.wav" ); + PRECACHE_SOUND( "debris/bustflesh2.wav" ); break; case matComputer: - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); + PRECACHE_SOUND( "buttons/spark5.wav"); + PRECACHE_SOUND( "buttons/spark6.wav"); pGibName = "models/computergibs.mdl"; - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); + 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"); + 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"); + 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"); + 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"); + PRECACHE_SOUND( "debris/bustconcrete1.wav" ); + PRECACHE_SOUND( "debris/bustconcrete2.wav" ); break; case matCeilingTile: pGibName = "models/ceilinggibs.mdl"; - PRECACHE_SOUND ("debris/bustceiling.wav"); + PRECACHE_SOUND( "debris/bustceiling.wav" ); break; } MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); + if( m_iszGibModel ) + pGibName = STRING( m_iszGibModel ); m_idShard = PRECACHE_MODEL( (char *)pGibName ); - PRECACHE_MODEL( (char *)STRING(pev->model) ); + PRECACHE_MODEL( (char *)STRING( pev->model ) ); } void CProp::DamageSound( void ) @@ -323,20 +339,20 @@ void CProp::DamageSound( void ) int i; int material = m_Material; - //if (RANDOM_LONG(0,1)) + //if( RANDOM_LONG( 0, 1 ) ) // return; - if (RANDOM_LONG(0,2)) + if( RANDOM_LONG( 0, 2 ) ) pitch = PITCH_NORM; else - pitch = 95 + RANDOM_LONG(0,34); + pitch = 95 + RANDOM_LONG( 0, 34 ); - fvol = RANDOM_FLOAT(0.75, 1.0); + fvol = RANDOM_FLOAT( 0.75, 1.0 ); - if (material == matComputer && RANDOM_LONG(0,1)) + if( material == matComputer && RANDOM_LONG( 0, 1 ) ) material = matMetal; - switch (material) + switch( material ) { case matComputer: case matGlass: @@ -380,8 +396,8 @@ void CProp::DamageSound( void ) break; } - if (i) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); + if( i ) + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, rgpsz[RANDOM_LONG( 0, i - 1 )], fvol, ATTN_NORM, 0, pitch ); } void CProp::Die( void ) @@ -392,79 +408,89 @@ void CProp::Die( void ) int pitch; float fvol; - pitch = 95 + RANDOM_LONG(0,29); + pitch = 95 + RANDOM_LONG( 0, 29 ); - if (pitch > 97 && pitch < 103) + 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) + (fabs(pev->health) / 100.0); + fvol = RANDOM_FLOAT( 0.85, 1.0 ) + ( fabs( pev->health ) / 100.0 ); - if (fvol > 1.0) + if( fvol > 1.0 ) fvol = 1.0; - switch (m_Material) + switch( m_Material ) { case matGlass: - switch ( RANDOM_LONG(0,1) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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) ) + switch( RANDOM_LONG( 0, 1 ) ) { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); + 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); + 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); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch ); break; } - if (m_Explosion == expDirected) + if( m_Explosion == expDirected ) vecVelocity = g_vecAttackDir * 200; else { @@ -509,9 +535,9 @@ void CProp::Die( void ) MESSAGE_END(); float size = pev->size.x; - if ( size < pev->size.y ) + if( size < pev->size.y ) size = pev->size.y; - if ( size < pev->size.z ) + if( size < pev->size.z ) size = pev->size.z; // !!! HACK This should work! @@ -524,9 +550,9 @@ void CProp::Die( void ) // 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 ) + if( count ) { - for ( int i = 0; i < count; i++ ) + for( int i = 0; i < count; i++ ) { ClearBits( pList[i]->pev->flags, FL_ONGROUND ); pList[i]->pev->groundentity = NULL; @@ -541,15 +567,15 @@ void CProp::Die( void ) // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - if ( Explodable() && (m_attacker != NULL) ) + if( Explodable() && ( m_attacker != NULL ) ) { ExplosionCreate( pev->origin, pev->angles, m_attacker, ExplosionMagnitude(), FALSE ); - RadiusDamage ( pev->origin, pev, VARS(m_attacker), ExplosionMagnitude(), ExplosionMagnitude() * 2.5 , CLASS_NONE, DMG_BLAST ); + RadiusDamage( pev->origin, pev, VARS(m_attacker), ExplosionMagnitude(), ExplosionMagnitude() * 2.5 , CLASS_NONE, DMG_BLAST ); } - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); } -void CProp::Killed(entvars_t *pevAttacker, int iGib) +void CProp::Killed( entvars_t *pevAttacker, int iGib ) { pev->takedamage = DAMAGE_NO; pev->deadflag = DEAD_DEAD; @@ -561,13 +587,13 @@ void CProp::Killed(entvars_t *pevAttacker, int iGib) SetUse( NULL ); } -void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +void CProp::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if( pev->health <= 0) + if( pev->health <= 0 ) return; - if (m_owner2 != pActivator->edict()) + if( m_owner2 != pActivator->edict() ) { - if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + if( pev->velocity.Length() < 100 && pActivator->IsPlayer() ) { m_owner2 = m_attacker = pActivator->edict(); } @@ -580,9 +606,9 @@ void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, if( m_pHolstered ) { - if ( m_pHolstered->m_pActiveItem ) + if( m_pHolstered->m_pActiveItem ) { - CBasePlayerWeapon *weapon = (CBasePlayerWeapon *) m_pHolstered->m_pActiveItem->GetWeaponPtr(); + CBasePlayerWeapon *weapon = (CBasePlayerWeapon *)m_pHolstered->m_pActiveItem->GetWeaponPtr(); //m_Holstered->m_pActiveItem->Holster(); // strange bug here. ValveWHY? @@ -600,64 +626,64 @@ void CProp::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, pev->nextthink = gpGlobals->time + 0.2; } } - Vector target = pActivator->pev->origin + UTIL_GetAimVector(m_owner2, 1000) * 50; + Vector target = pActivator->pev->origin + UTIL_GetAimVector( m_owner2, 1000 ) * 50; target.z = target.z + 32; - pev->velocity = (target - VecBModelOrigin(pev)) * 10; - Vector atarget = UTIL_VecToAngles(UTIL_GetAimVector(m_owner2, 1000)); - pev->angles.x = UTIL_AngleMod(pev->angles.x); - pev->angles.y = UTIL_AngleMod(pev->angles.y); - pev->angles.z = UTIL_AngleMod(pev->angles.z); - atarget.x = UTIL_AngleMod(atarget.x); - atarget.y = UTIL_AngleMod(atarget.y); - atarget.z = UTIL_AngleMod(atarget.z); - pev->avelocity.x = UTIL_AngleDiff(atarget.x, pev->angles.x) * 10; - pev->avelocity.y = UTIL_AngleDiff(atarget.y, pev->angles.y) * 10; - pev->avelocity.z = UTIL_AngleDiff(atarget.z, pev->angles.z) * 10; - //pev->angles.z += (0 - pev->angles.z) * 0.06; - if ((pActivator->pev->button & (IN_ATTACK))) + pev->velocity = ( target - VecBModelOrigin( pev ) ) * 10; + Vector atarget = UTIL_VecToAngles(UTIL_GetAimVector( m_owner2, 1000 ) ); + pev->angles.x = UTIL_AngleMod( pev->angles.x ); + pev->angles.y = UTIL_AngleMod( pev->angles.y ); + pev->angles.z = UTIL_AngleMod( pev->angles.z ); + atarget.x = UTIL_AngleMod( atarget.x ); + atarget.y = UTIL_AngleMod( atarget.y ); + atarget.z = UTIL_AngleMod( atarget.z ); + pev->avelocity.x = UTIL_AngleDiff( atarget.x, pev->angles.x ) * 10; + pev->avelocity.y = UTIL_AngleDiff( atarget.y, pev->angles.y ) * 10; + pev->avelocity.z = UTIL_AngleDiff( atarget.z, pev->angles.z ) * 10; + //pev->angles.z += ( 0 - pev->angles.z ) * 0.06; + if( ( pActivator->pev->button & ( IN_ATTACK ) ) ) { - pev->velocity = UTIL_GetAimVector(m_owner2, 1000) * 1000; - pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + pev->velocity = UTIL_GetAimVector( m_owner2, 1000 ) * 1000; + pev->avelocity.y = pev->avelocity.y * 1.5 + RANDOM_FLOAT( 100, -100 ); + pev->avelocity.x = pev->avelocity.x * 1.5 + RANDOM_FLOAT( 100, -100 ); + //pev->avelocity.z = pev->avelocity.z * 0.5 + RANDOM_FLOAT( 100, -100 ); } - if ((pActivator->pev->button & (IN_ATTACK2))) + if ( ( pActivator->pev->button & ( IN_ATTACK2 ) ) ) { //m_Horizontal = false; //pev->angles.z = 0; } - // m_Horizontal = (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || ( sin(pev->angles.x/180*M_PI) > 0.1); + // m_Horizontal = ( fabs( UTIL_AngleDiff( pev->angles.z, 90 ) ) < 20 ) || ( sin( pev->angles.x / 180 * M_PI ) > 0.1 ); // CheckRotate(); - //ALERT( at_console, "Prop use!\n"); + //ALERT( at_console, "Prop use!\n" ); } -void CProp::Force(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +void CProp::Force( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( pev->health <= 0 ) return; - if (m_owner2 != pActivator->edict()) + if( m_owner2 != pActivator->edict() ) { - if (pev->velocity.Length() < 100 && pActivator->IsPlayer()) + if( pev->velocity.Length() < 100 && pActivator->IsPlayer() ) m_attacker = pActivator->edict(); else return; } - if ((pActivator->pev->button & (IN_ATTACK))) + if( ( pActivator->pev->button & ( IN_ATTACK ) ) ) { - pev->velocity = UTIL_GetAimVector(m_owner2, 3000) * 1000; - pev->avelocity.y = pev->avelocity.y*1.5 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*1.5 + RANDOM_FLOAT(100, -100); - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 100, -100 ); + pev->velocity = UTIL_GetAimVector( m_owner2, 3000 ) * 1000; + pev->avelocity.y = pev->avelocity.y * 1.5 + RANDOM_FLOAT( 100, -100 ); + pev->avelocity.x = pev->avelocity.x * 1.5 + RANDOM_FLOAT( 100, -100 ); + //pev->avelocity.z = pev->avelocity.z * 0.5 + RANDOM_FLOAT( 100, -100 ); } - if ((pActivator->pev->button & (IN_ATTACK2))) + if( ( pActivator->pev->button & ( IN_ATTACK2 ) ) ) { //m_Horizontal = false; //pev->angles.z = 0; } pev->nextthink = gpGlobals->time + m_flRespawnTime; - SetThink( &CProp::RespawnThink); + SetThink( &CProp::RespawnThink ); } void CProp::CheckRotate() @@ -667,47 +693,45 @@ void CProp::CheckRotate() UTIL_SetSize(pev, minsH, maxsH); return; } - if( (fabs(UTIL_AngleDiff(pev->angles.z, 90)) < 20) || - (fabs(sin(pev->angles.x / 180 * M_PI)) > 0.3) ) + if( ( fabs( UTIL_AngleDiff( pev->angles.z, 90 ) ) < 20 ) || ( fabs( sin( pev->angles.x / 180 * M_PI ) ) > 0.3 ) ) m_shape = SHAPE_CYL_H; else m_shape = SHAPE_CYL_V; - if (m_oldshape != m_shape) + if( m_oldshape != m_shape ) { - - if (m_shape == SHAPE_CYL_H) + if( m_shape == SHAPE_CYL_H ) { pev->angles.y += 90; - ALERT(at_console, "setH: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); + ALERT( at_console, "setH: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_SetSize(pev, minsH, maxsH); + UTIL_SetSize( pev, minsH, maxsH ); } - else if (m_shape == SHAPE_CYL_V) + else if( m_shape == SHAPE_CYL_V ) { Vector mins = pev->absmin; Vector maxs = pev->absmax; mins.z = pev->absmax.z; maxs.z += 10; - ALERT(at_console, "setV: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z); + ALERT( at_console, "setV: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); // BUGBUG -- can only find 256 entities on a prop -- should be enough CBaseEntity *pList[256]; int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); - if ( count ) + if( count ) { - for ( int i = 0; i < count; i++ ) + for( int i = 0; i < count; i++ ) { pList[i]->pev->origin.z += 10; } } pev->origin.z += 10; //pev->angles.y -= 90; - UTIL_SetSize(pev, minsV, maxsV); + UTIL_SetSize( pev, minsV, maxsV ); } - //DROP_TO_FLOOR(edict()); + //DROP_TO_FLOOR( edict() ); //pev->origin.z += 0.5; m_oldshape = m_shape; } @@ -737,7 +761,7 @@ void CProp::DeployThink( void ) } } -void CProp::BounceTouch(CBaseEntity *pOther) +void CProp::BounceTouch( CBaseEntity *pOther ) { if( pev->health <= 0 ) return; @@ -745,50 +769,50 @@ void CProp::BounceTouch(CBaseEntity *pOther) // only do damage if we're moving fairly fast DeployThink(); - if ( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 300) + if( m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 300 ) { - entvars_t *pevOwner = VARS(m_attacker); - if (pevOwner) + entvars_t *pevOwner = VARS( m_attacker ); + if( pevOwner ) { float dmg = 50 + pev->velocity.Length() / 40; - if (pOther->edict() == m_owner2) + if( pOther->edict() == m_owner2 ) { dmg = 5; - if (pOther->pev->button & (IN_USE)) + if( pOther->pev->button & ( IN_USE ) ) { dmg = 1; } } TraceResult tr = UTIL_GetGlobalTrace(); ClearMultiDamage(); - pOther->TraceAttack(pevOwner, dmg, gpGlobals->v_forward, &tr, DMG_CLUB); - ApplyMultiDamage(pev, pevOwner); + pOther->TraceAttack( pevOwner, dmg, gpGlobals->v_forward, &tr, DMG_CLUB ); + ApplyMultiDamage( pev, pevOwner ); } m_flNextAttack = gpGlobals->time + 1.0; // debounce } - if( (pOther->edict() != m_owner2) && (pev->spawnflags & SF_PROP_BREAKABLE) && (pev->velocity.Length() > 900) ) + if( ( pOther->edict() != m_owner2 ) && ( pev->spawnflags & SF_PROP_BREAKABLE ) && ( pev->velocity.Length() > 900 ) ) { pev->nextthink = gpGlobals->time + 0.1; SetThink( &CProp::DieThink ); } pev->velocity = pev->velocity + pOther->pev->velocity; - float dp = cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y)); - if (pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40) + float dp = cos( M_PI / 180 * UTIL_AngleDiff( UTIL_VecToAngles( pev->velocity ).y, pev->angles.y ) ); + if( pev->flags & FL_ONGROUND || fabs( pev->velocity.z ) < 40 ) { CheckRotate(); - if (m_shape == SHAPE_CYL_H) + if( m_shape == SHAPE_CYL_H ) { - pev->velocity.x *= fabs(dp) * 0.8 + 0.2; - pev->velocity.y *= fabs(dp) * 0.8 + 0.2; + pev->velocity.x *= fabs( dp ) * 0.8 + 0.2; + pev->velocity.y *= fabs( dp ) * 0.8 + 0.2; pev->velocity.z -= 20; pev->avelocity.x = -dp*pev->velocity.Length()* 1.5; pev->avelocity.y = 0; pev->avelocity.z = 0; - pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; + pev->angles.z += UTIL_AngleDiff( 90, pev->angles.z ) * 0.7; //AngleThink(); } - else if (m_shape == SHAPE_CYL_V) + else if( m_shape == SHAPE_CYL_V ) { // pev->angles.z *= 0.3; //pev->angles.x *= 0.3; @@ -798,13 +822,13 @@ void CProp::BounceTouch(CBaseEntity *pOther) pev->velocity.x *= m_flFloorFriction; pev->velocity.y *= m_flFloorFriction; pev->velocity.z -= 10; - pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(30, -30); + pev->avelocity.y = pev->avelocity.y * 0.4 + RANDOM_FLOAT( 30, -30 ); } else if( m_shape == SHAPE_SPHERE ) { pev->velocity.z -= 20; - pev->avelocity.x = -cos(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5; - pev->avelocity.y = -sin(M_PI / 180 * UTIL_AngleDiff(UTIL_VecToAngles(pev->velocity).y, pev->angles.y))*pev->velocity.Length()* 1.5;; + pev->avelocity.x = -cos( M_PI / 180 * UTIL_AngleDiff( UTIL_VecToAngles( pev->velocity ).y, pev->angles.y ) ) * pev->velocity.Length() * 1.5; + pev->avelocity.y = -sin( M_PI / 180 * UTIL_AngleDiff( UTIL_VecToAngles( pev->velocity ).y, pev->angles.y ) ) * pev->velocity.Length() * 1.5;; pev->avelocity.z = 0; } else if( m_shape == SHAPE_BOX || m_shape == SHAPE_GENERIC ) @@ -823,48 +847,54 @@ void CProp::BounceTouch(CBaseEntity *pOther) pev->velocity.x *= m_flCollideFriction; if( m_shape != SHAPE_SPHERE ) { - pev->avelocity.y = pev->avelocity.y*0.4 + RANDOM_FLOAT(100, -100); - pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); + pev->avelocity.y = pev->avelocity.y * 0.4 + RANDOM_FLOAT( 100, -100 ); + pev->avelocity.x = pev->avelocity.x * 0.5 + RANDOM_FLOAT( 100, -100 ); } } - //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT ( 1, -1 ); + //pev->avelocity.z = pev->avelocity.z*0.5 + RANDOM_FLOAT( 1, -1 ); BounceSound(); } pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) + if( pev->framerate > 1.0 ) pev->framerate = 1; - else if (pev->framerate < 0.2) + else if( pev->framerate < 0.2 ) { CheckRotate(); AngleThink(); - if (pev->angles.z == 0 || pev->angles.z == 90) + if( pev->angles.z == 0 || pev->angles.z == 90 ) pev->framerate = 0; else pev->framerate = 0.2; } } -void CProp::BounceSound(void) +void CProp::BounceSound( void ) { - switch (RANDOM_LONG(0, 2)) + 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; + 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 CProp::Spawn(void) +void CProp::Spawn( void ) { Precache(); if( minsH == g_vecZero ) { // default barrel parameters - minsV = Vector(-10, -10, -17); - maxsV = Vector(10, 10, 18); - minsH = Vector(-10, -10, -10); - maxsH = Vector(10, 10, 13); + minsV = Vector( -10, -10, -17 ); + maxsV = Vector( 10, 10, 18 ); + minsH = Vector( -10, -10, -10 ); + maxsH = Vector( 10, 10, 13 ); } m_flCollideFriction = 0.7; m_flFloorFriction = 0.5; @@ -881,7 +911,7 @@ void CProp::Spawn(void) void CProp::PropRespawn() { - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); pev->effects &= ~EF_NODRAW; pev->movetype = MOVETYPE_BOUNCE; pev->solid = SOLID_SLIDEBOX; @@ -890,8 +920,8 @@ void CProp::PropRespawn() pev->velocity = pev->avelocity = g_vecZero; pev->angles = spawnAngles; pev->deadflag = DEAD_NO; - SET_MODEL( ENT(pev), STRING(pev->model) ); - m_oldshape = (PropShape)-1; + SET_MODEL( ENT( pev ), STRING( pev->model ) ); + m_oldshape = ( PropShape ) - 1; CheckRotate(); SetTouch( &CProp::BounceTouch ); SetUse( &CProp::Use ); @@ -902,7 +932,7 @@ void CProp::PropRespawn() void CProp::RespawnThink() { - if( !(pev->spawnflags & SF_PROP_RESPAWN)) + if( !( pev->spawnflags & SF_PROP_RESPAWN ) ) { if( pev->health <= 0 ) { @@ -918,75 +948,75 @@ void CProp::AngleThink() { pev->nextthink = gpGlobals->time + m_flRespawnTime; SetThink( &CProp::RespawnThink); - if (!(pev->flags & FL_ONGROUND || fabs(pev->velocity.z) < 40)) + if(! ( pev->flags & FL_ONGROUND || fabs( pev->velocity.z ) < 40 ) ) { m_owner2 = m_attacker = 0; return; } - if (m_shape == SHAPE_CYL_H) + if( m_shape == SHAPE_CYL_H ) { - pev->angles.z += UTIL_AngleDiff(90, pev->angles.z) * 0.7; - if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + pev->angles.z += UTIL_AngleDiff( 90, pev->angles.z ) * 0.7; + if( fabs( UTIL_AngleDiff( 90, pev->angles.z ) ) > 0.1 ) { - SetThink( &CProp::AngleThink); + SetThink( &CProp::AngleThink ); pev->nextthink = gpGlobals->time + 0.1; } //ALERT( at_console, "AngleThink: %f %f %f\n", pev->angles.x, pev->angles.y, pev->angles.z ); pev->avelocity.y = pev->avelocity.z = 0; } - else if (m_shape == SHAPE_CYL_V) + else if( m_shape == SHAPE_CYL_V ) { - if (fabs(UTIL_AngleDiff(90, pev->angles.z)) > 0.1) + if( fabs( UTIL_AngleDiff( 90, pev->angles.z ) ) > 0.1 ) { - SetThink( &CProp::AngleThink); + SetThink( &CProp::AngleThink ); pev->nextthink = gpGlobals->time + 0.1; } - pev->angles.z += UTIL_AngleDiff(0, pev->angles.z) * 0.7; + pev->angles.z += UTIL_AngleDiff( 0, pev->angles.z ) * 0.7; //pev->angles.x += UTIL_AngleDiff( 0, pev->angles.x ) * 0.3; pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; } - else if (m_shape == SHAPE_BOX) + else if( m_shape == SHAPE_BOX ) { Vector iangles; iangles.x = round( pev->angles.x / 90 ) * 90; iangles.y = round( pev->angles.y / 90 ) * 90; iangles.z = round( pev->angles.z / 90 ) * 90; - if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || - //fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + if( fabs( UTIL_AngleDiff( iangles.x, pev->angles.x ) ) > 0.1 || + //fabs( UTIL_AngleDiff( iangles.y, pev->angles.y ) ) > 0.1 || + fabs( UTIL_AngleDiff( iangles.z, pev->angles.z ) ) > 0.1) { - SetThink( &CProp::AngleThink); + SetThink( &CProp::AngleThink ); pev->nextthink = gpGlobals->time + 0.1; } - pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; - //pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; - pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + pev->angles.x += UTIL_AngleDiff( iangles.x, pev->angles.x ) * 0.6; + //pev->angles.y += UTIL_AngleDiff( iangles.y, pev->angles.y ) * 0.6; + pev->angles.z += UTIL_AngleDiff( iangles.z, pev->angles.z ) * 0.6; pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; } - else if (m_shape == SHAPE_NOROTATE) + else if( m_shape == SHAPE_NOROTATE ) { pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; Vector iangles = spawnAngles; - if (fabs(UTIL_AngleDiff(iangles.x, pev->angles.x)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.y, pev->angles.y)) > 0.1 || - fabs(UTIL_AngleDiff(iangles.z, pev->angles.z)) > 0.1) + if( fabs(UTIL_AngleDiff( iangles.x, pev->angles.x ) ) > 0.1 || + fabs( UTIL_AngleDiff( iangles.y, pev->angles.y ) ) > 0.1 || + fabs( UTIL_AngleDiff( iangles.z, pev->angles.z ) ) > 0.1 ) { - SetThink( &CProp::AngleThink); + SetThink( &CProp::AngleThink ); pev->nextthink = gpGlobals->time + 0.1; } - pev->angles.x += UTIL_AngleDiff(iangles.x, pev->angles.x) * 0.6; - pev->angles.y += UTIL_AngleDiff(iangles.y, pev->angles.y) * 0.6; - pev->angles.z += UTIL_AngleDiff(iangles.z, pev->angles.z) * 0.6; + pev->angles.x += UTIL_AngleDiff( iangles.x, pev->angles.x ) * 0.6; + pev->angles.y += UTIL_AngleDiff( iangles.y, pev->angles.y ) * 0.6; + pev->angles.z += UTIL_AngleDiff( iangles.z, pev->angles.z ) * 0.6; } - else if (m_shape == SHAPE_GENERIC) + else if( m_shape == SHAPE_GENERIC ) { float ianglex = 0, ianglez = 0, imaxanglediff=360.0f; // if first number is zero, it is angle // all other zeroes is array end - for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesX[i] ); i++) + for( int i = 0; ( i < 10 ) && ( ( i == 0 ) || m_iaCustomAnglesX[i] ); i++ ) { - float anglediff = fabs(UTIL_AngleDiff(pev->angles.x, m_iaCustomAnglesX[i])); + float anglediff = fabs( UTIL_AngleDiff( pev->angles.x, m_iaCustomAnglesX[i] ) ); if( imaxanglediff > anglediff ) { ianglex = m_iaCustomAnglesX[i]; @@ -994,66 +1024,65 @@ void CProp::AngleThink() } } imaxanglediff=360.0f; - for( int i = 0; (i < 10) && ( (i == 0 ) || m_iaCustomAnglesZ[i] ); i++) + for( int i = 0; ( i < 10 ) && ( ( i == 0 ) || m_iaCustomAnglesZ[i] ); i++ ) { - float anglediff = fabs(UTIL_AngleDiff(pev->angles.z, m_iaCustomAnglesZ[i])); + float anglediff = fabs( UTIL_AngleDiff( pev->angles.z, m_iaCustomAnglesZ[i] ) ); if( imaxanglediff > anglediff ) { ianglez = m_iaCustomAnglesZ[i]; imaxanglediff = anglediff; } } - if (fabs(UTIL_AngleDiff(ianglex, pev->angles.x)) > 0.1 || - fabs(UTIL_AngleDiff(ianglez, pev->angles.z)) > 0.1 ) + if( fabs( UTIL_AngleDiff( ianglex, pev->angles.x ) ) > 0.1 || + fabs( UTIL_AngleDiff( ianglez, pev->angles.z ) ) > 0.1 ) { - SetThink( &CProp::AngleThink); + SetThink( &CProp::AngleThink ); pev->nextthink = gpGlobals->time + 0.1; } - pev->angles.x += UTIL_AngleDiff(ianglex, pev->angles.x) * 0.6; - pev->angles.z += UTIL_AngleDiff(ianglez, pev->angles.z) * 0.6; + pev->angles.x += UTIL_AngleDiff( ianglex, pev->angles.x ) * 0.6; + pev->angles.z += UTIL_AngleDiff( ianglez, pev->angles.z ) * 0.6; pev->avelocity.x = pev->avelocity.y = pev->avelocity.z = 0; } - pev->angles.x = UTIL_AngleMod(pev->angles.x); - pev->angles.y = UTIL_AngleMod(pev->angles.y); - pev->angles.z = UTIL_AngleMod(pev->angles.z); + pev->angles.x = UTIL_AngleMod( pev->angles.x ); + pev->angles.y = UTIL_AngleMod( pev->angles.y ); + pev->angles.z = UTIL_AngleMod( pev->angles.z ); } void CProp::DieThink() { - Killed( VARS(m_attacker), GIB_NORMAL ); + Killed( VARS( m_attacker ), GIB_NORMAL ); Die(); } -int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +int CProp::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - Vector r = (pevInflictor->origin - pev->origin); - if ( (!m_attacker - || (pev->velocity.Length() < 700)) - && ((CBaseEntity*)GET_PRIVATE(ENT(pevAttacker)))->IsPlayer()) - m_attacker = ENT(pevAttacker); + Vector r = ( pevInflictor->origin - pev->origin ); + if( ( !m_attacker || ( pev->velocity.Length() < 700 ) ) + && ( (CBaseEntity*)GET_PRIVATE( ENT( pevAttacker ) ) )->IsPlayer() ) + m_attacker = ENT( pevAttacker ); DeployThink(); pev->velocity = r * flDamage / -7; - pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT(100, -100); - ALERT(at_console, "Takedmg: %s %s %f %f\n", STRING(pevInflictor->classname), STRING(pevAttacker->classname), flDamage, pev->health ); + pev->avelocity.x = pev->avelocity.x*0.5 + RANDOM_FLOAT( 100, -100 ); + ALERT( at_console, "Takedmg: %s %s %f %f\n", STRING( pevInflictor->classname ), STRING( pevAttacker->classname ), flDamage, pev->health ); // now some func_breakable code - if ( !(pev->spawnflags & SF_PROP_BREAKABLE ) ) + if( !( pev->spawnflags & SF_PROP_BREAKABLE ) ) return 0; - if ( pev->health <= 0 ) + if( pev->health <= 0 ) return; // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) + 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 ) + if( bitsDamageType & DMG_POISON ) flDamage *= 0.1; g_vecAttackDir = r.Normalize(); // do the damage pev->health -= flDamage; - if ( pev->health <= 0 ) + if( pev->health <= 0 ) { // delayed explode SetThink( &CProp::DieThink ); @@ -1069,84 +1098,84 @@ int CProp::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flD void CProp::KeyValue( KeyValueData* pkvd ) { - ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue); + ALERT( at_console, "%s %s\n", pkvd->szKeyName, pkvd->szValue ); // UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file! - if (FStrEq(pkvd->szKeyName, "explosion")) + if( FStrEq( pkvd->szKeyName, "explosion" ) ) { - if (!stricmp(pkvd->szValue, "directed")) + if( !stricmp( pkvd->szValue, "directed" ) ) m_Explosion = expDirected; - else if (!stricmp(pkvd->szValue, "random")) + else if( !stricmp(pkvd->szValue, "random" ) ) m_Explosion = expRandom; else m_Explosion = expRandom; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "material")) + else if( FStrEq( pkvd->szKeyName, "material" ) ) { - int i = atoi( pkvd->szValue); + int i = atoi( pkvd->szValue ); // 0:glass, 1:metal, 2:flesh, 3:wood - if ((i < 0) || (i >= matLastMaterial)) + if( ( i < 0 ) || ( i >= matLastMaterial ) ) m_Material = matWood; else m_Material = (Materials)i; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "shape")) + else if( FStrEq( pkvd->szKeyName, "shape" ) ) { - int i = atoi( pkvd->szValue); + int i = atoi( pkvd->szValue ); - if ((i < 0) || (i >= SHAPE_NOROTATE)) + if( ( i < 0 ) || ( i >= SHAPE_NOROTATE ) ) m_shape = SHAPE_NOROTATE; else m_shape = (PropShape)i; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) + else if( FStrEq( pkvd->szKeyName, "gibmodel" ) ) { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); + m_iszGibModel = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) + else if( FStrEq( pkvd->szKeyName, "explodemagnitude" ) ) { ExplosionSetMagnitude( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "respawntime") ) + else if( FStrEq( pkvd->szKeyName, "respawntime" ) ) { m_flRespawnTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "customanglesx")) + else if( FStrEq( pkvd->szKeyName, "customanglesx" ) ) { UTIL_StringToIntArray( m_iaCustomAnglesX, ARRAYSIZE( m_iaCustomAnglesX ), pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "customanglesz")) + else if( FStrEq( pkvd->szKeyName, "customanglesz" ) ) { UTIL_StringToIntArray( m_iaCustomAnglesZ, ARRAYSIZE( m_iaCustomAnglesZ ), pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "hmin")) + else if( FStrEq( pkvd->szKeyName, "hmin" ) ) { UTIL_StringToVector( minsH, pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "hmax")) + else if( FStrEq( pkvd->szKeyName, "hmax" ) ) { UTIL_StringToVector( maxsH, pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "vmin")) + else if( FStrEq( pkvd->szKeyName, "vmin" ) ) { UTIL_StringToVector( minsV, pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "vmax")) + else if( FStrEq( pkvd->szKeyName, "vmax" ) ) { UTIL_StringToVector( maxsV, pkvd->szValue ); pkvd->fHandled = TRUE; diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index b59511f4..08000f28 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -26,34 +26,34 @@ CSoundEnt *pSoundEnt; //========================================================= // CSound - Clear - zeros all fields for a sound //========================================================= -void CSound :: Clear ( void ) +void CSound::Clear( void ) { - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_flExpireTime = 0; - m_iNext = SOUNDLIST_EMPTY; - m_iNextAudible = 0; + 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 ) +void CSound::Reset( void ) { - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_iNext = SOUNDLIST_EMPTY; + 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 ) +BOOL CSound::FIsSound( void ) { - if ( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) + if( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) { return TRUE; } @@ -64,9 +64,9 @@ BOOL CSound :: FIsSound ( void ) //========================================================= // FIsScent - returns TRUE if the sound is actually a scent //========================================================= -BOOL CSound :: FIsScent ( void ) +BOOL CSound::FIsScent( void ) { - if ( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) + if( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) { return TRUE; } @@ -77,7 +77,7 @@ BOOL CSound :: FIsScent ( void ) //========================================================= // Spawn //========================================================= -void CSoundEnt :: Spawn( void ) +void CSoundEnt::Spawn( void ) { pev->solid = SOLID_NOT; Initialize(); @@ -90,7 +90,7 @@ void CSoundEnt :: Spawn( void ) // for sounds that have ExpireTimes less than or equal // to the current world time, and these sounds are deallocated. //========================================================= -void CSoundEnt :: Think ( void ) +void CSoundEnt::Think( void ) { int iSound; int iPreviousSound; @@ -100,9 +100,9 @@ void CSoundEnt :: Think ( void ) iPreviousSound = SOUNDLIST_EMPTY; iSound = m_iActiveSound; - while ( iSound != SOUNDLIST_EMPTY ) + while( iSound != SOUNDLIST_EMPTY ) { - if ( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) + if( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) { int iNext = m_SoundPool[ iSound ].m_iNext; @@ -118,17 +118,17 @@ void CSoundEnt :: Think ( void ) } } - if ( m_fShowReport ) + 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 ); + 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 ) +void CSoundEnt::Precache( void ) { } @@ -137,29 +137,29 @@ void CSoundEnt :: Precache ( void ) // 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 ) +void CSoundEnt::FreeSound( int iSound, int iPrevious ) { - if ( !pSoundEnt ) + if( !pSoundEnt ) { // no sound ent! return; } - if ( iPrevious != SOUNDLIST_EMPTY ) + 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; + //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; + 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_SoundPool[iSound].m_iNext = pSoundEnt->m_iFreeSound; pSoundEnt->m_iFreeSound = iSound; } @@ -167,25 +167,25 @@ void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) // 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 CSoundEnt::IAllocSound( void ) { int iNewSound; - if ( m_iFreeSound == SOUNDLIST_EMPTY ) + if( m_iFreeSound == SOUNDLIST_EMPTY ) { // no free sound! - ALERT ( at_console, "Free Sound List is full!\n" ); + 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_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_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. @@ -196,11 +196,11 @@ int CSoundEnt :: IAllocSound( void ) // InsertSound - Allocates a free sound and fills it with // sound info. //========================================================= -void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) +void CSoundEnt::InsertSound( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) { - int iThisSound; + int iThisSound; - if ( !pSoundEnt ) + if( !pSoundEnt ) { // no sound ent! return; @@ -208,23 +208,23 @@ void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, iThisSound = pSoundEnt->IAllocSound(); - if ( iThisSound == SOUNDLIST_EMPTY ) + if( iThisSound == SOUNDLIST_EMPTY ) { - ALERT ( at_console, "Could not AllocSound() for InsertSound() (DLL)\n" ); + 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; + 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 ) +void CSoundEnt::Initialize( void ) { int i; int iSound; @@ -233,30 +233,30 @@ void CSoundEnt :: Initialize ( void ) m_iFreeSound = 0; m_iActiveSound = SOUNDLIST_EMPTY; - for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) + 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].Clear(); + m_SoundPool[i].m_iNext = i + 1; } - m_SoundPool[ i - 1 ].m_iNext = SOUNDLIST_EMPTY;// terminate the list here. + 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++ ) + for( i = 0; i < gpGlobals->maxClients; i++ ) { iSound = pSoundEnt->IAllocSound(); - if ( iSound == SOUNDLIST_EMPTY ) + if( iSound == SOUNDLIST_EMPTY ) { - ALERT ( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); + ALERT( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); return; } - pSoundEnt->m_SoundPool[ iSound ].m_flExpireTime = SOUND_NEVER_EXPIRE; + pSoundEnt->m_SoundPool[iSound].m_flExpireTime = SOUND_NEVER_EXPIRE; } - if ( CVAR_GET_FLOAT("displaysoundlist") == 1 ) + if( CVAR_GET_FLOAT( "displaysoundlist" ) == 1 ) { m_fShowReport = TRUE; } @@ -270,36 +270,36 @@ void CSoundEnt :: Initialize ( void ) // ISoundsInList - returns the number of sounds in the desired // sound list. //========================================================= -int CSoundEnt :: ISoundsInList ( int iListType ) +int CSoundEnt::ISoundsInList( int iListType ) { int i; int iThisSound = 0; - if ( iListType == SOUNDLISTTYPE_FREE ) + if( iListType == SOUNDLISTTYPE_FREE ) { iThisSound = m_iFreeSound; } - else if ( iListType == SOUNDLISTTYPE_ACTIVE ) + else if( iListType == SOUNDLISTTYPE_ACTIVE ) { iThisSound = m_iActiveSound; } else { - ALERT ( at_console, "Unknown Sound List Type!\n" ); + ALERT( at_console, "Unknown Sound List Type!\n" ); } - if ( iThisSound == SOUNDLIST_EMPTY ) + if( iThisSound == SOUNDLIST_EMPTY ) { return 0; } i = 0; - while ( iThisSound != SOUNDLIST_EMPTY ) + while( iThisSound != SOUNDLIST_EMPTY ) { i++; - iThisSound = m_SoundPool[ iThisSound ].m_iNext; + iThisSound = m_SoundPool[iThisSound].m_iNext; } return i; @@ -308,9 +308,9 @@ int CSoundEnt :: ISoundsInList ( int iListType ) //========================================================= // ActiveList - returns the head of the active sound list //========================================================= -int CSoundEnt :: ActiveList ( void ) +int CSoundEnt::ActiveList( void ) { - if ( !pSoundEnt ) + if( !pSoundEnt ) { return SOUNDLIST_EMPTY; } @@ -321,9 +321,9 @@ int CSoundEnt :: ActiveList ( void ) //========================================================= // FreeList - returns the head of the free sound list //========================================================= -int CSoundEnt :: FreeList ( void ) +int CSoundEnt::FreeList( void ) { - if ( !pSoundEnt ) + if( !pSoundEnt ) { return SOUNDLIST_EMPTY; } @@ -335,26 +335,26 @@ int CSoundEnt :: FreeList ( void ) // SoundPointerForIndex - returns a pointer to the instance // of CSound at index's position in the sound pool. //========================================================= -CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) +CSound *CSoundEnt::SoundPointerForIndex( int iIndex ) { - if ( !pSoundEnt ) + if( !pSoundEnt ) { return NULL; } - if ( iIndex > ( MAX_WORLD_SOUNDS - 1 ) ) + if( iIndex > ( MAX_WORLD_SOUNDS - 1 ) ) { - ALERT ( at_console, "SoundPointerForIndex() - Index too large!\n" ); + ALERT( at_console, "SoundPointerForIndex() - Index too large!\n" ); return NULL; } - if ( iIndex < 0 ) + if( iIndex < 0 ) { - ALERT ( at_console, "SoundPointerForIndex() - Index < 0!\n" ); + ALERT( at_console, "SoundPointerForIndex() - Index < 0!\n" ); return NULL; } - return &pSoundEnt->m_SoundPool[ iIndex ]; + return &pSoundEnt->m_SoundPool[iIndex]; } //========================================================= @@ -363,14 +363,14 @@ CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) // 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 CSoundEnt::ClientSoundIndex( edict_t *pClient ) { int iReturn = ENTINDEX( pClient ) - 1; #ifdef _DEBUG - if ( iReturn < 0 || iReturn > gpGlobals->maxClients ) + if( iReturn < 0 || iReturn > gpGlobals->maxClients ) { - ALERT ( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); + ALERT( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); } #endif // _DEBUG diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index f3d67ac6..b1ba1385 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -31,20 +31,20 @@ #include "decals.h" #include "gamerules.h" -extern CGraph WorldGraph; +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 +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]; @@ -62,11 +62,11 @@ MULTIDAMAGE gMultiDamage; //========================================================= int MaxAmmoCarry( int iszName ) { - for ( int i = 0; i < MAX_WEAPONS; i++ ) + for( int i = 0; i < MAX_WEAPONS; i++ ) { - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo1 ) ) + 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 ) ) + if( CBasePlayerItem::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING( iszName ), CBasePlayerItem::ItemInfoArray[i].pszAmmo2 ) ) return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo2; } @@ -87,10 +87,10 @@ Collects multiple small damages into a single damage // // ClearMultiDamage - resets the global multi damage accumulator // -void ClearMultiDamage(void) +void ClearMultiDamage( void ) { gMultiDamage.pEntity = NULL; - gMultiDamage.amount = 0; + gMultiDamage.amount = 0; gMultiDamage.type = 0; } @@ -99,34 +99,32 @@ void ClearMultiDamage(void) // // GLOBALS USED: // gMultiDamage - -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) +void ApplyMultiDamage( entvars_t *pevInflictor, entvars_t *pevAttacker ) { - Vector vecSpot1;//where blood comes from - Vector vecDir;//direction blood should go - TraceResult tr; + Vector vecSpot1;//where blood comes from + Vector vecDir;//direction blood should go + TraceResult tr; - if ( !gMultiDamage.pEntity ) + if( !gMultiDamage.pEntity ) return; - gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); + gMultiDamage.pEntity->TakeDamage( pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); } // GLOBALS USED: // gMultiDamage - -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType ) { - if ( !pEntity ) + if( !pEntity ) return; gMultiDamage.type |= bitsDamageType; - if ( pEntity != gMultiDamage.pEntity ) + if( pEntity != gMultiDamage.pEntity ) { - ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! - gMultiDamage.pEntity = pEntity; - gMultiDamage.amount = 0; + ApplyMultiDamage( pevInflictor,pevInflictor ); // UNDONE: wrong attacker! + gMultiDamage.pEntity = pEntity; + gMultiDamage.amount = 0; } gMultiDamage.amount += flDamage; @@ -137,15 +135,15 @@ void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDama SpawnBlood ================ */ -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) +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)); + if( !pEntity ) + return ( DECAL_GUNSHOT1 + RANDOM_LONG( 0, 4 ) ); return pEntity->DamageDecal( bitsDamageType ); } @@ -153,15 +151,15 @@ int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) void DecalGunshot( TraceResult *pTrace, int iBulletType ) { // Is the entity valid - if ( !UTIL_IsValidEntity( pTrace->pHit ) ) + if( !UTIL_IsValidEntity( pTrace->pHit ) ) return; - if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) + 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); + if( !FNullEnt( pTrace->pHit ) ) + pEntity = CBaseEntity::Instance( pTrace->pHit ); switch( iBulletType ) { @@ -190,22 +188,21 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType ) // // 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 ) +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_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 + WRITE_BYTE( soundtype ); + WRITE_BYTE( 25 );// 2.5 seconds MESSAGE_END(); } @@ -214,14 +211,14 @@ void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rota void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) { MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE ( TE_EXPLODEMODEL ); + 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 + WRITE_BYTE( 15 );// 1.5 seconds MESSAGE_END(); } #endif @@ -232,18 +229,18 @@ int giAmmoIndex = 0; void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { // make sure it's not already in the registry - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) + for( int i = 0; i < MAX_AMMO_SLOTS; i++ ) { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName) + if( !CBasePlayerItem::AmmoInfoArray[i].pszName) continue; - if ( stricmp( CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname ) == 0 ) + 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 ) + if( giAmmoIndex >= MAX_AMMO_SLOTS ) giAmmoIndex = 0; CBasePlayerItem::AmmoInfoArray[giAmmoIndex].pszName = szAmmoname; @@ -256,29 +253,29 @@ void UTIL_PrecacheOtherWeapon( const char *szClassname ) edict_t *pent; pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) + if( FNullEnt( pent ) ) { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); + ALERT( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); return; } - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); + CBaseEntity *pEntity = CBaseEntity::Instance( VARS( pent ) ); - if (pEntity) + if( pEntity ) { ItemInfo II; - pEntity->Precache( ); + pEntity->Precache(); memset( &II, 0, sizeof II ); - if ( ((CBasePlayerItem*)pEntity)->GetItemInfo( &II ) ) + if( ( (CBasePlayerItem*)pEntity )->GetItemInfo( &II ) ) { CBasePlayerItem::ItemInfoArray[II.iId] = II; - if ( II.pszAmmo1 && *II.pszAmmo1 ) + if( II.pszAmmo1 && *II.pszAmmo1 ) { AddAmmoNameToAmmoRegistry( II.pszAmmo1 ); } - if ( II.pszAmmo2 && *II.pszAmmo2 ) + if( II.pszAmmo2 && *II.pszAmmo2 ) { AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); } @@ -287,11 +284,11 @@ void UTIL_PrecacheOtherWeapon( const char *szClassname ) } } - REMOVE_ENTITY(pent); + REMOVE_ENTITY( pent ); } // called by worldspawn -void W_Precache(void) +void W_Precache( void ) { memset( CBasePlayerItem::ItemInfoArray, 0, sizeof(CBasePlayerItem::ItemInfoArray) ); memset( CBasePlayerItem::AmmoInfoArray, 0, sizeof(CBasePlayerItem::AmmoInfoArray) ); @@ -326,9 +323,7 @@ void W_Precache(void) // 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" ); @@ -336,9 +331,7 @@ void W_Precache(void) // 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" ); @@ -361,37 +354,37 @@ void W_Precache(void) // hornetgun UTIL_PrecacheOtherWeapon( "weapon_hornetgun" ); - if ( g_pGameRules->IsDeathmatch() ) + 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_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"); + g_sModelIndexLaserDot = PRECACHE_MODEL( "sprites/laserdot.spr" ); // used by explosions - PRECACHE_MODEL ("models/grenade.mdl"); - PRECACHE_MODEL ("sprites/explode1.spr"); + 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/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/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 + 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[] = @@ -421,28 +414,28 @@ TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = 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 + //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 ) +void CBasePlayerItem::SetObjectCollisionBox( void ) { - pev->absmin = pev->origin + Vector(-24, -24, 0); - pev->absmax = pev->origin + Vector(24, 24, 16); + 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 ) +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. + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );//pointsize until it lands on the ground. SetTouch( &CBasePlayerItem::DefaultTouch ); SetThink( &CBasePlayerItem::FallThink ); @@ -457,18 +450,18 @@ void CBasePlayerItem :: FallInit( void ) // to trigger and set it in a large box that helps the // player get it. //========================================================= -void CBasePlayerItem::FallThink ( void ) +void CBasePlayerItem::FallThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - if ( pev->flags & FL_ONGROUND ) + 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 ) ) + 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); + int pitch = 95 + RANDOM_LONG( 0, 29 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch ); } // lie flat @@ -484,10 +477,10 @@ void CBasePlayerItem::FallThink ( void ) //========================================================= void CBasePlayerItem::Materialize( void ) { - if ( pev->effects & EF_NODRAW ) + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); pev->effects &= ~EF_NODRAW; pev->effects |= EF_MUZZLEFLASH; } @@ -507,7 +500,7 @@ void CBasePlayerItem::AttemptToMaterialize( void ) { float time = g_pGameRules->FlWeaponTryRespawn( this ); - if ( time == 0 ) + if( time == 0 ) { Materialize(); return; @@ -520,9 +513,9 @@ void CBasePlayerItem::AttemptToMaterialize( void ) // CheckRespawn - a player is taking this weapon, should // it respawn? //========================================================= -void CBasePlayerItem :: CheckRespawn ( void ) +void CBasePlayerItem::CheckRespawn( void ) { - switch ( g_pGameRules->WeaponShouldRespawn( this ) ) + switch( g_pGameRules->WeaponShouldRespawn( this ) ) { case GR_WEAPON_RESPAWN_YES: Respawn(); @@ -543,13 +536,13 @@ CBaseEntity* CBasePlayerItem::Respawn( void ) // 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 ) + if( pNewWeapon ) { pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now pNewWeapon->SetTouch( NULL );// no touch pNewWeapon->SetThink( &CBasePlayerItem::AttemptToMaterialize ); - DROP_TO_FLOOR ( ENT(pev) ); + 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. @@ -557,7 +550,7 @@ CBaseEntity* CBasePlayerItem::Respawn( void ) } else { - ALERT ( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); + ALERT( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); } return pNewWeapon; @@ -566,25 +559,25 @@ CBaseEntity* CBasePlayerItem::Respawn( void ) void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { // if it's not a player, ignore - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) return; CBasePlayer *pPlayer = (CBasePlayer *)pOther; // can I have this? - if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) + if( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) { - if ( gEvilImpulse101 ) + if( gEvilImpulse101 ) { UTIL_Remove( this ); } return; } - if (pOther->AddPlayerItem( this )) + if( pOther->AddPlayerItem( this ) ) { AttachToPlayer( pPlayer ); - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? @@ -593,9 +586,9 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) { #if defined( CLIENT_WEAPONS ) - if ( !isPredicted ) + if( !isPredicted ) #else - if ( 1 ) + if( 1 ) #endif { return ( attack_time <= curtime ) ? TRUE : FALSE; @@ -608,7 +601,7 @@ BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) void CBasePlayerWeapon::ItemPostFrame( void ) { - if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) + if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); @@ -622,9 +615,9 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fInReload = FALSE; } - if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) + if( ( m_pPlayer->pev->button & IN_ATTACK2 ) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + if( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { m_fFireOnEmpty = TRUE; } @@ -633,9 +626,9 @@ void CBasePlayerWeapon::ItemPostFrame( void ) SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } - else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) + 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()] ) ) + if( ( m_iClip == 0 && pszAmmo1() ) || ( iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { m_fFireOnEmpty = TRUE; } @@ -643,21 +636,20 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_pPlayer->TabulateAmmo(); PrimaryAttack(); } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + 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) ) ) + 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 ) ) + 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 ) ) + if( !( iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY ) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; return; @@ -666,19 +658,19 @@ void CBasePlayerWeapon::ItemPostFrame( void ) 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 ) ) + if( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD ) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { Reload(); return; } } - WeaponIdle( ); + WeaponIdle(); return; } // catch all - if ( ShouldWeaponIdle() ) + if( ShouldWeaponIdle() ) { WeaponIdle(); } @@ -686,13 +678,13 @@ void CBasePlayerWeapon::ItemPostFrame( void ) void CBasePlayerItem::DestroyItem( void ) { - if ( m_pPlayer ) + if( m_pPlayer ) { // if attached to a player, remove. m_pPlayer->RemovePlayerItem( this ); } - Kill( ); + Kill(); } int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) @@ -705,14 +697,14 @@ int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) void CBasePlayerItem::Drop( void ) { SetTouch( NULL ); - SetThink( &CBaseEntity::SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + .1; } void CBasePlayerItem::Kill( void ) { SetTouch( NULL ); - SetThink( &CBaseEntity::SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + .1; } @@ -722,7 +714,7 @@ void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) m_pPlayer->pev->weaponmodel = 0; } -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) +void CBasePlayerItem::AttachToPlayer( CBasePlayer *pPlayer ) { pev->movetype = MOVETYPE_FOLLOW; pev->solid = SOLID_NOT; @@ -739,7 +731,7 @@ void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) // CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { - if ( m_iDefaultAmmo ) + if( m_iDefaultAmmo ) { return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); } @@ -754,16 +746,16 @@ int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - pPlayer->pev->weapons |= (1<pev->weapons |= ( 1 << m_iId ); - if ( !m_iPrimaryAmmoType ) + if( !m_iPrimaryAmmoType ) { m_iPrimaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo1() ); m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); } - if (bResult) - return AddWeapon( ); + if( bResult ) + return AddWeapon(); return FALSE; } @@ -771,39 +763,36 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { BOOL bSend = FALSE; int state = 0; - if ( pPlayer->m_pActiveItem == this ) + if( pPlayer->m_pActiveItem == this ) { - if ( pPlayer->m_fOnTarget ) + if( pPlayer->m_fOnTarget ) state = WEAPON_IS_ONTARGET; else state = 1; } // Forcing send of all data! - if ( !pPlayer->m_fWeapon ) + 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( this == pPlayer->m_pActiveItem || this == pPlayer->m_pClientActiveItem ) { - if ( pPlayer->m_pActiveItem != 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 ) + if( m_iClip != m_iClientClip || state != m_iClientWeaponState || pPlayer->m_iFOV != pPlayer->m_iClientFOV ) { bSend = TRUE; } - if ( bSend ) + if( bSend ) { MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); WRITE_BYTE( state ); @@ -816,7 +805,7 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) pPlayer->m_fWeapon = TRUE; } - if ( m_pNext ) + if( m_pNext ) m_pNext->UpdateClientData( pPlayer ); return 1; @@ -824,7 +813,7 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) { - if ( UseDecrement() ) + if( UseDecrement() ) skiplocal = 1; else skiplocal = 0; @@ -832,25 +821,25 @@ void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) m_pPlayer->pev->weaponanim = iAnim; #if defined( CLIENT_WEAPONS ) - if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) + 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. + WRITE_BYTE( iAnim ); // sequence number + WRITE_BYTE( pev->body ); // weaponmodel bodygroup. MESSAGE_END(); } -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) +BOOL CBasePlayerWeapon::AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { int iIdAmmo; - if (iMaxClip < 1) + if( iMaxClip < 1 ) { m_iClip = -1; iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); } - else if (m_iClip == 0) + else if( m_iClip == 0 ) { int i; i = min( m_iClip + iCount, iMaxClip ) - m_iClip; @@ -864,21 +853,21 @@ BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing - if (iIdAmmo > 0) + if( iIdAmmo > 0 ) { m_iPrimaryAmmoType = iIdAmmo; - if (m_pPlayer->HasPlayerItem( this ) ) + 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); + 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 ) +BOOL CBasePlayerWeapon::AddSecondaryAmmo( int iCount, char *szName, int iMax ) { int iIdAmmo; @@ -886,10 +875,10 @@ BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) //m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing - if (iIdAmmo > 0) + if( iIdAmmo > 0 ) { m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); } return iIdAmmo > 0 ? TRUE : FALSE; } @@ -900,11 +889,11 @@ BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) // (does it have ammo loaded? do I have any ammo for the // weapon?, etc) //========================================================= -BOOL CBasePlayerWeapon :: IsUseable( void ) +BOOL CBasePlayerWeapon::IsUseable( void ) { - if ( m_iClip <= 0 ) + if( m_iClip <= 0 ) { - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) + 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; @@ -914,29 +903,29 @@ BOOL CBasePlayerWeapon :: IsUseable( void ) return TRUE; } -BOOL CBasePlayerWeapon :: CanDeploy( void ) +BOOL CBasePlayerWeapon::CanDeploy( void ) { BOOL bHasAmmo = 0; - if ( !pszAmmo1() ) + if( !pszAmmo1() ) { // this weapon doesn't use ammo, can always deploy. return TRUE; } - if ( pszAmmo1() ) + if( pszAmmo1() ) { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); + bHasAmmo |= ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0 ); } - if ( pszAmmo2() ) + if( pszAmmo2() ) { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); + bHasAmmo |= ( m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0 ); } - if (m_iClip > 0) + if( m_iClip > 0 ) { bHasAmmo |= 1; } - if (!bHasAmmo) + if( !bHasAmmo ) { return FALSE; } @@ -944,14 +933,14 @@ BOOL CBasePlayerWeapon :: CanDeploy( void ) return TRUE; } -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) +BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) { - if (!CanDeploy( )) + if( !CanDeploy() ) return FALSE; m_pPlayer->TabulateAmmo(); - m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); - m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); + m_pPlayer->pev->viewmodel = MAKE_STRING( szViewModel ); + m_pPlayer->pev->weaponmodel = MAKE_STRING( szWeaponModel ); strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); SendWeaponAnim( iAnim, skiplocal, body ); @@ -961,14 +950,14 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, return TRUE; } -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) +BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) { - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) return FALSE; - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + int j = min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); - if (j == 0) + if( j == 0 ) return FALSE; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; @@ -982,18 +971,18 @@ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, return TRUE; } -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +BOOL CBasePlayerWeapon::PlayEmptySound( void ) { - if (m_iPlayEmptySound) + if( m_iPlayEmptySound ) { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); + 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 ) +void CBasePlayerWeapon::ResetEmptySound( void ) { m_iPlayEmptySound = 1; } @@ -1023,7 +1012,7 @@ void CBasePlayerAmmo::Spawn( void ) { pev->movetype = MOVETYPE_TOSS; pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 16 ) ); UTIL_SetOrigin( pev, pev->origin ); SetTouch( &CBasePlayerAmmo::DefaultTouch ); @@ -1044,10 +1033,10 @@ CBaseEntity* CBasePlayerAmmo::Respawn( void ) void CBasePlayerAmmo::Materialize( void ) { - if ( pev->effects & EF_NODRAW ) + 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); pev->effects &= ~EF_NODRAW; pev->effects |= EF_MUZZLEFLASH; } @@ -1055,31 +1044,31 @@ void CBasePlayerAmmo::Materialize( void ) SetTouch( &CBasePlayerAmmo::DefaultTouch ); } -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) +void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) { - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { return; } - if (AddAmmo( pOther )) + if( AddAmmo( pOther ) ) { - if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) + if( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) { Respawn(); } else { SetTouch( NULL ); - SetThink( &CBaseEntity::SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + .1; } } - else if (gEvilImpulse101) + else if( gEvilImpulse101 ) { // evil impulse 101 hack, kill always SetTouch( NULL ); - SetThink( &CBaseEntity::SUB_Remove); + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time + .1; } } @@ -1094,9 +1083,9 @@ void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) //========================================================= int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { - int iReturn; + int iReturn; - if ( pszAmmo1() != NULL ) + 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. @@ -1104,7 +1093,7 @@ int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) m_iDefaultAmmo = 0; } - if ( pszAmmo2() != NULL ) + if( pszAmmo2() != NULL ) { iReturn = pWeapon->AddSecondaryAmmo( 0, (char *)pszAmmo2(), iMaxAmmo2() ); } @@ -1117,9 +1106,9 @@ int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) //========================================================= int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { - int iAmmo; + int iAmmo; - if ( m_iClip == WEAPON_NOCLIP ) + if( m_iClip == WEAPON_NOCLIP ) { iAmmo = 0;// guns with no clips always come empty if they are second-hand } @@ -1127,7 +1116,7 @@ int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { iAmmo = m_iClip; } - + return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); // , &m_iPrimaryAmmoType } @@ -1165,23 +1154,23 @@ IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ) //========================================================= void CWeaponBox::Precache( void ) { - PRECACHE_MODEL("models/w_weaponbox.mdl"); + PRECACHE_MODEL( "models/w_weaponbox.mdl" ); } //========================================================= //========================================================= -void CWeaponBox :: KeyValue( KeyValueData *pkvd ) +void CWeaponBox::KeyValue( KeyValueData *pkvd ) { - if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) + if( m_cAmmoTypes < MAX_AMMO_SLOTS ) { - PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); + 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 ); + ALERT( at_console, "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); } } @@ -1190,14 +1179,14 @@ void CWeaponBox :: KeyValue( KeyValueData *pkvd ) //========================================================= void CWeaponBox::Spawn( void ) { - Precache( ); + Precache(); pev->movetype = MOVETYPE_TOSS; pev->solid = SOLID_TRIGGER; UTIL_SetSize( pev, g_vecZero, g_vecZero ); - SET_MODEL( ENT(pev), "models/w_weaponbox.mdl"); + SET_MODEL( ENT( pev ), "models/w_weaponbox.mdl" ); } //========================================================= @@ -1210,13 +1199,13 @@ void CWeaponBox::Kill( void ) int i; // destroy the weapons - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - pWeapon = m_rgpPlayerItems[ i ]; + pWeapon = m_rgpPlayerItems[i]; - while ( pWeapon ) + while( pWeapon ) { - pWeapon->SetThink( &CBaseEntity::SUB_Remove); + pWeapon->SetThink( &CBaseEntity::SUB_Remove ); pWeapon->pev->nextthink = gpGlobals->time + 0.1; pWeapon = pWeapon->m_pNext; } @@ -1232,18 +1221,18 @@ void CWeaponBox::Kill( void ) //========================================================= void CWeaponBox::Touch( CBaseEntity *pOther ) { - if ( !(pev->flags & FL_ONGROUND ) ) + if( !( pev->flags & FL_ONGROUND ) ) { return; } - if ( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() ) { // only players may touch a weaponbox. return; } - if ( !pOther->IsAlive() ) + if( !pOther->IsAlive() ) { // no dead guys. return; @@ -1253,39 +1242,39 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) int i; // dole out ammo - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + for( i = 0; i < MAX_AMMO_SLOTS; i++ ) { - if ( !FStringNull( m_rgiszAmmo[ 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 ] ) ); + 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]) ); + //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; + 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++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[ i ] ) + if( m_rgpPlayerItems[i] ) { CBasePlayerItem *pItem; // have at least one weapon in this slot - while ( m_rgpPlayerItems[ i ] ) + while( m_rgpPlayerItems[i] ) { - //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); + //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 + pItem = m_rgpPlayerItems[i]; + m_rgpPlayerItems[i] = m_rgpPlayerItems[i]->m_pNext;// unlink this weapon from the box - if ( pPlayer->AddPlayerItem( pItem ) ) + if( pPlayer->AddPlayerItem( pItem ) ) { pItem->AttachToPlayer( pPlayer ); } @@ -1304,14 +1293,14 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) { // is one of these weapons already packed in this box? - if ( HasWeapon( pWeapon ) ) + if( HasWeapon( pWeapon ) ) { return FALSE;// box can only hold one of each weapon type } - if ( pWeapon->m_pPlayer ) + if( pWeapon->m_pPlayer ) { - if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) + if( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) { // failed to unhook the weapon from the player! return FALSE; @@ -1320,16 +1309,16 @@ BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) int iWeaponSlot = pWeapon->iItemSlot(); - if ( m_rgpPlayerItems[ iWeaponSlot ] ) + 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; + pWeapon->m_pNext = m_rgpPlayerItems[iWeaponSlot]; + m_rgpPlayerItems[iWeaponSlot] = pWeapon; } else { // first weapon we have for this slot - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; + m_rgpPlayerItems[iWeaponSlot] = pWeapon; pWeapon->m_pNext = NULL; } @@ -1344,7 +1333,7 @@ BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) pWeapon->SetTouch( NULL ); pWeapon->m_pPlayer = NULL; - //ALERT ( at_console, "packed %s\n", STRING(pWeapon->pev->classname) ); + //ALERT( at_console, "packed %s\n", STRING( pWeapon->pev->classname ) ); return TRUE; } @@ -1356,18 +1345,18 @@ BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) { int iMaxCarry; - if ( FStringNull( iszName ) ) + if( FStringNull( iszName ) ) { // error here - ALERT ( at_console, "NULL String in PackAmmo!\n" ); + ALERT( at_console, "NULL String in PackAmmo!\n" ); return FALSE; } iMaxCarry = MaxAmmoCarry( iszName ); - if ( iMaxCarry != -1 && iCount > 0 ) + if( iMaxCarry != -1 && iCount > 0 ) { - //ALERT ( at_console, "Packed %d rounds of %s\n", iCount, STRING(iszName) ); + //ALERT( at_console, "Packed %d rounds of %s\n", iCount, STRING( iszName ) ); GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); return TRUE; } @@ -1382,15 +1371,15 @@ int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NU { int i; - for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) + for( i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++ ) { - if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) + if( stricmp( szName, STRING( m_rgiszAmmo[i] ) ) == 0 ) { - if (pIndex) + if( pIndex ) *pIndex = i; - int iAdd = min( iCount, iMax - m_rgAmmo[i]); - if (iCount == 0 || iAdd > 0) + int iAdd = min( iCount, iMax - m_rgAmmo[i] ); + if( iCount == 0 || iAdd > 0 ) { m_rgAmmo[i] += iAdd; @@ -1399,9 +1388,9 @@ int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NU return -1; } } - if (i < MAX_AMMO_SLOTS) + if( i < MAX_AMMO_SLOTS ) { - if (pIndex) + if( pIndex ) *pIndex = i; m_rgiszAmmo[i] = MAKE_STRING( szName ); @@ -1409,7 +1398,7 @@ int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NU return i; } - ALERT( at_console, "out of named ammo slots\n"); + ALERT( at_console, "out of named ammo slots\n" ); return i; } @@ -1421,9 +1410,9 @@ BOOL CWeaponBox::HasWeapon( CBasePlayerItem *pCheckItem ) { CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - while (pItem) + while( pItem ) { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) + if( FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname ) ) ) { return TRUE; } @@ -1440,17 +1429,17 @@ BOOL CWeaponBox::IsEmpty( void ) { int i; - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + for( i = 0; i < MAX_ITEM_TYPES; i++ ) { - if ( m_rgpPlayerItems[ i ] ) + if( m_rgpPlayerItems[i] ) { return FALSE; } } - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + for( i = 0; i < MAX_AMMO_SLOTS; i++ ) { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) + if( !FStringNull( m_rgiszAmmo[i] ) ) { // still have a bit of this type of ammo return FALSE; @@ -1464,11 +1453,10 @@ BOOL CWeaponBox::IsEmpty( void ) //========================================================= void CWeaponBox::SetObjectCollisionBox( void ) { - pev->absmin = pev->origin + Vector(-16, -16, 0); - pev->absmax = pev->origin + Vector(16, 16, 16); + 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 ); @@ -1542,4 +1530,3 @@ TYPEDESCRIPTION CSatchel::m_SaveData[] = }; IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ) - From 2f0174474f4a7b17a899df4755d606b162ba5ab3 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 1 Aug 2016 22:11:01 +0500 Subject: [PATCH 054/227] Oops. Fix macros. --- cl_dll/cl_util.h | 36 ++++++++++++++++++------------------ cl_dll/scoreboard.cpp | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 8d9661b2..84488050 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -43,29 +43,29 @@ inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } -#define SPR_Load( *gEngfuncs.pfnSPR_Load ) -#define SPR_Set( *gEngfuncs.pfnSPR_Set ) -#define SPR_Frames( *gEngfuncs.pfnSPR_Frames ) -#define SPR_GetList( *gEngfuncs.pfnSPR_GetList ) +#define SPR_Load ( *gEngfuncs.pfnSPR_Load ) +#define SPR_Set ( *gEngfuncs.pfnSPR_Set ) +#define SPR_Frames ( *gEngfuncs.pfnSPR_Frames ) +#define SPR_GetList ( *gEngfuncs.pfnSPR_GetList ) // SPR_Draw draws a the current sprite as solid -#define SPR_Draw( *gEngfuncs.pfnSPR_Draw ) +#define SPR_Draw ( *gEngfuncs.pfnSPR_Draw ) // SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) -#define SPR_DrawHoles( *gEngfuncs.pfnSPR_DrawHoles ) +#define SPR_DrawHoles ( *gEngfuncs.pfnSPR_DrawHoles ) // SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) -#define SPR_DrawAdditive( *gEngfuncs.pfnSPR_DrawAdditive ) +#define SPR_DrawAdditive ( *gEngfuncs.pfnSPR_DrawAdditive ) // SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. -#define SPR_EnableScissor( *gEngfuncs.pfnSPR_EnableScissor ) +#define SPR_EnableScissor ( *gEngfuncs.pfnSPR_EnableScissor ) // SPR_DisableScissor disables the clipping rect -#define SPR_DisableScissor( *gEngfuncs.pfnSPR_DisableScissor ) +#define SPR_DisableScissor ( *gEngfuncs.pfnSPR_DisableScissor ) // -#define FillRGBA( *gEngfuncs.pfnFillRGBA ) +#define FillRGBA ( *gEngfuncs.pfnFillRGBA ) // ScreenHeight returns the height of the screen, in pixels -#define ScreenHeight( gHUD.m_scrinfo.iHeight ) +#define ScreenHeight ( gHUD.m_scrinfo.iHeight ) // ScreenWidth returns the width of the screen, in pixels -#define ScreenWidth( gHUD.m_scrinfo.iWidth ) +#define ScreenWidth ( gHUD.m_scrinfo.iWidth ) // Use this to set any co-ords in 640x480 space #define XRES(x) ( (int)( float(x) * ( (float)ScreenWidth / 640.0f ) + 0.5f ) ) @@ -75,11 +75,11 @@ inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int fl #define XPROJECT(x) ( ( 1.0f + (x) ) * ScreenWidth * 0.5f ) #define YPROJECT(y) ( ( 1.0f - (y) ) * ScreenHeight * 0.5f ) -#define GetScreenInfo( *gEngfuncs.pfnGetScreenInfo ) -#define ServerCmd( *gEngfuncs.pfnServerCmd ) -#define ClientCmd( *gEngfuncs.pfnClientCmd ) -#define SetCrosshair( *gEngfuncs.pfnSetCrosshair ) -#define AngleVectors( *gEngfuncs.pfnAngleVectors ) +#define GetScreenInfo ( *gEngfuncs.pfnGetScreenInfo ) +#define ServerCmd ( *gEngfuncs.pfnServerCmd ) +#define ClientCmd ( *gEngfuncs.pfnClientCmd ) +#define SetCrosshair ( *gEngfuncs.pfnSetCrosshair ) +#define AngleVectors ( *gEngfuncs.pfnAngleVectors ) extern cvar_t *hud_textmode; extern float g_hud_text_color[3]; inline void DrawSetTextColor( float r, float g, float b ) @@ -135,7 +135,7 @@ inline void CenterPrint( const char *string ) } // returns the players name of entity no. -#define GetPlayerInfo( *gEngfuncs.pfnGetPlayerInfo ) +#define GetPlayerInfo ( *gEngfuncs.pfnGetPlayerInfo ) // sound functions inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 62d140e1..2e0722f9 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -107,7 +107,7 @@ int SCOREBOARD_WIDTH = 320; // Y positions #define ROW_GAP 13 #define ROW_RANGE_MIN 15 -#define ROW_RANGE_MAX( ScreenHeight - 50 ) +#define ROW_RANGE_MAX ( ScreenHeight - 50 ) int CHudScoreboard::Draw( float fTime ) { From 213653e3729165ac22f1535955a50ef2f1b3f9cd Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 1 Aug 2016 22:14:28 +0500 Subject: [PATCH 055/227] Remove duplicate macros. --- cl_dll/eventscripts.h | 44 ------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h index c052805d..bb835474 100644 --- a/cl_dll/eventscripts.h +++ b/cl_dll/eventscripts.h @@ -15,49 +15,6 @@ #define FTENT_FADEOUT 0x00000080 -#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. - -// time-based damage -//mask off TF-specific stuff too -#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage - -#define DMG_DROWN (1 << 14) // Drowning -#define DMG_FIRSTTIMEBASED DMG_DROWN - -#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) - -//TF ADDITIONS -#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn -#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance -#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. -#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor -#define DMG_AIMED (1 << 28) // Does Hit location damage -#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls - -#define DMG_CALTROP (1 << 30) -#define DMG_HALLUC (1 << 31) - // Some of these are HL/TFC specific? void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); @@ -69,5 +26,4 @@ void EV_CreateTracer( float *start, float *end ); struct cl_entity_s *GetEntity( int idx ); struct cl_entity_s *GetViewEntity( void ); void EV_MuzzleFlash( void ); - #endif // EVENTSCRIPTSH From acd54c6edfacc667267a6ed3b9eee659a3e14c33 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 1 Aug 2016 22:18:54 +0500 Subject: [PATCH 056/227] Rework DNO_VOICEGAMEMGR macro. --- dlls/multiplay_gamerules.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index cd5ffaf2..43a24077 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -26,7 +26,9 @@ #include "skill.h" #include "game.h" #include "items.h" +#ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" +#endif #include "hltv.h" extern DLL_GLOBAL CGameRules *g_pGameRules; @@ -46,7 +48,6 @@ float g_flIntermissionStartTime = 0; #ifndef NO_VOICEGAMEMGR CVoiceGameMgr g_VoiceGameMgr; -#endif class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper { @@ -66,7 +67,7 @@ public: }; static CMultiplayGameMgrHelper g_GameMgrHelper; - +#endif //********************************************************* // Rules for the half-life multiplayer game. //********************************************************* From 7c17f6e0428878cc4512c202331cfac54b0bb4b3 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 2 Aug 2016 16:59:22 +0500 Subject: [PATCH 057/227] Rework initialization. --- cl_dll/hl/hl_weapons.cpp | 4 +--- cl_dll/hud_servers.cpp | 3 +-- cl_dll/statusbar.cpp | 3 +-- dlls/client.cpp | 7 ++----- dlls/multiplay_gamerules.cpp | 3 +-- dlls/player.cpp | 6 ++---- dlls/sound.cpp | 6 +++--- dlls/stats.cpp | 3 +-- dlls/teamplay_gamerules.cpp | 4 +--- dlls/weapons.cpp | 5 +---- pm_shared/pm_shared.c | 4 ++-- 11 files changed, 16 insertions(+), 32 deletions(-) diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index c712b76f..5a17e858 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -688,11 +688,9 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm int buttonsChanged; CBasePlayerWeapon *pWeapon = NULL; CBasePlayerWeapon *pCurrent; - weapon_data_t nulldata, *pfrom, *pto; + weapon_data_t nulldata = {0}, *pfrom, *pto; static int lasthealth; - memset( &nulldata, 0, sizeof(nulldata) ); - HUD_InitClientWeapons(); // Get current clock diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp index 3cdab827..67973c75 100644 --- a/cl_dll/hud_servers.cpp +++ b/cl_dll/hud_servers.cpp @@ -914,8 +914,7 @@ void CHudServers::RequestBroadcastList( int clearpending ) m_nDone = 0; m_dStarted = m_fElapsed; - netadr_t adr; - memset( &adr, 0, sizeof(adr) ); + netadr_t adr = {0}; if( clearpending ) { diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index e730f05e..98b317c5 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -73,8 +73,7 @@ void CHudStatusBar::Reset( void ) void CHudStatusBar::ParseStatusString( int line_num ) { // localise string first - char szBuffer[MAX_STATUSTEXT_LENGTH]; - memset( szBuffer, 0, sizeof szBuffer ); + char szBuffer[MAX_STATUSTEXT_LENGTH] = {0}; gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH ); // parse m_szStatusText & m_iStatusValues into m_szStatusBar diff --git a/dlls/client.cpp b/dlls/client.cpp index 908769db..21e5d810 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1489,8 +1489,6 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); CBasePlayerWeapon *gun; - ItemInfo II; - memset( info, 0, 32 * sizeof(weapon_data_t) ); if( !pl ) @@ -1509,8 +1507,8 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); if( gun && gun->UseDecrement() ) { + ItemInfo II = {0}; // Get The ID. - memset( &II, 0, sizeof(II) ); gun->GetItemInfo( &II ); if( II.iId >= 0 && II.iId < 32 ) @@ -1610,8 +1608,7 @@ void UpdateClientData( const struct edict_s *ent, int sendweapons, struct client gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); if( gun && gun->UseDecrement() ) { - ItemInfo II; - memset( &II, 0, sizeof(II) ); + ItemInfo II = {0}; gun->GetItemInfo( &II ); cd->m_iId = II.iId; diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 43a24077..929c2bf6 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1319,7 +1319,6 @@ 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; @@ -1332,8 +1331,8 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) // the first map name in the file becomes the default while( 1 ) { + char szBuffer[MAX_RULE_BUFFER] = {0}; hasbuffer = 0; - memset( szBuffer, 0, MAX_RULE_BUFFER ); pFileList = COM_Parse( pFileList ); if( strlen( com_token ) <= 0 ) diff --git a/dlls/player.cpp b/dlls/player.cpp index 708096b2..2f097072 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -660,12 +660,11 @@ 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? + CBasePlayerWeapon *rgpPackWeapons[20] = {0};// 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, NULL, sizeof(rgpPackWeapons) ); memset( iPackAmmo, -1, sizeof(iPackAmmo) ); // get the game rules @@ -1624,11 +1623,10 @@ void CBasePlayer::InitStatusBar() void CBasePlayer::UpdateStatusBar() { - int newSBarState[SBAR_END]; + int newSBarState[SBAR_END] = {0}; char sbuf0[SBAR_STRING_SIZE]; char sbuf1[ SBAR_STRING_SIZE ]; - memset( newSBarState, 0, sizeof(newSBarState) ); strcpy( sbuf0, m_SbarString0 ); strcpy( sbuf1, m_SbarString1 ); diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 7ca01410..5f0d3da3 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1261,8 +1261,6 @@ void SENTENCEG_Init() gcallsentences = 0; memset( rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG) ); - memset( buffer, 0, 512 ); - memset( szgroup, 0, 64 ); isentencegs = -1; int filePos = 0, fileSize; @@ -1270,6 +1268,7 @@ void SENTENCEG_Init() if( !pMemFile ) return; + memset( buffer, 0, 512 ); // for each line in the file... while( memfgets( pMemFile, fileSize, filePos, buffer, 511 ) != NULL ) { @@ -1322,6 +1321,7 @@ void SENTENCEG_Init() buffer[j + 1] = 0; + memset( szgroup, 0, 64 ); // if new name doesn't match previous group name, // make a new group. if( strcmp( szgroup, &( buffer[i] ) ) ) @@ -1527,12 +1527,12 @@ void TEXTURETYPE_Init() memset( grgchTextureType, 0, CTEXTURESMAX ); gcTextures = 0; - memset( buffer, 0, 512 ); pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); if( !pMemFile ) return; + memset( buffer, 0, 512 ); // for each line in the file... while( memfgets( pMemFile, fileSize, filePos, buffer, 511 ) != NULL && ( gcTextures < CTEXTURESMAX) ) { diff --git a/dlls/stats.cpp b/dlls/stats.cpp index cdb42d82..038e1667 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -99,9 +99,8 @@ void UpdateStats( CBasePlayer *pPlayer ) CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; while( p ) { - ItemInfo II; + ItemInfo II = {0}; - memset( &II, 0, sizeof(II) ); p->GetItemInfo( &II ); int index = pPlayer->GetAmmoIndex( II.pszAmmo1 ); diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index 6c9d72af..614bd7bb 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -518,11 +518,9 @@ const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) { int i; int minPlayers = MAX_TEAMS; - int teamCount[MAX_TEAMS]; + int teamCount[MAX_TEAMS] = {0}; 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++ ) { diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index b1ba1385..3e2ef386 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -263,9 +263,8 @@ void UTIL_PrecacheOtherWeapon( const char *szClassname ) if( pEntity ) { - ItemInfo II; + ItemInfo II = {0}; pEntity->Precache(); - memset( &II, 0, sizeof II ); if( ( (CBasePlayerItem*)pEntity )->GetItemInfo( &II ) ) { CBasePlayerItem::ItemInfoArray[II.iId] = II; @@ -279,8 +278,6 @@ void UTIL_PrecacheOtherWeapon( const char *szClassname ) { AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); } - - memset( &II, 0, sizeof II ); } } diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 2ac023a2..92377197 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -192,7 +192,7 @@ void PM_InitTextureTypes() char buffer[512]; int i, j; byte *pMemFile; - int fileSize, filePos = 0; + int fileSize, filePos; static qboolean bTextureTypeInit = false; if( bTextureTypeInit ) @@ -202,13 +202,13 @@ void PM_InitTextureTypes() 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; + memset( buffer, 0, 512 ); filePos = 0; // for each line in the file... while( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX ) ) From 156b0ae69ae0d059c8bb3ce65e5d0279548f5f33 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 2 Aug 2016 18:36:48 +0500 Subject: [PATCH 058/227] Reformat some strings yet. --- cl_dll/MOTD.cpp | 50 ++++++++++++++++++------------------- cl_dll/ammo_secondary.cpp | 4 +-- cl_dll/com_weapons.cpp | 28 +++++++++++++++++---- cl_dll/hl/hl_baseentity.cpp | 16 ++++++------ 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp index dfb587aa..4273b0bf 100644 --- a/cl_dll/MOTD.cpp +++ b/cl_dll/MOTD.cpp @@ -28,7 +28,7 @@ DECLARE_MESSAGE( m_MOTD, MOTD ) -int CHudMOTD :: Init( void ) +int CHudMOTD::Init( void ) { gHUD.AddHudElem( this ); @@ -42,13 +42,13 @@ int CHudMOTD :: Init( void ) return 1; } -int CHudMOTD :: VidInit( void ) +int CHudMOTD::VidInit( void ) { // Load sprites here return 1; } -void CHudMOTD :: Reset( void ) +void CHudMOTD::Reset( void ) { m_iFlags &= ~HUD_ACTIVE; // start out inactive m_szMOTD[0] = 0; @@ -60,7 +60,7 @@ void CHudMOTD :: Reset( void ) #define ROW_GAP 13 #define ROW_RANGE_MIN 30 #define ROW_RANGE_MAX ( ScreenHeight - 100 ) -int CHudMOTD :: Draw( float fTime ) +int CHudMOTD::Draw( float fTime ) { gHUD.m_iNoConsolePrint &= ~( 1 << 1 ); if( !m_bShow ) @@ -68,60 +68,61 @@ int CHudMOTD :: Draw( float fTime ) gHUD.m_iNoConsolePrint |= 1 << 1; bool bScroll; // find the top of where the MOTD should be drawn, so the whole thing is centered in the screen - int ypos = (ScreenHeight - LINE_HEIGHT * m_iLines)/2; // shift it up slightly + int ypos = ( ScreenHeight - LINE_HEIGHT * m_iLines ) / 2; // shift it up slightly char *ch = m_szMOTD; - int xpos = (ScreenWidth - gHUD.m_scrinfo.charWidths[ 'M' ] * m_iMaxLength) / 2; - if( xpos < 30 ) xpos = 30; - int xmax = xpos + gHUD.m_scrinfo.charWidths[ 'M' ] * m_iMaxLength; + int xpos = ( ScreenWidth - gHUD.m_scrinfo.charWidths['M'] * m_iMaxLength ) / 2; + if( xpos < 30 ) + xpos = 30; + int xmax = xpos + gHUD.m_scrinfo.charWidths['M'] * m_iMaxLength; int height = LINE_HEIGHT * m_iLines; int ypos_r=ypos; if( height > ROW_RANGE_MAX ) { ypos = ROW_RANGE_MIN + 7 + scroll; if( ypos > ROW_RANGE_MIN + 4 ) - scroll-= (ypos - ( ROW_RANGE_MIN + 4))/3.0; + scroll-= ( ypos - ( ROW_RANGE_MIN + 4 ) ) / 3.0; if( ypos + height < ROW_RANGE_MAX ) - scroll+= (ROW_RANGE_MAX - (ypos + height))/ 3.0; + scroll+= ( ROW_RANGE_MAX - ( ypos + height ) ) / 3.0; ypos_r = ROW_RANGE_MIN; height = ROW_RANGE_MAX; } int ymax = ypos + height; if( xmax > ScreenWidth - 30 ) xmax = ScreenWidth - 30; - gHUD.DrawDarkRectangle(xpos-5, ypos_r - 5, xmax - xpos+10, height + 10); - while ( *ch ) + gHUD.DrawDarkRectangle( xpos - 5, ypos_r - 5, xmax - xpos + 10, height + 10 ); + while( *ch ) { char *next_line; int line_length = 0; // count the length of the current line - for ( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) - line_length += gHUD.m_scrinfo.charWidths[ *next_line ]; + for( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) + line_length += gHUD.m_scrinfo.charWidths[*next_line]; char *top = next_line; - if ( *top == '\n' ) + if( *top == '\n' ) *top = 0; else top = NULL; // find where to start drawing the line - if( (ypos > ROW_RANGE_MIN) && (ypos + LINE_HEIGHT <= ypos_r + height) ) + if( ( ypos > ROW_RANGE_MIN ) && ( ypos + LINE_HEIGHT <= ypos_r + height ) ) gHUD.DrawHudString( xpos, ypos, xmax, ch, 255, 180, 0 ); ypos += LINE_HEIGHT; - if ( top ) // restore + if( top ) // restore *top = '\n'; ch = next_line; - if ( *ch == '\n' ) + if( *ch == '\n' ) ch++; - if ( ypos > (ScreenHeight - 20) ) + if( ypos > ( ScreenHeight - 20 ) ) break; // don't let it draw too low } return 1; } -int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) +int CHudMOTD::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) { - if ( m_iFlags & HUD_ACTIVE ) + if( m_iFlags & HUD_ACTIVE ) { Reset(); // clear the current MOTD in prep for this one } @@ -131,17 +132,16 @@ int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) int is_finished = READ_BYTE(); strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) ); - if ( is_finished ) + if( is_finished ) { int length = 0; m_iMaxLength = 0; m_iFlags |= HUD_ACTIVE; - - for ( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD + for( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD { - if ( *sz == '\n' ) + if( *sz == '\n' ) { m_iLines++; if( length > m_iMaxLength ) diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index 994350ed..148d29b7 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -35,7 +35,7 @@ int CHudAmmoSecondary::Init( void ) gHUD.AddHudElem(this); m_HUD_ammoicon = 0; - for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + for( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) m_iAmmoAmounts[i] = -1; // -1 means don't draw this value Reset(); @@ -55,7 +55,7 @@ int CHudAmmoSecondary::VidInit( void ) int CHudAmmoSecondary::Draw( float flTime ) { - if ( ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) + if( ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) return 1; // draw secondary ammo icons above normal ammo readout diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index 3a3f0a6f..4f539df9 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -268,8 +268,26 @@ stub functions for such things as precaching. So we don't have to modify weapon is compiled into both game and client .dlls. ====================== */ -int stub_PrecacheModel ( char* s ) { return 0; } -int stub_PrecacheSound ( char* s ) { return 0; } -unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } -const char *stub_NameForFunction ( unsigned long function ) { return "func"; } -void stub_SetModel ( edict_t *e, const char *m ) {} +int stub_PrecacheModel( char* s ) +{ + return 0; +} + +int stub_PrecacheSound( char* s ) +{ + return 0; +} + +unsigned short stub_PrecacheEvent( int type, const char *s ) +{ + return 0; +} + +const char *stub_NameForFunction( unsigned long function ) +{ + return "func"; +} + +void stub_SetModel( edict_t *e, const char *m ) +{ +} diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 655272d4..9a47110f 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -42,19 +42,19 @@ ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; void EMIT_SOUND_DYN( edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch ) { } // CBaseEntity Stubs -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +int CBaseEntity::TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 1; } CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } int CBaseEntity::Save( CSave &save ) { return 1; } int CBaseEntity::Restore( CRestore &restore ) { return 1; } void CBaseEntity::SetObjectCollisionBox( void ) { } -int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } -void CBaseEntity :: MakeDormant( void ) { } -int CBaseEntity :: IsDormant( void ) { return 0; } -BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity::MakeDormant( void ) { } +int CBaseEntity::IsDormant( void ) { return 0; } +BOOL CBaseEntity::IsInWorld( void ) { return TRUE; } int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } -int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } -CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +int CBaseEntity::DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity *CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } void CBaseEntity::SUB_Remove( void ) { } // CBaseDelay Stubs From b925cbd284158711a75d92ff74b1899b4b9c0e4d Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 2 Aug 2016 21:24:33 +0500 Subject: [PATCH 059/227] Oops. Fix voice. --- dlls/sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 5f0d3da3..b97eee12 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1269,6 +1269,7 @@ void SENTENCEG_Init() return; memset( buffer, 0, 512 ); + memset( szgroup, 0, 64 ); // for each line in the file... while( memfgets( pMemFile, fileSize, filePos, buffer, 511 ) != NULL ) { @@ -1321,7 +1322,6 @@ void SENTENCEG_Init() buffer[j + 1] = 0; - memset( szgroup, 0, 64 ); // if new name doesn't match previous group name, // make a new group. if( strcmp( szgroup, &( buffer[i] ) ) ) From 932d269e7488848d7755f028f3b0676846a9ee92 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 2 Aug 2016 22:24:25 +0500 Subject: [PATCH 060/227] Fix memory leak. --- dlls/gamerules.h | 2 ++ dlls/world.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dlls/gamerules.h b/dlls/gamerules.h index ef235fc1..41dec089 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -59,6 +59,8 @@ enum class CGameRules { public: + virtual ~CGameRules(); + 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). diff --git a/dlls/world.cpp b/dlls/world.cpp index ffe5e8c4..fe119919 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -462,18 +462,19 @@ void CWorld::Precache( void ) { g_pLastSpawn = NULL; #if 1 - CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec - CVAR_SET_STRING("sv_stepsize", "18"); + 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"); + CVAR_SET_STRING( "sv_gravity", "384" ); // 32ft/sec + CVAR_SET_STRING( "sv_stepsize", "24" ); #endif - CVAR_SET_STRING("room_type", "0");// clear DSP + CVAR_SET_STRING( "room_type", "0" );// clear DSP // Set up game rules if( g_pGameRules ) { delete g_pGameRules; + g_pGameRules = NULL; } g_pGameRules = InstallGameRules(); From a8b188e1d5bd5ee9003f98b32b946195ded2c9a0 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 2 Aug 2016 23:16:24 +0500 Subject: [PATCH 061/227] Fix -Wshadow. --- cl_dll/ev_hldm.cpp | 7 +++---- dlls/buttons.cpp | 2 +- dlls/gauss.cpp | 2 +- dlls/monsters.cpp | 2 +- dlls/talkmonster.cpp | 6 +++--- dlls/util.cpp | 4 ++-- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index a011ae4f..9787a839 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1048,7 +1048,6 @@ void EV_FireGauss( event_args_t *args ) if( !beam_tr.allsolid ) { vec3_t delta; - float n; // trace backwards to find exit point gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); @@ -1057,9 +1056,9 @@ void EV_FireGauss( event_args_t *args ) n = Length( delta ); - if(n < flDamage) + if( n < flDamage ) { - if(n == 0) + if( n == 0 ) n = 1; flDamage -= n; @@ -1443,7 +1442,7 @@ void EV_EgonFire( event_args_t *args ) if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. { - vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; + vec3_t vecSrc, vecEnd, angles, forward, right, up; pmtrace_t tr; cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 15a17cf2..7b050add 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -191,7 +191,7 @@ void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE if( IsTriggered( pActivator ) ) { ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING( pev->targetname ), m_iTotal ); - USE_TYPE useType = USE_TOGGLE; + useType = USE_TOGGLE; if( m_globalstate ) useType = USE_ON; SUB_UseTargets( NULL, useType, 0 ); diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index db806eb3..14aac39b 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -469,7 +469,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // 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( ); + n = ( beam_tr.vecEndPos - tr.vecEndPos ).Length(); if( n < flDamage ) { diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index 631eddd5..d034abd6 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -1074,7 +1074,7 @@ int CBaseMonster::CheckEnemy( CBaseEntity *pEnemy ) { // distance to enemy's feet vecEnemyPos.z -= pEnemy->pev->size.z; - float flDistToEnemy2 = ( vecEnemyPos - pev->origin ).Length(); + flDistToEnemy2 = ( vecEnemyPos - pev->origin ).Length(); if( flDistToEnemy2 < flDistToEnemy ) flDistToEnemy = flDistToEnemy2; } diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index a370b949..a0a52f52 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -466,12 +466,12 @@ void CTalkMonster::StartTask( Task_t *pTask ) void CTalkMonster::RunTask( Task_t *pTask ) { + edict_t *pPlayer; + 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() && @@ -517,7 +517,7 @@ void CTalkMonster::RunTask( Task_t *pTask ) case TASK_FACE_PLAYER: { // Get edict for one player - edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); + pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); if( pPlayer ) { diff --git a/dlls/util.cpp b/dlls/util.cpp index 825e5241..47eaf2f8 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1794,7 +1794,7 @@ void CSave::WriteFloat( const char *pname, const float *data, int count ) void CSave::WriteTime( const char *pname, const float *data, int count ) { int i; - Vector tmp, input; + //Vector tmp, input; BufferHeader( pname, sizeof(float) * count ); for( i = 0; i < count; i++ ) @@ -1871,7 +1871,7 @@ void CSave::WritePositionVector( const char *pname, const Vector &value ) void CSave::WritePositionVector( const char *pname, const float *value, int count ) { int i; - Vector tmp, input; + //Vector tmp, input; BufferHeader( pname, sizeof(float) * 3 * count ); for( i = 0; i < count; i++ ) From 9e262a0e14dd3f4389f4c6398c5e584950801082 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 3 Aug 2016 00:54:19 +0500 Subject: [PATCH 062/227] Include missing header. Remove duplicate structs definitions. --- pm_shared/pm_defs.h | 4 ++-- pm_shared/pm_shared.c | 33 --------------------------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index 7c04d22d..70b8369d 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -36,7 +36,7 @@ // PM_PlayerTrace results. #include "pmtrace.h" - +#include "com_model.h" #include "usercmd.h" // physent_t @@ -218,4 +218,4 @@ typedef struct playermove_s struct pmtrace_s *(*PM_TraceLineEx)( float *start, float *end, int flags, int usehulll, int (*pfnIgnore)( physent_t *pe )); struct msurface_s *(*PM_TraceSurface)( int ground, float *vstart, float *vend ); } playermove_t; -#endif//PM_DEFS_H \ No newline at end of file +#endif//PM_DEFS_H diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 92377197..a9ac380f 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -38,41 +38,8 @@ static int pm_shared_initialized = 0; #pragma warning( disable : 4305 ) -typedef enum -{ - mod_brush, - mod_sprite, - mod_alias, - mod_studio -}modtype_t; - playermove_t *pmove = NULL; -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -}dclipnode_t; - -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 hull_s -{ - dclipnode_t *clipnodes; - mplane_t *planes; - int firstclipnode; - int lastclipnode; - vec3_t clip_mins; - vec3_t clip_maxs; -} hull_t; - // Ducking time #define TIME_TO_DUCK 0.4 #define VEC_DUCK_HULL_MIN -18 From f614c7331852fed4565cd0d4572c64960e743a59 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 3 Aug 2016 02:05:15 +0500 Subject: [PATCH 063/227] Remove duplicate loop. --- cl_dll/health.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index 4a567665..d4979c35 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -125,7 +125,7 @@ int CHudHealth::MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ) vec3_t vecFrom; - for ( int i = 0; i < 3; i++ ) + for( int i = 0; i < 3; i++ ) vecFrom[i] = READ_COORD(); UpdateTiles( gHUD.m_flTime, bitsDamage ); @@ -240,8 +240,8 @@ int CHudHealth::Draw( float flTime ) void CHudHealth::CalcDamageDirection( vec3_t vecFrom ) { - vec3_t forward, right, up; - float side, front; + vec3_t forward, right, up; + float side, front; vec3_t vecOrigin, vecAngles; if( !vecFrom[0] && !vecFrom[1] && !vecFrom[2] ) @@ -376,26 +376,15 @@ int CHudHealth::DrawDamage( float flTime ) int i, r, g, b, a; DAMAGE_IMAGE *pdmg; - if (!m_bitsDamage) + if( !m_bitsDamage ) return 1; UnpackRGB( r, g, b, RGB_YELLOWISH ); - a = (int)( fabs( sin( flTime * 2 ) ) * 256.0); + a = (int)( fabs( sin( flTime * 2 ) ) * 256.0 ); ScaleColors( r, g, b, a ); - // Draw all the items - for( i = 0; i < NUM_DMG_TYPES; i++ ) - { - if (m_bitsDamage & giDmgFlags[i]) - { - pdmg = &m_dmg[i]; - SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); - SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); - } - } - // check for bits that should be expired for( i = 0; i < NUM_DMG_TYPES; i++ ) { @@ -403,6 +392,10 @@ int CHudHealth::DrawDamage( float flTime ) { pdmg = &m_dmg[i]; + // Draw all the items + SPR_Set( gHUD.GetSprite( m_HUD_dmg_bio + i ), r, g, b ); + SPR_DrawAdditive( 0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect( m_HUD_dmg_bio + i ) ); + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); if( pdmg->fExpire <= flTime // when the time has expired From d8c8c09d54b30bf8ca488922b4f85384413f1a71 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 3 Aug 2016 02:40:57 +0500 Subject: [PATCH 064/227] Oops. Fix my mistakes. --- dlls/gamerules.cpp | 2 +- dlls/gamerules.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index 059b4d61..f59788c4 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -156,7 +156,7 @@ void CGameRules::RefreshSkillData ( void ) 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 "); + gSkillData.gargantuaDmgStomp = GetSkillCvar( "sk_gargantua_dmg_stomp" ); // Hassassin gSkillData.hassassinHealth = GetSkillCvar( "sk_hassassin_health" ); diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 41dec089..6ad470d0 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -59,7 +59,7 @@ enum class CGameRules { public: - virtual ~CGameRules(); + virtual ~CGameRules(){} 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. From b2da6a4c926b8a9e593f0623284f7bf5dae167ba Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 3 Aug 2016 02:50:36 +0500 Subject: [PATCH 065/227] Move vgui files to useless/game_shared directory. --- {game_shared => useless/game_shared}/vgui_checkbutton2.cpp | 0 {game_shared => useless/game_shared}/vgui_checkbutton2.h | 0 {game_shared => useless/game_shared}/vgui_defaultinputsignal.h | 0 {game_shared => useless/game_shared}/vgui_grid.cpp | 0 {game_shared => useless/game_shared}/vgui_grid.h | 0 {game_shared => useless/game_shared}/vgui_helpers.cpp | 0 {game_shared => useless/game_shared}/vgui_helpers.h | 0 {game_shared => useless/game_shared}/vgui_listbox.cpp | 0 {game_shared => useless/game_shared}/vgui_listbox.h | 0 {game_shared => useless/game_shared}/vgui_loadtga.cpp | 0 {game_shared => useless/game_shared}/vgui_loadtga.h | 0 {game_shared => useless/game_shared}/vgui_scrollbar2.cpp | 0 {game_shared => useless/game_shared}/vgui_scrollbar2.h | 0 {game_shared => useless/game_shared}/vgui_slider2.cpp | 0 {game_shared => useless/game_shared}/vgui_slider2.h | 0 {game_shared => useless/game_shared}/voice_vgui_tweakdlg.cpp | 0 {game_shared => useless/game_shared}/voice_vgui_tweakdlg.h | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename {game_shared => useless/game_shared}/vgui_checkbutton2.cpp (100%) rename {game_shared => useless/game_shared}/vgui_checkbutton2.h (100%) rename {game_shared => useless/game_shared}/vgui_defaultinputsignal.h (100%) rename {game_shared => useless/game_shared}/vgui_grid.cpp (100%) rename {game_shared => useless/game_shared}/vgui_grid.h (100%) rename {game_shared => useless/game_shared}/vgui_helpers.cpp (100%) rename {game_shared => useless/game_shared}/vgui_helpers.h (100%) rename {game_shared => useless/game_shared}/vgui_listbox.cpp (100%) rename {game_shared => useless/game_shared}/vgui_listbox.h (100%) rename {game_shared => useless/game_shared}/vgui_loadtga.cpp (100%) rename {game_shared => useless/game_shared}/vgui_loadtga.h (100%) rename {game_shared => useless/game_shared}/vgui_scrollbar2.cpp (100%) rename {game_shared => useless/game_shared}/vgui_scrollbar2.h (100%) rename {game_shared => useless/game_shared}/vgui_slider2.cpp (100%) rename {game_shared => useless/game_shared}/vgui_slider2.h (100%) rename {game_shared => useless/game_shared}/voice_vgui_tweakdlg.cpp (100%) rename {game_shared => useless/game_shared}/voice_vgui_tweakdlg.h (100%) diff --git a/game_shared/vgui_checkbutton2.cpp b/useless/game_shared/vgui_checkbutton2.cpp similarity index 100% rename from game_shared/vgui_checkbutton2.cpp rename to useless/game_shared/vgui_checkbutton2.cpp diff --git a/game_shared/vgui_checkbutton2.h b/useless/game_shared/vgui_checkbutton2.h similarity index 100% rename from game_shared/vgui_checkbutton2.h rename to useless/game_shared/vgui_checkbutton2.h diff --git a/game_shared/vgui_defaultinputsignal.h b/useless/game_shared/vgui_defaultinputsignal.h similarity index 100% rename from game_shared/vgui_defaultinputsignal.h rename to useless/game_shared/vgui_defaultinputsignal.h diff --git a/game_shared/vgui_grid.cpp b/useless/game_shared/vgui_grid.cpp similarity index 100% rename from game_shared/vgui_grid.cpp rename to useless/game_shared/vgui_grid.cpp diff --git a/game_shared/vgui_grid.h b/useless/game_shared/vgui_grid.h similarity index 100% rename from game_shared/vgui_grid.h rename to useless/game_shared/vgui_grid.h diff --git a/game_shared/vgui_helpers.cpp b/useless/game_shared/vgui_helpers.cpp similarity index 100% rename from game_shared/vgui_helpers.cpp rename to useless/game_shared/vgui_helpers.cpp diff --git a/game_shared/vgui_helpers.h b/useless/game_shared/vgui_helpers.h similarity index 100% rename from game_shared/vgui_helpers.h rename to useless/game_shared/vgui_helpers.h diff --git a/game_shared/vgui_listbox.cpp b/useless/game_shared/vgui_listbox.cpp similarity index 100% rename from game_shared/vgui_listbox.cpp rename to useless/game_shared/vgui_listbox.cpp diff --git a/game_shared/vgui_listbox.h b/useless/game_shared/vgui_listbox.h similarity index 100% rename from game_shared/vgui_listbox.h rename to useless/game_shared/vgui_listbox.h diff --git a/game_shared/vgui_loadtga.cpp b/useless/game_shared/vgui_loadtga.cpp similarity index 100% rename from game_shared/vgui_loadtga.cpp rename to useless/game_shared/vgui_loadtga.cpp diff --git a/game_shared/vgui_loadtga.h b/useless/game_shared/vgui_loadtga.h similarity index 100% rename from game_shared/vgui_loadtga.h rename to useless/game_shared/vgui_loadtga.h diff --git a/game_shared/vgui_scrollbar2.cpp b/useless/game_shared/vgui_scrollbar2.cpp similarity index 100% rename from game_shared/vgui_scrollbar2.cpp rename to useless/game_shared/vgui_scrollbar2.cpp diff --git a/game_shared/vgui_scrollbar2.h b/useless/game_shared/vgui_scrollbar2.h similarity index 100% rename from game_shared/vgui_scrollbar2.h rename to useless/game_shared/vgui_scrollbar2.h diff --git a/game_shared/vgui_slider2.cpp b/useless/game_shared/vgui_slider2.cpp similarity index 100% rename from game_shared/vgui_slider2.cpp rename to useless/game_shared/vgui_slider2.cpp diff --git a/game_shared/vgui_slider2.h b/useless/game_shared/vgui_slider2.h similarity index 100% rename from game_shared/vgui_slider2.h rename to useless/game_shared/vgui_slider2.h diff --git a/game_shared/voice_vgui_tweakdlg.cpp b/useless/game_shared/voice_vgui_tweakdlg.cpp similarity index 100% rename from game_shared/voice_vgui_tweakdlg.cpp rename to useless/game_shared/voice_vgui_tweakdlg.cpp diff --git a/game_shared/voice_vgui_tweakdlg.h b/useless/game_shared/voice_vgui_tweakdlg.h similarity index 100% rename from game_shared/voice_vgui_tweakdlg.h rename to useless/game_shared/voice_vgui_tweakdlg.h From 95b177bf3a475ca4c0b702467f1e4514e1fde947 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 3 Aug 2016 03:00:40 +0500 Subject: [PATCH 066/227] CRLF to LF for license. --- gnu.txt | 1240 +++++++++++++++++++++++++++---------------------------- 1 file changed, 620 insertions(+), 620 deletions(-) diff --git a/gnu.txt b/gnu.txt index f718b3eb..e587591e 100644 --- a/gnu.txt +++ b/gnu.txt @@ -1,621 +1,621 @@ - 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. - + 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 \ No newline at end of file From 5bdb97c26c58ed1555eb1c45c62e3dad0e80d276 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 3 Aug 2016 21:21:37 +0000 Subject: [PATCH 067/227] Fix cl_movespeedkey multiplied twice --- cl_dll/input_xash3d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index 128d6fa4..a1b8d8c1 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -221,7 +221,7 @@ void IN_Move( float frametime, usercmd_t *cmd ) IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); if( ac_forwardmove ) cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; if( ac_sidemove ) cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; - if (in_speed.state & 1) + if( (in_speed.state & 1) && ( ac_sidemove || ac_forwardmove ) ) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; From 6c7d89ea76e35c86d068c3d04b82790088e7f4d4 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 3 Aug 2016 22:36:50 +0000 Subject: [PATCH 068/227] Fix win64 build --- cl_dll/in_defs.h | 2 ++ dlls/extdll.h | 2 ++ dlls/util.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index c48cf373..e04cc18c 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -17,7 +17,9 @@ #define ROLL 2 #ifdef _WIN32 +#define HSPRITE HSPRITE_win32 #include +#undef HSPRITE #else typedef struct point_s{ int x; diff --git a/dlls/extdll.h b/dlls/extdll.h index 659f9a0a..0f5f33c2 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -39,7 +39,9 @@ #define NOSERVICE #define NOMCX #define NOIME +#define HSPRITE HSPRITE_win32 #include "windows.h" +#undef HSPRITE #else // _WIN32 #define FALSE 0 #define TRUE (!FALSE) diff --git a/dlls/util.h b/dlls/util.h index b478b781..39e281b5 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -38,7 +38,7 @@ extern globalvars_t *gpGlobals; #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) #if !defined __amd64__ || defined(CLIENT_DLL) -#define MAKE_STRING(str) ((int)str - (int)STRING(0)) +#define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) #else #define MAKE_STRING ALLOC_STRING #endif From d4d78f76911ba6cf59ae2641d70e295794dacfd9 Mon Sep 17 00:00:00 2001 From: FreeSlave Date: Sat, 6 Aug 2016 22:25:29 +0400 Subject: [PATCH 069/227] Add README.md. Some fixes for FreeBSD. Add Makefile for client --- README.md | 27 +++++++++++++++ cl_dll/Makefile | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ dlls/Makefile | 20 ++++++----- dlls/nodes.cpp | 2 +- 4 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 README.md create mode 100644 cl_dll/Makefile diff --git a/README.md b/README.md new file mode 100644 index 00000000..1d5c0afc --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Half-Life SDK for Xash3D + +Half-Life SDK for Xash3D with some fixes. + +## How to build + +### Windows + +TODO + +### Linux + +TODO + +### OS X + +TODO + +### FreeBSD + +``` + cd dlls + gmake CXX=clang++ CC=clang + cd ../cl_dll + gmake CXX=clang++ CC=clang +``` + diff --git a/cl_dll/Makefile b/cl_dll/Makefile new file mode 100644 index 00000000..ce174dbf --- /dev/null +++ b/cl_dll/Makefile @@ -0,0 +1,89 @@ +CC=gcc +CXX=g++ +SRCS+=../dlls/crossbow.cpp +SRCS+=../dlls/crowbar.cpp +SRCS+=../dlls/egon.cpp +SRCS+=./ev_hldm.cpp +SRCS+=../dlls/gauss.cpp +SRCS+=../dlls/handgrenade.cpp +SRCS+=./hl/hl_baseentity.cpp +SRCS+=./hl/hl_events.cpp +SRCS+=./hl/hl_objects.cpp +SRCS+=./hl/hl_weapons.cpp +SRCS+=../dlls/glock.cpp +SRCS+=../dlls/hornetgun.cpp +#SRCS+=../common/interface.cpp +SRCS+=../dlls/mp5.cpp +SRCS+=../dlls/python.cpp +SRCS+=../dlls/rpg.cpp +SRCS+=../dlls/satchel.cpp +SRCS+=../dlls/shotgun.cpp +SRCS+=../dlls/squeakgrenade.cpp +SRCS+=../dlls/tripmine.cpp +#SRCS+=../game_shared/voice_banmgr.cpp +#SRCS+=../game_shared/voice_status.cpp +SRCS+=./ammo.cpp +SRCS+=./ammo_secondary.cpp +SRCS+=./ammohistory.cpp +SRCS+=./battery.cpp +SRCS+=./cdll_int.cpp +SRCS+=./com_weapons.cpp +SRCS+=./death.cpp +SRCS+=./demo.cpp +SRCS+=./entity.cpp +SRCS+=./ev_common.cpp +SRCS+=./events.cpp +SRCS+=./flashlight.cpp +SRCS+=./GameStudioModelRenderer.cpp +SRCS+=./geiger.cpp +SRCS+=./health.cpp +SRCS+=./hud.cpp +SRCS+=./hud_msg.cpp +SRCS+=./hud_redraw.cpp +#SRCS+=./hud_servers.cpp +SRCS+=./hud_spectator.cpp +SRCS+=./hud_update.cpp +SRCS+=./in_camera.cpp +SRCS+=./input.cpp +#SRCS+=./inputw32.cpp +SRCS+=./menu.cpp +SRCS+=./message.cpp +SRCS+=./overview.cpp +SRCS+=./parsemsg.cpp +SRCS_C+=../pm_shared/pm_debug.c +SRCS_C+=../pm_shared/pm_math.c +SRCS_C+=../pm_shared/pm_shared.c +SRCS+=./saytext.cpp +SRCS+=./status_icons.cpp +SRCS+=./statusbar.cpp +SRCS+=./studio_util.cpp +SRCS+=./StudioModelRenderer.cpp +SRCS+=./text_message.cpp +SRCS+=./train.cpp +SRCS+=./tri.cpp +SRCS+=./util.cpp +SRCS+=./view.cpp +SRCS+=./input_xash3d.cpp +SRCS+=./scoreboard.cpp +SRCS+=./MOTD.cpp +INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls +DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL +CFLAGS = -m32 +OBJS = $(SRCS:.cpp=.o) $(SRCS_C:.c=.o) + +LIBS=-lm + +ifeq ($(shell uname -s),Linux) + LIBS=$(LIBS) -ldl +endif + +%.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -fPIC -c $< -o $@ + +%.o : %.cpp + $(CXX) $(CFLAGS) $(INCLUDES) $(DEFINES) -fPIC -c $< -o $@ +client.so : $(OBJS) + $(CXX) $(OBJS) -o client.so -shared -Wl,--no-undefined -fPIC $(LIBS) + +clean: + $(RM) $(OBJS) diff --git a/dlls/Makefile b/dlls/Makefile index 374be650..fe84e256 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -10,6 +10,7 @@ ARCH=i386 #make sure this is the correct compiler for your system CC=gcc +CXX=g++ DLL_SRCDIR=. ENGINE_SRCDIR=../engine @@ -24,10 +25,10 @@ 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 + -DCLIENT_WEAPONS -DNO_VOICEGAMEMGR #safe optimization -CFLAGS=$(BASE_CFLAGS) -w -m486 -O1 +CFLAGS=$(BASE_CFLAGS) -m32 -w -O1 #full optimization #CFLAGS=$(BASE_CFLAGS) -w -O1 -m486 -ffast-math -funroll-loops \ @@ -46,6 +47,7 @@ SHLIBCFLAGS=-fPIC SHLIBLDFLAGS=-shared DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< +DO_CXX=$(CXX) $(CFLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< ############################################################################# # SETUP AND BUILD @@ -53,13 +55,13 @@ DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< ############################################################################# $(DLL_OBJDIR)/%.o: $(DLL_SRCDIR)/%.cpp - $(DO_CC) + $(DO_CXX) $(WPN_SHARED_OBJDIR)/%.o: $(WPN_SHARED_SRCDIR)/%.cpp - $(DO_CC) + $(DO_CXX) $(GAME_SHARED_OBJDIR)/%.o: $(GAME_SHARED_SRCDIR)/%.cpp - $(DO_CC) + $(DO_CXX) $(PM_SHARED_OBJDIR)/%.o: $(PM_SHARED_SRCDIR)/%.c $(DO_CC) @@ -161,14 +163,14 @@ OBJ = \ $(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 \ + $(DLL_OBJDIR)/glock.o \ $(PM_SHARED_OBJDIR)/pm_debug.o \ $(PM_SHARED_OBJDIR)/pm_math.o \ - $(PM_SHARED_OBJDIR)/pm_shared.o + $(PM_SHARED_OBJDIR)/pm_shared.o +# $(GAME_SHARED_OBJDIR)/voice_gamemgr.o $(DLLNAME)_$(ARCH).$(SHLIBEXT) : neat $(OBJ) - $(CC) $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(OBJ) + $(CXX) $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(OBJ) neat: -mkdir $(DLL_OBJDIR) diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index d512e54c..d72dabb3 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -40,7 +40,7 @@ CGraph WorldGraph; LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); -#if defined _LINUX && !defined _WIN32 +#if !defined _WIN32 #include #include #define CreateDirectory(p, n) mkdir(p, 0777) From 5d0b6f267e7e4c96c834fbde44399335af319343 Mon Sep 17 00:00:00 2001 From: FreeSlave Date: Sat, 6 Aug 2016 23:37:36 +0400 Subject: [PATCH 070/227] Use ?= on compilers. Remove D_LINUX from client Makefile --- cl_dll/Makefile | 6 +++--- dlls/Makefile | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cl_dll/Makefile b/cl_dll/Makefile index ce174dbf..983b61c0 100644 --- a/cl_dll/Makefile +++ b/cl_dll/Makefile @@ -1,5 +1,5 @@ -CC=gcc -CXX=g++ +CC?=gcc +CXX?=g++ SRCS+=../dlls/crossbow.cpp SRCS+=../dlls/crowbar.cpp SRCS+=../dlls/egon.cpp @@ -67,7 +67,7 @@ SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL +DEFINES = -Wno-write-strings -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL CFLAGS = -m32 OBJS = $(SRCS:.cpp=.o) $(SRCS_C:.c=.o) diff --git a/dlls/Makefile b/dlls/Makefile index fe84e256..c75731d5 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -9,8 +9,8 @@ DLLNAME=hl ARCH=i386 #make sure this is the correct compiler for your system -CC=gcc -CXX=g++ +CC?=gcc +CXX?=g++ DLL_SRCDIR=. ENGINE_SRCDIR=../engine From 42052a5057940fca7bc0abea3742d20418d58448 Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:27:59 +0600 Subject: [PATCH 071/227] CMake as optional build system --- CMakeLists.txt | 62 ++++++++++++++++++ cl_dll/CMakeLists.txt | 107 ++++++++++++++++++++++++++++++ dlls/CMakeLists.txt | 148 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cl_dll/CMakeLists.txt create mode 100644 dlls/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..5c2d6822 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,62 @@ +# +# Copyright (c) 2016 Alibek Omarov +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +cmake_minimum_required(VERSION 2.6.0) +project (HLSDK-XASH3D) + +#-------------- +# USER DEFINES \ +################\ +option(USE_VGUI "Enable VGUI1. UNDONE" OFF) +option(USE_VGUI2 "Enable VGUI2. UNDONE" OFF) +option(USE_VOICEMGR "Enable VOICE MANAGER." OFF) +option(BUILD_CLIENT "Build client dll" ON) +option(BUILD_SERVER "Build server dll" ON) + +#----------------- +# MAIN BUILD CODE \ +###################\ + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") + +# Build 32-bit Xash on 64-bit, because Xash3D not support this +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + if(MSVC) + error("UNDONE: set 32 build flags") + else() + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + endif() +endif() + +if(BUILD_CLIENT) + add_subdirectory(cl_dll) +endif() + +if(BUILD_SERVER) + add_subdirectory(dlls) +endif() + +if(NOT BUILD_SERVER AND NOT BUILD_CLIENT) + error("Nothing to build") +endif() \ No newline at end of file diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt new file mode 100644 index 00000000..7fffb29b --- /dev/null +++ b/cl_dll/CMakeLists.txt @@ -0,0 +1,107 @@ +# +# Copyright (c) 2016 Alibek Omarov +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +cmake_minimum_required(VERSION 2.6.0) +project (CLDLL) + +set (CLDLL_LIBRARY client) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + +set (CLDLL_SOURCES + ../dlls/crossbow.cpp + ../dlls/crowbar.cpp + ../dlls/egon.cpp + ../dlls/gauss.cpp + ../dlls/handgrenade.cpp + ../dlls/hornetgun.cpp + ../dlls/mp5.cpp + ../dlls/python.cpp + ../dlls/rpg.cpp + ../dlls/satchel.cpp + ../dlls/shotgun.cpp + ../dlls/squeakgrenade.cpp + ../dlls/tripmine.cpp + ../dlls/glock.cpp + ev_hldm.cpp + hl/hl_baseentity.cpp + hl/hl_events.cpp + hl/hl_objects.cpp + hl/hl_weapons.cpp + ammo.cpp + ammo_secondary.cpp + ammohistory.cpp + battery.cpp + cdll_int.cpp + com_weapons.cpp + death.cpp + demo.cpp + entity.cpp + ev_common.cpp + events.cpp + flashlight.cpp + GameStudioModelRenderer.cpp + geiger.cpp + health.cpp + hud.cpp + hud_msg.cpp + hud_redraw.cpp + hud_spectator.cpp + hud_update.cpp + in_camera.cpp + input.cpp +#SRCS+=./inputw32.cpp + menu.cpp + message.cpp + overview.cpp + parsemsg.cpp + ../pm_shared/pm_debug.c + ../pm_shared/pm_math.c + ../pm_shared/pm_shared.c + saytext.cpp + status_icons.cpp + statusbar.cpp + studio_util.cpp + StudioModelRenderer.cpp + text_message.cpp + train.cpp + tri.cpp + util.cpp + view.cpp + input_xash3d.cpp + scoreboard.cpp + MOTD.cpp) +include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public) + +if(USE_VOICEMGR) + #set(CLDLL_SOURCES + # ${CLDLL_SOURCES} + # ../game_shared/voice_banmgr.cpp + # ../game_shared/voice_status.cpp) +endif() + +add_library (${CLDLL_LIBRARY} SHARED ${CLDLL_SOURCES}) + +set_target_properties (${CLDLL_SHARED} PROPERTIES + POSITION_INDEPENDENT_CODE 1) + diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt new file mode 100644 index 00000000..cc0063b4 --- /dev/null +++ b/dlls/CMakeLists.txt @@ -0,0 +1,148 @@ +# +# Copyright (c) 2015 Pavlo Lavrenenko +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +cmake_minimum_required(VERSION 2.6.0) +project (SVDLL) + +set (SVDLL_LIBRARY server) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -fno-exceptions -w") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + +set (SVDLL_SOURCES + agrunt.cpp + airtank.cpp + aflock.cpp + animating.cpp + animation.cpp + apache.cpp + barnacle.cpp + barney.cpp + bigmomma.cpp + bloater.cpp + bmodels.cpp + bullsquid.cpp + buttons.cpp + cbase.cpp + client.cpp + combat.cpp + controller.cpp + crossbow.cpp + crowbar.cpp + defaultai.cpp + doors.cpp + effects.cpp + egon.cpp + explode.cpp + flyingmonster.cpp + func_break.cpp + func_tank.cpp + game.cpp + gamerules.cpp + gargantua.cpp + gauss.cpp + genericmonster.cpp + ggrenade.cpp + globals.cpp + glock.cpp + gman.cpp + h_ai.cpp + h_battery.cpp + h_cine.cpp + h_cycler.cpp + h_export.cpp + handgrenade.cpp + hassassin.cpp + headcrab.cpp + healthkit.cpp + hgrunt.cpp + hornet.cpp + hornetgun.cpp + houndeye.cpp + ichthyosaur.cpp + islave.cpp + items.cpp + leech.cpp + lights.cpp + maprules.cpp + monstermaker.cpp + monsters.cpp + monsterstate.cpp + mortar.cpp + mp5.cpp + multiplay_gamerules.cpp + nihilanth.cpp + nodes.cpp + osprey.cpp + pathcorner.cpp + plane.cpp + plats.cpp + player.cpp + python.cpp + rat.cpp + roach.cpp + rpg.cpp + satchel.cpp + schedule.cpp + scientist.cpp + scripted.cpp + shotgun.cpp + singleplay_gamerules.cpp + skill.cpp + sound.cpp + soundent.cpp + spectator.cpp + squadmonster.cpp + squeakgrenade.cpp + subs.cpp + talkmonster.cpp + teamplay_gamerules.cpp + tempmonster.cpp + tentacle.cpp + triggers.cpp + tripmine.cpp + turret.cpp + util.cpp + weapons.cpp + world.cpp + xen.cpp + zombie.cpp + ../pm_shared/pm_debug.c + ../pm_shared/pm_math.c + ../pm_shared/pm_shared.c +) + +include_directories (. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public) + +if(USE_VOICEMGR) + set(SVDLL_SOURCES + ${SVDLL_SOURCES} + ../game_shared/voice_gamemgr.cpp) +else() + add_definitions(-DNO_VOICEGAMEMGR) +endif() + +add_library (${SVDLL_LIBRARY} SHARED ${SVDLL_SOURCES}) + +set_target_properties (${SVDLL_SHARED} PROPERTIES + POSITION_INDEPENDENT_CODE 1) + From 6012e0e51d68949fd87cac527d24935e17630715 Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:28:33 +0600 Subject: [PATCH 072/227] Travis CI script --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..2a095c5b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: cpp +compiler: + - gcc + - clang +script: + - mkdir -p build && cd build + - export CC=gcc + - export CXX=g++ + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * + - export CC=clang + - export CXX=clang++ + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * \ No newline at end of file From 9124c049cddf9026ad28a43674be8d849e60283a Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:28:43 +0600 Subject: [PATCH 073/227] Add build/ to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e01e183d..26362f60 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ */*/*.o *.a *.framework -*.exe \ No newline at end of file +*.exe +build/ \ No newline at end of file From 8d3cce7aa29eb3ff854907e61afbba1971e16ea2 Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:37:32 +0600 Subject: [PATCH 074/227] Add GoldSource support --- cl_dll/cdll_int.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 80fdfe81..d9e1101f 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -146,6 +146,24 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) return 1; } +/* +================= +HUD_GetRect + +VGui stub +================= +*/ +int *HUD_GetRect( void ) +{ + static int extent[4]; + + extent[0] = gEngfuncs.GetWindowCenterX() - ScreenWidth / 2; + extent[1] = gEngfuncs.GetWindowCenterY() - ScreenHeight / 2; + extent[2] = gEngfuncs.GetWindowCenterX() + ScreenWidth / 2; + extent[3] = gEngfuncs.GetWindowCenterY() + ScreenHeight / 2; + + return extent; +} /* ========================== @@ -241,6 +259,7 @@ Called by engine every frame that client .dll is loaded void DLLEXPORT HUD_Frame( double time ) { + gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); } From fb4091a3144b418ab669ee1e667288b4946e2fea Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:52:29 +0600 Subject: [PATCH 075/227] Seems YAML don't like tabs --- .travis.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a095c5b..6974f6ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ language: cpp compiler: - - gcc - - clang + - gcc + - clang script: - - mkdir -p build && cd build - - export CC=gcc - - export CXX=g++ - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * - - export CC=clang - - export CXX=clang++ - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * \ No newline at end of file + - mkdir -p build && cd build + - export CC=gcc + - export CXX=g++ + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * + - export CC=clang + - export CXX=clang++ + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * + - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * \ No newline at end of file From 6f6b0000b5b552faddbf6d66f3d1baab49d84977 Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 13:59:52 +0600 Subject: [PATCH 076/227] Travis does not need manual set of compiler. Enable multilib --- .travis.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6974f6ff..d2505524 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,10 @@ language: cpp compiler: - gcc - clang +sudo: true +before_script: + - sudo apt-get install gcc-multilib g++-multilib script: - mkdir -p build && cd build - - export CC=gcc - - export CXX=g++ - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * - - export CC=clang - - export CXX=clang++ - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * \ No newline at end of file From 46218fe41521c59c8560391de09de95a35261ecc Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 14:15:10 +0600 Subject: [PATCH 077/227] [skip ci] Edit README --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d5c0afc..bb1cc675 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,20 @@ -# Half-Life SDK for Xash3D +# Half-Life SDK for Xash3D [![Build Status](https://travis-ci.org/FWGS/hlsdk-xash3d.svg)](https://travis-ci.org/FWGS/hlsdk-xash3d) -Half-Life SDK for Xash3D with some fixes. +Half-Life SDK for Xash3D & GoldSource with some fixes. ## How to build +### CMake as most universal way + +``` +mkdir build && cd build +cmake ../ +``` + +You may enable or disable some build options by -Dkey=value. All available build options are defined in CMakeLists.txt at root directory. + +See below, if CMake is not suitable for you: + ### Windows TODO @@ -25,3 +36,7 @@ TODO gmake CXX=clang++ CC=clang ``` +### Android + +Just typical `ndk-build`. + From 7fdc4ee620427d0eb73ec12fe535be9d41b9810f Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 14:22:24 +0600 Subject: [PATCH 078/227] OSX enable --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index d2505524..a00d7a21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: cpp compiler: - gcc - clang +os: + - linux + - osx sudo: true before_script: - sudo apt-get install gcc-multilib g++-multilib From 422a439b851925ac9542a8e27d3ad8ba4942c2b2 Mon Sep 17 00:00:00 2001 From: a1batross Date: Mon, 8 Aug 2016 14:25:29 +0600 Subject: [PATCH 079/227] conditional apt-get --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a00d7a21..9e165b81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ os: - osx sudo: true before_script: - - sudo apt-get install gcc-multilib g++-multilib + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install gcc-multilib g++-multilib; fi script: - mkdir -p build && cd build - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * From 2f317acc241911dcf07ff8a70a0d374d9d744ecd Mon Sep 17 00:00:00 2001 From: a1batross Date: Thu, 11 Aug 2016 12:21:14 +0600 Subject: [PATCH 080/227] Fix name in Android.mk --- dlls/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index 2a7bfdc3..7f107a12 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -115,7 +115,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ talkmonster.cpp \ teamplay_gamerules.cpp \ tentacle.cpp \ - tempentity.cpp \ + tempmonster.cpp \ triggers.cpp \ tripmine.cpp \ turret.cpp \ From 396629081c3d89cb9e89c1a69cb34b43b4fa01c5 Mon Sep 17 00:00:00 2001 From: a1batross Date: Sat, 13 Aug 2016 13:16:23 +0600 Subject: [PATCH 081/227] Fix "too quality" @nekonomicon's PR --- dlls/aflock.cpp | 2 +- dlls/crowbar.cpp | 18 +++++++++--------- dlls/doors.cpp | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index b27b8d4d..1e317632 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -160,7 +160,7 @@ void CFlockingFlyerFlock::Spawn() void CFlockingFlyerFlock::Precache() { //PRECACHE_MODEL( "models/aflock.mdl" ); - PRECACHE_MODEL( "models/boid.mdl "); + PRECACHE_MODEL( "models/boid.mdl" ); PrecacheFlockSounds(); } diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 0ec2be70..94f0066b 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -53,15 +53,15 @@ void CCrowbar::Spawn( ) 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 "); + 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" ); } diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 26fca575..bf7205ee 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1025,10 +1025,10 @@ void CMomentaryDoor::Precache( void ) switch( m_bStopSnd ) { case 0: - pev->noiseArrived = ALLOC_STRING(" common/null.wav "); + pev->noiseArrived = ALLOC_STRING( "common/null.wav" ); break; case 1: - PRECACHE_SOUND(" doors/doorstop1.wav "); + PRECACHE_SOUND( "doors/doorstop1.wav" ); pev->noiseArrived = ALLOC_STRING( "doors/doorstop1.wav" ); break; case 2: From 21317e7da39a8c74b3690ccb4713e6e6d2ed2556 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 18 Aug 2016 23:23:03 +0000 Subject: [PATCH 082/227] Fix build on some enviroments --- dlls/extdll.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dlls/extdll.h b/dlls/extdll.h index cecf62f3..cbc7ebb9 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -51,12 +51,6 @@ typedef int BOOL; #include #include #endif //_WIN32 -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif // Misc C-runtime library headers #include "stdio.h" @@ -84,4 +78,11 @@ typedef float vec_t; // needed before including progdefs.h // Shared header between the client DLL and the game DLLs #include "cdll_dll.h" +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + #endif //EXTDLL_H From 2d0ef9914ae871a9d5824e64fb727aadb2af2c97 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 30 Nov 2016 01:41:14 +0500 Subject: [PATCH 083/227] Prevent crash when pressed USE and called scripted_sequence. --- dlls/talkmonster.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index a0a52f52..d832c2cc 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -1342,6 +1342,8 @@ BOOL CTalkMonster::CanFollow( void ) { if( m_MonsterState == MONSTERSTATE_SCRIPT ) { + if( !m_pCine ) + return FALSE; if( !m_pCine->CanInterrupt() ) return FALSE; } From 74edcd09b335be7a69bafa7f964645556eccb3e9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 4 Dec 2016 00:41:40 +0500 Subject: [PATCH 084/227] Make duplicate global variables extern. --- pm_shared/pm_shared.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index a9ac380f..de855a50 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -30,8 +30,8 @@ #ifdef CLIENT_DLL // Spectator Mode int iJumpSpectator; - float vJumpOrigin[3]; - float vJumpAngles[3]; +extern float vJumpOrigin[3]; +extern float vJumpAngles[3]; #endif static int pm_shared_initialized = 0; From b7990e270d398a0ecd431cdbc37d37856e7f9e40 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Tue, 3 Jan 2017 00:49:22 +0300 Subject: [PATCH 085/227] Remove usage of MOVETYPE_COMPOUND to prevent crash --- dlls/crossbow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index d34ad25d..63d2efac 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -168,8 +168,8 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) pev->nextthink = gpGlobals->time + 10.0; // g-cont. Setup movewith feature - pev->movetype = MOVETYPE_COMPOUND; // set movewith type - pev->aiment = ENT( pOther->pev ); // set parent + //pev->movetype = MOVETYPE_COMPOUND; // set movewith type + //pev->aiment = ENT( pOther->pev ); // set parent } if( UTIL_PointContents( pev->origin ) != CONTENTS_WATER ) From 56aa9f4a9c9ab7704af9dbaf1cb72acc5623c1a5 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 4 Jan 2017 22:05:21 +0300 Subject: [PATCH 086/227] Put MOVETYPE_COMPOUND usage under if --- dlls/crossbow.cpp | 10 +++++++--- dlls/world.cpp | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 63d2efac..45fd922c 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -27,6 +27,8 @@ #define BOLT_AIR_VELOCITY 2000 #define BOLT_WATER_VELOCITY 1000 +extern BOOL gPhysicsInterfaceInitialized; + // UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS() // // OVERLOADS SOME ENTVARS: @@ -167,9 +169,11 @@ void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) pev->angles.z = RANDOM_LONG( 0, 360 ); pev->nextthink = gpGlobals->time + 10.0; - // g-cont. Setup movewith feature - //pev->movetype = MOVETYPE_COMPOUND; // set movewith type - //pev->aiment = ENT( pOther->pev ); // set parent + if (gPhysicsInterfaceInitialized) { + // g-cont. Setup movewith feature + pev->movetype = MOVETYPE_COMPOUND; // set movewith type + pev->aiment = ENT( pOther->pev ); // set parent + } } if( UTIL_PointContents( pev->origin ) != CONTENTS_WATER ) diff --git a/dlls/world.cpp b/dlls/world.cpp index fe119919..a065b5be 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -822,6 +822,8 @@ static physics_interface_t gPhysicsInterface = DispatchPhysicsEntity, }; +BOOL gPhysicsInterfaceInitialized = FALSE; + int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable ) { if( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION ) @@ -834,6 +836,6 @@ int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEn // fill engine callbacks memcpy( pFunctionTable, &gPhysicsInterface, sizeof(physics_interface_t) ); - + gPhysicsInterfaceInitialized = TRUE; return TRUE; } From 02532a478bfa63b6abdbbaf6c62e385ec8ba4eef Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 10 Jan 2017 16:09:44 +0700 Subject: [PATCH 087/227] Fix visual studio server build --- dlls/effects.cpp | 4 ++-- dlls/nodes.cpp | 2 ++ dlls/weapons.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/effects.cpp b/dlls/effects.cpp index e9492dd6..ecc04a19 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -410,7 +410,7 @@ LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ) void CTripBeam::Spawn( void ) { CLightning::Spawn(); - SetTouch( &TriggerTouch ); + SetTouch( &CLightning::TriggerTouch ); pev->solid = SOLID_TRIGGER; RelinkBeam(); } @@ -1267,7 +1267,7 @@ void CSprite::TurnOn( void ) pev->effects = 0; if( ( pev->framerate && m_maxFrame > 1.0 ) || ( pev->spawnflags & SF_SPRITE_ONCE ) ) { - SetThink( &CSprite::CSprite::AnimateThink ); + SetThink( &CSprite::AnimateThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; } diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index ed4b4033..a97b6a80 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -45,6 +45,8 @@ LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ) #include #include #define CreateDirectory(p, n) mkdir(p, 0777) +#else +#define CreateDirectory(p, n) CreateDirectoryA(p, n) #endif //========================================================= diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 3e2ef386..ff03bbfc 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1080,7 +1080,7 @@ void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) //========================================================= int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { - int iReturn; + int iReturn = 0; if( pszAmmo1() != NULL ) { From 5da21e38d23be01669fade2747425dcc8692e0e9 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 10 Jan 2017 16:45:52 +0700 Subject: [PATCH 088/227] Fix client visual studio build --- cl_dll/hud_spectator.cpp | 2 +- cl_dll/input_xash3d.cpp | 2 +- cl_dll/util.cpp | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 91e8fa37..ff6eb8ff 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -993,7 +993,7 @@ void CHudSpectator::DrawOverviewLayer() if ( hasMapImage) { i = m_MapSprite->numframes / (4*3); - i = sqrt(i); + i = sqrt(float(i)); xTiles = i*4; yTiles = i*3; } diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index 033af962..63cdfbeb 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -54,7 +54,7 @@ float rel_pitch; #define IMPULSE_DOWN 2 #define IMPULSE_UP 4 -bool CL_IsDead(); +int CL_IsDead( void ); Vector dead_viewangles(0, 0, 0); void IN_ToggleButtons( float forwardmove, float sidemove ) diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp index 52dc2f61..655bde64 100644 --- a/cl_dll/util.cpp +++ b/cl_dll/util.cpp @@ -32,6 +32,10 @@ extern vec3_t vec3_origin; +#ifdef _MSC_VER +vec3_t vec3_origin; +#endif + double sqrt( double x ); float Length( const float *v ) From a9f2549c5785582bb08e0f6d76aeba48f23c68f4 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 1 Feb 2017 14:11:06 +0000 Subject: [PATCH 089/227] Add aggregate-return hack for mingw --- pm_shared/pm_defs.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index 70b8369d..d29bff19 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -194,7 +194,12 @@ typedef struct playermove_s 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 ); +#ifdef __MINGW32__ + pmtrace_t *(*PM_PlayerTrace_real)( pmtrace_t * retvalue, float *start, float *end, int traceFlags, int ignore_pe ); + +#else pmtrace_t (*PM_PlayerTrace)( float *start, float *end, int traceFlags, int ignore_pe ); +#endif struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); long (*RandomLong)( long lLow, long lHigh ); float (*RandomFloat)( float flLow, float flHigh ); @@ -213,9 +218,32 @@ typedef struct playermove_s 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 ); +#ifdef __MINGW32__ + pmtrace_t *(*PM_PlayerTraceEx_real) (pmtrace_t *retvalue, float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe )); +#else pmtrace_t (*PM_PlayerTraceEx) (float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe )); +#endif 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 )); struct msurface_s *(*PM_TraceSurface)( int ground, float *vstart, float *vend ); } playermove_t; + +#ifdef __MINGW32__ +static pmtrace_t _pm_globalresult, _pm_globaltmp; + static inline pmtrace_t PM_PlayerTrace_wrap( float *start, float *end, int traceFlags, int ignore_pe, playermove_t *pmove ) + { + _pm_globaltmp = pmove->touchindex[MAX_PHYSENTS -1]; + pmove->PM_PlayerTrace_real( &_pm_globalresult, start, end, traceFlags, ignore_pe ); + return _pm_globalresult; + } + static inline pmtrace_t PM_PlayerTraceEx_wrap( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), playermove_t *pmove ) + { + _pm_globaltmp = pmove->touchindex[MAX_PHYSENTS -1]; + pmove->PM_PlayerTraceEx_real( &_pm_globalresult, start, end, traceFlags, pfnIgnore ); + return _pm_globalresult; + } +#define PM_PlayerTrace(a,b,c,d) touchindex[MAX_PHYSENTS -1] = PM_PlayerTrace_wrap( a, b, c, d, pmove );pmove->touchindex[MAX_PHYSENTS -1] = _pm_globaltmp +#define PM_PlayerTraceEx(a,b,c,d) touchindex[MAX_PHYSENTS -1] = PM_PlayerTraceEx_wrap( a, b, c, d, pmove );pmove->touchindex[MAX_PHYSENTS -1] = _pm_globaltmp +#endif + #endif//PM_DEFS_H From 80593d29bdde8c8afa7e1f66a44505d5dc3f0fbe Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 1 Feb 2017 14:55:40 +0000 Subject: [PATCH 090/227] Apply fixes from gravgun branch --- cl_dll/MOTD.cpp | 2 +- cl_dll/hl/hl_weapons.cpp | 2 +- cl_dll/message.cpp | 2 +- dlls/mpstubb.cpp | 2 +- dlls/stats.cpp | 2 +- engine/cdll_int.h | 8 +++++++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp index 4273b0bf..6ab3a161 100644 --- a/cl_dll/MOTD.cpp +++ b/cl_dll/MOTD.cpp @@ -130,7 +130,7 @@ int CHudMOTD::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) BEGIN_READ( pbuf, iSize ); int is_finished = READ_BYTE(); - strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) ); + strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) - 1 ); if( is_finished ) { diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 5a17e858..6d555b4c 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -288,7 +288,7 @@ Only produces random numbers to match the server ones. */ 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 ) { - float x, y, z; + float x = 0, y = 0, z; for( ULONG iShot = 1; iShot <= cShots; iShot++ ) { diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index a9c706ec..5d52d413 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -310,7 +310,7 @@ int CHudMessage::Draw( float fTime ) { int i, drawn; client_textmessage_t *pMessage; - float endTime; + float endTime = 0; drawn = 0; diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index 3cc2e5c2..703a4dba 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -74,7 +74,7 @@ void CBaseMonster::MonsterInitDead( void ) // Setup health counters, etc. BecomeDead(); - SetThink( &CorpseFallThink ); + SetThink( &CBaseMonster::CorpseFallThink ); pev->nextthink = gpGlobals->time + 0.5; } diff --git a/dlls/stats.cpp b/dlls/stats.cpp index 038e1667..9b21f792 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -15,7 +15,7 @@ #include "weapons.h" #include "soundent.h" #include "monsters.h" -#include "..\engine\shake.h" +#include "../engine/shake.h" #include "decals.h" #include "gamerules.h" diff --git a/engine/cdll_int.h b/engine/cdll_int.h index b77a174a..eaa7f4e8 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -93,6 +93,12 @@ typedef struct client_textmessage_s const char *pMessage; } client_textmessage_t; +#if __MSC_VER == 1200 +#define ulonglong_t __int64 +#else +#define ulonglong_t unsigned long long +#endif + typedef struct hud_player_info_s { char *name; @@ -106,7 +112,7 @@ typedef struct hud_player_info_s short topcolor; short bottomcolor; - unsigned long long m_nSteamID; + ulonglong_t m_nSteamID; } hud_player_info_t; typedef struct cl_enginefuncs_s From 617d75545f2ecb9b2d46cc30728dc37c9eb6d35e Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 9 Feb 2017 22:30:11 +0600 Subject: [PATCH 091/227] Fix unaligned access when built by clang --- dlls/util.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index 47eaf2f8..9be35472 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2228,22 +2228,22 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou *( (EOFFSET *)pOutputData ) = 0; break; case FIELD_VECTOR: + #ifdef __VFP_FP__ + memcpy( pOutputData, pInputData, sizeof( Vector ) ); + #else ( (float *)pOutputData )[0] = ( (float *)pInputData )[0]; ( (float *)pOutputData )[1] = ( (float *)pInputData )[1]; ( (float *)pOutputData )[2] = ( (float *)pInputData )[2]; + #endif break; case FIELD_POSITION_VECTOR: #ifdef __VFP_FP__ - float tmp; - memcpy( &tmp, (char *)pInputData + 0, 4 ); - tmp += position.x; - memcpy( (char *)pOutputData + 0, &tmp, 4 ); - memcpy( &tmp, (char *)pInputData + 4, 4 ); - tmp += position.y; - memcpy( (char *)pOutputData + 4, &tmp, 4 ); - memcpy( &tmp, (char *)pInputData + 8, 4 ); - tmp += position.z; - memcpy( (char *)pOutputData + 8, &tmp, 4 ); + { + Vector tmp; + memcpy( &tmp, pInputData, sizeof( Vector ) ); + tmp += position; + memcpy( pOutputData, &tmp, sizeof( Vector ) ); + } #else ( (float *)pOutputData )[0] = ( (float *)pInputData )[0] + position.x; ( (float *)pOutputData )[1] = ( (float *)pInputData )[1] + position.y; From 55a3ab741adf617aec3ae4968238a8697e58159d Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 9 Feb 2017 22:46:48 +0600 Subject: [PATCH 092/227] Fix build --- dlls/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index 9be35472..d1fceb0a 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2241,7 +2241,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou { Vector tmp; memcpy( &tmp, pInputData, sizeof( Vector ) ); - tmp += position; + tmp = tmp + position; memcpy( pOutputData, &tmp, sizeof( Vector ) ); } #else From e099224bc5948dd604632f1602017b99cb29cc90 Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 29 Mar 2017 19:59:50 +0000 Subject: [PATCH 093/227] Use vgui2 functions for utf-8 print --- cl_dll/MOTD.cpp | 2 +- cl_dll/cl_util.h | 2 ++ cl_dll/hud_redraw.cpp | 29 +++++++++++++++++++++++++++++ cl_dll/scoreboard.cpp | 24 ++++++++++++------------ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp index 6ab3a161..179ae4a8 100644 --- a/cl_dll/MOTD.cpp +++ b/cl_dll/MOTD.cpp @@ -103,7 +103,7 @@ int CHudMOTD::Draw( float fTime ) // find where to start drawing the line if( ( ypos > ROW_RANGE_MIN ) && ( ypos + LINE_HEIGHT <= ypos_r + height ) ) - gHUD.DrawHudString( xpos, ypos, xmax, ch, 255, 180, 0 ); + DrawUtfString( xpos, ypos, xmax, ch, 255, 180, 0 ); ypos += LINE_HEIGHT; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 84488050..54dcede0 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -115,6 +115,8 @@ inline void GetConsoleStringSize( const char *string, int *width, int *height ) gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); } +int DrawUtfString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ); + inline int ConsoleStringLen( const char *string ) { int _width = 0, _height = 0; diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index aed98455..b5314961 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -226,6 +226,35 @@ int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g return xpos; } + + +int DrawUtfString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +{ + // xash3d: reset unicode state + gEngfuncs.pfnVGUI2DrawCharacterAdditive( 0, 0, 0, 0, 0, 0, 0 ); + + // draw the string until we hit the null character or a newline character + for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int w = gHUD.m_scrinfo.charWidths['M']; + if( xpos + w > iMaxX ) + return xpos; + if( ( *szIt == '^' ) && ( *( szIt + 1 ) >= '0') && ( *( szIt + 1 ) <= '7') ) + { + szIt++; + r = colors[*szIt - '0'][0]; + g = colors[*szIt - '0'][1]; + b = colors[*szIt - '0'][2]; + if( !*(++szIt) ) + return xpos; + } + int c = (unsigned int)(unsigned char)*szIt; + xpos += gEngfuncs.pfnVGUI2DrawCharacterAdditive( xpos, ypos, c, r, g, b, 0 ); + } + + return xpos; +} + int CHud::DrawHudStringLen( char *szIt ) { int l = 0; diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 2e0722f9..3a780baf 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -146,18 +146,18 @@ int CHudScoreboard::Draw( float fTime ) FAR_RIGHT += 5; gHUD.DrawDarkRectangle( xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX ); if( !gHUD.m_Teamplay ) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); + DrawUtfString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); else - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); + DrawUtfString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "kills", 255, 140, 0 ); - gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); - gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); - gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); + DrawUtfString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); + DrawUtfString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); + DrawUtfString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); if( can_show_packetloss ) { - gHUD.DrawHudString( PL_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "pkt loss", 255, 140, 0 ); + DrawUtfString( PL_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "pkt loss", 255, 140, 0 ); } list_slot += 1.2; @@ -272,7 +272,7 @@ int CHudScoreboard::Draw( float fTime ) } // draw their name (left to right) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); + DrawUtfString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); // draw kills (right to left) xpos = KILLS_RANGE_MAX + xpos_rel; @@ -280,7 +280,7 @@ int CHudScoreboard::Draw( float fTime ) // draw divider xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + DrawUtfString( xpos, ypos, xpos + 20, "/", r, g, b ); // draw deaths xpos = DEATHS_RANGE_MAX + xpos_rel; @@ -300,7 +300,7 @@ int CHudScoreboard::Draw( float fTime ) xpos = ( ( PL_RANGE_MAX - PL_RANGE_MIN ) / 2) + PL_RANGE_MIN + xpos_rel + 25; sprintf( buf, " %d", team_info->packetloss ); - gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); + DrawUtfString( xpos, ypos, xpos+50, buf, r, g, b ); } team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again @@ -400,7 +400,7 @@ int CHudScoreboard::DrawPlayers( int xpos_rel, float list_slot, int nameoffset, } // draw their name (left to right) - gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b ); + DrawUtfString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b ); // draw kills (right to left) xpos = KILLS_RANGE_MAX + xpos_rel; @@ -408,7 +408,7 @@ int CHudScoreboard::DrawPlayers( int xpos_rel, float list_slot, int nameoffset, // draw divider xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); + DrawUtfString( xpos, ypos, xpos + 20, "/", r, g, b ); // draw deaths xpos = DEATHS_RANGE_MAX + xpos_rel; @@ -435,7 +435,7 @@ int CHudScoreboard::DrawPlayers( int xpos_rel, float list_slot, int nameoffset, xpos = ( ( PL_RANGE_MAX - PL_RANGE_MIN ) / 2 ) + PL_RANGE_MIN + xpos_rel + 25; - gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); + DrawUtfString( xpos, ypos, xpos+50, buf, r, g, b ); } pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again From 409848b80fd02893f6eb34cd97e18cd93c2ada04 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 3 Apr 2017 21:16:25 +0500 Subject: [PATCH 094/227] Do not break menuselect behavior. --- dlls/client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/client.cpp b/dlls/client.cpp index 21e5d810..5fb7c221 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -466,10 +466,10 @@ void ClientCommand( edict_t *pEntity ) edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); pPlayer->StartObserver( pev->origin, VARS( pentSpawnSpot )->angles ); } - /*else if( g_pGameRules->ClientCommand( GetClassPtr( (CBasePlayer *)pev ), pcmd ) ) + 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 if( FStrEq( pcmd, "VModEnable" ) ) { // clear 'Unknown command: VModEnable' in singleplayer From 4fbb070e7d59c8dc660f5895ba8470fe869cd49a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 4 Apr 2017 01:15:16 +0500 Subject: [PATCH 095/227] Implement cl_scoreboard_bg cvar. --- cl_dll/scoreboard.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 3a780baf..507e0415 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -26,6 +26,7 @@ #include #include +cvar_t *cl_scoreboard_bg; cvar_t *cl_showpacketloss; hud_player_info_t g_PlayerInfoList[MAX_PLAYERS + 1]; // player info from the engine extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS + 1]; // additional player info sent directly to the client dll @@ -59,6 +60,7 @@ int CHudScoreboard::Init( void ) InitHUDData(); + cl_scoreboard_bg = CVAR_CREATE( "cl_scoreboard_bg", "1", 0 ); cl_showpacketloss = CVAR_CREATE( "cl_showpacketloss", "0", FCVAR_ARCHIVE ); return 1; @@ -144,7 +146,8 @@ int CHudScoreboard::Draw( float fTime ) FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; FAR_RIGHT += 5; - gHUD.DrawDarkRectangle( xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX ); + if( cl_scoreboard_bg && cl_scoreboard_bg->value ) + gHUD.DrawDarkRectangle( xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX ); if( !gHUD.m_Teamplay ) DrawUtfString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); else From 6f8d64df898ba58f1d5c3cd6f81951f38d6f74dd Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 4 Apr 2017 01:43:21 +0500 Subject: [PATCH 096/227] Make cl_scoreboard_bg cvar archive. --- cl_dll/scoreboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index 507e0415..b20e316c 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -60,7 +60,7 @@ int CHudScoreboard::Init( void ) InitHUDData(); - cl_scoreboard_bg = CVAR_CREATE( "cl_scoreboard_bg", "1", 0 ); + cl_scoreboard_bg = CVAR_CREATE( "cl_scoreboard_bg", "1", FCVAR_ARCHIVE ); cl_showpacketloss = CVAR_CREATE( "cl_showpacketloss", "0", FCVAR_ARCHIVE ); return 1; From 8163bced2c29e22629b3c3c3541d131fed00bfdf Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 12 Apr 2017 02:02:18 +0500 Subject: [PATCH 097/227] Do not break hud_takesshots cvar behavior. --- cl_dll/hud_redraw.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index b5314961..c30df36d 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -93,6 +93,13 @@ int CHud::Redraw( float flTime, int intermission ) if( m_flTimeDelta < 0 ) m_flTimeDelta = 0; + if( !m_iIntermission && intermission ) + { + // Take a screenshot if the client's got the cvar set + if( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 ) + m_flShotTime = flTime + 1.0; // Take a screenshot in a second + } + if( m_flShotTime && m_flShotTime < flTime ) { gEngfuncs.pfnClientCmd( "snapshot\n" ); From fc276ad52f51ec128352ac680ef9cbac038e6b23 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Fri, 16 Jun 2017 19:18:24 +0500 Subject: [PATCH 098/227] Do not use -frtti flag. --- dlls/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/Android.mk b/dlls/Android.mk index 7f107a12..7fcdf581 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -16,7 +16,7 @@ endif LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \ -fno-exceptions -DNO_VOICEGAMEMGR -w -LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti +LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) LOCAL_C_INCLUDES := $(SDL_PATH)/include \ $(LOCAL_PATH)/. \ From a522ae20c3dcb7b48381205254021796db914d14 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 26 Jun 2017 05:47:19 +0500 Subject: [PATCH 099/227] Merge some changes from git version of hlsdk. --- common/const.h | 11 +- common/cvardef.h | 3 +- dlls/buttons.cpp | 6 +- dlls/cbase.h | 4 +- dlls/client.cpp | 238 ++++++++++++++++++++++++++++------- dlls/crossbow.cpp | 4 +- dlls/crowbar.cpp | 9 +- dlls/doors.cpp | 9 +- dlls/extdll.h | 2 +- dlls/game.cpp | 2 + dlls/gauss.cpp | 4 +- dlls/handgrenade.cpp | 4 +- dlls/mp5.cpp | 4 +- dlls/multiplay_gamerules.cpp | 4 +- dlls/nihilanth.cpp | 18 ++- dlls/player.cpp | 115 +++++++++++++++-- dlls/player.h | 12 ++ dlls/rpg.cpp | 4 +- dlls/satchel.cpp | 6 +- dlls/saverestore.h | 2 +- dlls/shotgun.cpp | 10 +- dlls/squeakgrenade.cpp | 2 +- dlls/subs.cpp | 8 ++ dlls/triggers.cpp | 2 +- dlls/tripmine.cpp | 2 +- dlls/util.cpp | 4 +- dlls/util.h | 2 +- dlls/weapons.cpp | 36 ++++++ dlls/weapons.h | 5 + dlls/zombie.cpp | 6 +- engine/eiface.h | 17 +-- engine/shake.h | 4 +- engine/studio.h | 10 +- pm_shared/pm_defs.h | 2 +- pm_shared/pm_materials.h | 1 + pm_shared/pm_shared.c | 24 ++-- 36 files changed, 473 insertions(+), 123 deletions(-) diff --git a/common/const.h b/common/const.h index b885e44e..d29816e6 100644 --- a/common/const.h +++ b/common/const.h @@ -110,7 +110,9 @@ #define EF_NOINTERP 32 // don't interpolate the next frame #define EF_LIGHT 64 // rocket flare glow sprite #define EF_NODRAW 128 // don't draw entity - +#define EF_NIGHTVISION 256 // player nightvision +#define EF_SNIPERLASER 512 // sniper laser effect +#define EF_FIBERCAMERA 1024 // fiber camera #define EF_NOREFLECT (1<<24) // Entity won't reflecting in mirrors @@ -531,6 +533,7 @@ #define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. #define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque #define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. +#define TEFIRE_FLAG_ADDITIVE 32 // if set, sprite is rendered non-opaque with additive #define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) // byte (entity index of player) @@ -621,8 +624,9 @@ #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 +#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network #define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). +#define CHAN_BOT 501 // channel used for bot chatter. // attenuation values #define ATTN_NONE 0 @@ -724,7 +728,8 @@ enum kRenderFxDeadPlayer, // kRenderAmt is the player index kRenderFxExplode, // Scale up really big! kRenderFxGlowShell, // Glowing Shell - kRenderFxClampMinScale // Keep this sprite from getting very small (SPRITES only!) + 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 }; typedef unsigned int func_t; diff --git a/common/cvardef.h b/common/cvardef.h index f822cc7a..c57b97a7 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -24,6 +24,7 @@ #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 { @@ -34,4 +35,4 @@ typedef struct cvar_s struct cvar_s *next; } cvar_t; -#endif//CVARDEF_H \ No newline at end of file +#endif//CVARDEF_H diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 7b050add..3027f10e 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -1045,7 +1045,11 @@ void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, US pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; UpdateAllButtons( pev->ideal_yaw, 1 ); - UpdateTarget( pev->ideal_yaw ); + + // 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 ) diff --git a/dlls/cbase.h b/dlls/cbase.h index 47ce7595..617bbab9 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -280,8 +280,8 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, char *name ) { - if( pFunction && !NAME_FOR_FUNCTION( (unsigned long)( pFunction ) ) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (unsigned long)pFunction ); + if( pFunction && !NAME_FOR_FUNCTION( (size_t)( pFunction ) ) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (size_t)pFunction ); } BASEPTR ThinkSet( BASEPTR func, char *name ) diff --git a/dlls/client.cpp b/dlls/client.cpp index 5fb7c221..74be0ea3 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -48,6 +48,8 @@ extern void CopyToBodyQue( entvars_t* pev ); extern int giPrecacheGrunt; extern int gmsgSayText; +extern cvar_t allow_spectators; + extern int g_teamplay; void LinkUserMessages( void ); @@ -204,6 +206,97 @@ void ClientPutInServer( edict_t *pEntity ) #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; #endif + +//----------------------------------------------------------------------------- +// Purpose: determine if a uchar32 represents a valid Unicode code point +//----------------------------------------------------------------------------- +bool Q_IsValidUChar32( unsigned int 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 < 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_, unsigned int &uValueOut, bool &bErrorOut ) +{ + const unsigned char *pUTF8 = (const unsigned char*)pUTF8_; + + int nBytes = 1; + unsigned int uValue = pUTF8[0]; + unsigned int 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 +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 && (unsigned char)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 ) + { + uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (unsigned char)( 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 ) + { + unsigned int 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 @@ -265,20 +358,13 @@ void Host_Say( edict_t *pEntity, int teamonly ) p[strlen( p ) - 1] = 0; } - // make sure the text has content - for( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if( !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if( pc != NULL ) + if( !p || !p[0] || !Q_UnicodeValidate ( p ) ) return; // no character found, so say nothing // turn on color set 2 (color on, no sound) - if( teamonly ) + 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 ) ); @@ -313,9 +399,14 @@ void Host_Say( edict_t *pEntity, int teamonly ) if( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) continue; #endif - if( teamonly && g_pGameRules->PlayerRelationship( client, CBaseEntity::Instance( pEntity ) ) != GR_TEAMMATE ) + 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 ); @@ -459,12 +550,40 @@ void ClientCommand( edict_t *pEntity ) { GetClassPtr( (CBasePlayer *)pev )->SelectLastItem(); } - else if( FStrEq( pcmd, "spectate" ) && ( pev->flags & FL_PROXY ) ) // added for proxy support + else if( FStrEq( pcmd, "spectate" ) // clients wants to become a spectator { - CBasePlayer * pPlayer = GetClassPtr( (CBasePlayer *)pev ); + // 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 ); + 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 ) ) { @@ -524,12 +643,15 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) // Set the name g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pEntity ), infobuffer, "name", sName ); - char text[256]; - snprintf( text, 256, "* %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(); + if( gpGlobals->maxClients > 1 ) + { + char text[256]; + snprintf( text, 256, "* %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 ) @@ -983,7 +1105,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h 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 ) ) + if( ( ent->v.effects & EF_NODRAW ) && ( ent != host ) ) return 0; // Ignore ents without valid / visible models @@ -1553,41 +1675,67 @@ engine sets cd to 0 before calling. */ void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) { - cd->flags = ent->v.flags; - cd->health = ent->v.health; + if( !ent || !ent->pvPrivateData ) + return; + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = (CBasePlayer *)( CBasePlayer::Instance( pev ) ); + entvars_t *pevOrg = NULL; - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + // 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 = (CBasePlayer *)(CBasePlayer::Instance( pev ) ); + } + } - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; + 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 = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; + cd->origin = pev->origin; + cd->velocity = pev->velocity; + cd->view_ofs = pev->view_ofs; + cd->punchangle = pev->punchangle; - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; + 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 = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; + cd->maxspeed = pev->maxspeed; + cd->fov = pev->fov; + cd->weaponanim = pev->weaponanim; - cd->pushmsec = ent->v.pushmsec; + 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 ) { - entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); - if( pl ) { cd->m_flNextAttack = pl->m_flNextAttack; diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 45fd922c..7a4686e7 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -353,7 +353,7 @@ void CCrossbow::PrimaryAttack( void ) // this function only gets called in multiplayer void CCrossbow::FireSniperBolt() { - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); if( m_iClip == 0 ) { @@ -451,7 +451,7 @@ void CCrossbow::FireBolt() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 94f0066b..80a18d65 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -27,7 +27,7 @@ LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ) -enum gauss_e +enum crowbar_e { CROWBAR_IDLE = 0, CROWBAR_DRAW, @@ -40,8 +40,7 @@ enum gauss_e CROWBAR_ATTACK3HIT }; - -void CCrowbar::Spawn( ) +void CCrowbar::Spawn() { Precache(); m_iId = WEAPON_CROWBAR; @@ -191,7 +190,7 @@ int CCrowbar::Swing( int fFirst ) if( fFirst ) { // miss - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); @@ -297,7 +296,7 @@ int CCrowbar::Swing( int fFirst ) m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; #endif - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index bf7205ee..bdc82f06 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1100,19 +1100,22 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP Vector move = m_vecPosition1 + ( value * ( m_vecPosition2 - m_vecPosition1 ) ); Vector delta = move - pev->origin; - float speed = delta.Length() * 10; + //float speed = delta.Length() * 10; + float speed = delta.Length() / 0.1; // move there in 0.1 sec if( speed != 0 ) { // 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 + // 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; LinearMove( move, speed ); SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); } - } void CMomentaryDoor::MomentaryMoveDone( void ) diff --git a/dlls/extdll.h b/dlls/extdll.h index cbc7ebb9..58349e32 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -44,7 +44,7 @@ #else // _WIN32 #define FALSE 0 #define TRUE (!FALSE) -typedef unsigned long ULONG; +typedef unsigned int ULONG; typedef unsigned char BYTE; typedef int BOOL; #define MAX_PATH PATH_MAX diff --git a/dlls/game.cpp b/dlls/game.cpp index 3aec1810..fb247903 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -39,6 +39,8 @@ 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", FCVAR_SERVER }; // 0 prevents players from being spectators + cvar_t mp_chattime = { "mp_chattime","10", FCVAR_SERVER }; // Engine Cvars diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 14aac39b..10149202 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -145,7 +145,7 @@ void CGauss::PrimaryAttack() if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -183,7 +183,7 @@ void CGauss::SecondaryAttack() PlayEmptySound(); } - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); return; } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 063b2886..96119b6b 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -170,7 +170,7 @@ void CHandGrenade::WeaponIdle( void ) m_flReleaseThrow = 0; m_flStartThrow = 0; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; @@ -180,7 +180,7 @@ void CHandGrenade::WeaponIdle( void ) // 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 = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing + m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );// ensure that the animation can finish playing } return; } diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 7d05d5e1..7131f888 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -177,7 +177,7 @@ void CMP5::PrimaryAttack() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.1 ); if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; @@ -227,7 +227,7 @@ void CMP5::SecondaryAttack( void ) #endif PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; + m_flNextPrimaryAttack = GetNextAttackDelay( 1 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 929c2bf6..ebef51de 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -92,7 +92,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() if( IS_DEDICATED_SERVER() ) { // dedicated server - char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + /*char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); if( servercfgfile && servercfgfile[0] ) { @@ -102,6 +102,8 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() sprintf( szCommand, "exec %s\n", servercfgfile ); SERVER_COMMAND( szCommand ); } + */ + // this code has been moved into engine, to only run server.cfg once } else { diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 58317b3c..ba1c6192 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -1185,8 +1185,22 @@ void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ case USE_OFF: { CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - if( pTouch && m_hEnemy != NULL ) - pTouch->Touch( m_hEnemy ); + if( pTouch ) + { + if( m_hEnemy != NULL ) + { + 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: diff --git a/dlls/player.cpp b/dlls/player.cpp index 2f097072..7d7363b5 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -34,6 +34,7 @@ #include "decals.h" #include "gamerules.h" #include "game.h" +#include "pm_shared.h" #include "hltv.h" // #define DUCKFIX @@ -201,7 +202,8 @@ void LinkUserMessages( void ) gmsgDamage = REG_USER_MSG( "Damage", 12 ); gmsgBattery = REG_USER_MSG( "Battery", 2); gmsgTrain = REG_USER_MSG( "Train", 1 ); - gmsgHudText = REG_USER_MSG( "HudText", -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 ); @@ -785,6 +787,12 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) m_pLastItem = NULL; + if( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + int i; CBasePlayerItem *pPendingItem; for( i = 0; i < MAX_ITEM_TYPES; i++ ) @@ -1297,6 +1305,9 @@ void CBasePlayer::PlayerDeathThink( void ) 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; @@ -1345,7 +1356,9 @@ void CBasePlayer::StartDeathCam( void ) } CopyToBodyQue( pev ); - StartObserver( pSpot->v.origin, pSpot->v.v_angle ); + + UTIL_SetOrigin( pev, pSpot->v.origin ); + pev->angles = pev->v_angle = pSpot->v.v_angle; } else { @@ -1353,23 +1366,89 @@ void CBasePlayer::StartDeathCam( void ) TraceResult tr; CopyToBodyQue( pev ); UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; + + 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 ) { - m_afPhysicsFlags |= PFLAG_OBSERVER; + // 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 != NULL ) + { + 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; - pev->modelindex = 0; + 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 ); } // @@ -1379,6 +1458,9 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) void CBasePlayer::PlayerUse( void ) { + if( IsObserver() ) + return; + // Was use pressed or released? if( !( ( pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE ) ) return; @@ -1747,6 +1829,16 @@ void CBasePlayer::PreThink( void ) CheckSuitUpdate(); + // Observer Button Handling + if( IsObserver() ) + { + Observer_HandleButtons(); + Observer_CheckTarget(); + Observer_CheckProperties(); + pev->impulse = 0; + return; + } + if( pev->deadflag >= DEAD_DYING ) { PlayerDeathThink(); @@ -3767,6 +3859,9 @@ void CBasePlayer::UpdateClientData( void ) g_pGameRules->InitHUD( this ); m_fGameHUDInitialized = TRUE; + + m_iObserverLastMode = OBS_ROAMING; + if( g_pGameRules->IsMultiplayer() ) { FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); @@ -3807,7 +3902,10 @@ void CBasePlayer::UpdateClientData( void ) if( pev->health != m_iClientHealth ) { - int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent +#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 ); @@ -4336,7 +4434,8 @@ void CBasePlayer::DropPlayerItem( char *pszItemName ) // item we want to drop and hit a BREAK; pWeapon is the item. if( pWeapon ) { - g_pGameRules->GetNextBestWeapon( this, 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 ); diff --git a/dlls/player.h b/dlls/player.h index e75787ee..cb2bddf8 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -86,6 +86,18 @@ enum sbar_data 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 diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 1fec5cf1..95c9132a 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -297,7 +297,7 @@ void CRpg::Reload( void ) // 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 = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); if( m_cActiveRockets && m_fSpotActive ) { @@ -463,7 +463,7 @@ void CRpg::PrimaryAttack() m_iClip--; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } else diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 48ec5b9a..05d1fc8c 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -354,7 +354,7 @@ void CSatchel::PrimaryAttack() } m_chargeReady = 2; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; break; @@ -401,7 +401,7 @@ void CSatchel::Throw( void ) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; } } @@ -442,7 +442,7 @@ void CSatchel::WeaponIdle( void ) // use tripmine animations strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_chargeReady = 0; break; diff --git a/dlls/saverestore.h b/dlls/saverestore.h index f76613e8..a9ad2c54 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -59,7 +59,7 @@ public: 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, const int *value, int count ); // Save a function pointer + 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 ); diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 8c96e99c..595561e2 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -119,7 +119,7 @@ void CShotgun::PrimaryAttack() if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -172,7 +172,7 @@ void CShotgun::PrimaryAttack() if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.5; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; @@ -187,7 +187,7 @@ void CShotgun::SecondaryAttack( void ) if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -243,7 +243,7 @@ void CShotgun::SecondaryAttack( void ) if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.95; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; @@ -269,7 +269,7 @@ void CShotgun::Reload( void ) m_fInSpecialReload = 1; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; return; } diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 22200b74..30ddda62 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -533,7 +533,7 @@ void CSqueak::PrimaryAttack() m_fJustThrown = 1; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; } } diff --git a/dlls/subs.cpp b/dlls/subs.cpp index bc7baf18..5ebe757b 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -415,6 +415,14 @@ 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; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index d7f9483c..958f899f 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -688,7 +688,7 @@ void PlayCDTrack( int iTrack ) if( iTrack == -1 ) { - CLIENT_COMMAND( pClient, "cd pause\n" ); + CLIENT_COMMAND( pClient, "cd stop\n" ); } else { diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index f04d906a..e2ed0817 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -470,7 +470,7 @@ void CTripmine::PrimaryAttack( void ) }*/ - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } diff --git a/dlls/util.cpp b/dlls/util.cpp index d1fceb0a..4fc0d51a 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1886,7 +1886,7 @@ void CSave::WritePositionVector( const char *pname, const float *value, int coun } } -void CSave::WriteFunction( const char *pname, const int *data, int count ) +void CSave::WriteFunction( const char *pname, void **data, int count ) { const char *functionName; @@ -2042,7 +2042,7 @@ int CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFi WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); break; case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + WriteFunction( pTest->fieldName, (void **)pOutputData, pTest->fieldSize ); break; default: ALERT( at_error, "Bad field type\n" ); diff --git a/dlls/util.h b/dlls/util.h index e8aee878..f8ae0b6a 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -37,7 +37,7 @@ extern globalvars_t *gpGlobals; #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) #if !defined __amd64__ || defined(CLIENT_DLL) -#define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) +#define MAKE_STRING(str) ((size_t)str - (size_t)STRING(0)) #else #define MAKE_STRING ALLOC_STRING #endif diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ff03bbfc..ee2a8547 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -612,6 +612,11 @@ void CBasePlayerWeapon::ItemPostFrame( void ) 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()] ) @@ -943,6 +948,7 @@ BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, i m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_flLastFireTime = 0.0f; return TRUE; } @@ -1130,6 +1136,36 @@ void CBasePlayerWeapon::RetireWeapon( void ) 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: //********************************************************* diff --git a/dlls/weapons.h b/dlls/weapons.h index 5112254a..3e6fc5ce 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -331,6 +331,7 @@ public: void PrintState( void ); virtual CBasePlayerItem *GetWeaponPtr( void ) { return (CBasePlayerItem *)this; }; + float GetNextAttackDelay( float delay ); float m_flPumpTime; int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns @@ -345,6 +346,10 @@ public: int m_fInReload; // Are we in the middle of a reload; int m_iDefaultAmmo;// how much ammo you get when you pick up this weapon as placed by a level designer. + + // hle time creep vars + float m_flPrevPrimaryAttack; + float m_flLastFireTime; }; class CBasePlayerAmmo : public CBaseEntity diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 7fe416c7..b20293c1 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -169,13 +169,15 @@ void CZombie::IdleSound( void ) int pitch = 95 + RANDOM_LONG( 0, 9 ); // 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 ) ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) -1 )], 1.0, ATTN_NORM, 0, pitch ); } void CZombie::AttackSound( void ) { + int pitch = 95 + RANDOM_LONG( 0, 9 ); + // 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 ) ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); } //========================================================= diff --git a/engine/eiface.h b/engine/eiface.h index 903451f5..3419e5bd 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -57,7 +57,8 @@ typedef enum { 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, // 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 @@ -88,7 +89,7 @@ typedef struct int fPlayTrack; } CDStatus; -typedef unsigned long CRC32_t; +typedef unsigned int CRC32_t; // Engine hands this to DLLs for functionality callbacks typedef struct enginefuncs_s @@ -156,7 +157,7 @@ typedef struct enginefuncs_s void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); - void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); + void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, int cb ); void* (*pfnPvEntPrivateData)( edict_t *pEdict ); void (*pfnFreeEntPrivateData)( edict_t *pEdict ); const char *(*pfnSzFromIndex)( int iString ); @@ -171,8 +172,8 @@ typedef struct enginefuncs_s int (*pfnRegUserMsg)( const char *pszName, int iSize ); void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); - unsigned long (*pfnFunctionFromName)( const char *pName ); - const char *(*pfnNameForFunction)( unsigned long function ); + unsigned int (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( unsigned int function ); void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients void (*pfnServerPrint)( const char *szMsg ); const char *(*pfnCmd_Args)( void ); // these 3 added @@ -183,7 +184,7 @@ typedef struct enginefuncs_s void (*pfnCRC32_ProcessBuffer)( CRC32_t *pulCRC, void *p, int len ); void (*pfnCRC32_ProcessByte)( CRC32_t *pulCRC, unsigned char ch ); CRC32_t (*pfnCRC32_Final)( CRC32_t pulCRC ); - long (*pfnRandomLong)( long lLow, long lHigh ); + int (*pfnRandomLong)( int lLow, int lHigh ); float (*pfnRandomFloat)( float flLow, float flHigh ); void (*pfnSetView)( const edict_t *pClient, const edict_t *pViewent ); float (*pfnTime)( void ); @@ -276,7 +277,7 @@ typedef struct KeyValueData_s char *szClassName; // in: entity classname char *szKeyName; // in: name of key char *szValue; // in: value of key - long fHandled; // out: DLL sets to true if key-value pair was understood + int fHandled; // out: DLL sets to true if key-value pair was understood } KeyValueData; @@ -354,7 +355,7 @@ typedef enum _fieldtypes FIELD_TYPECOUNT // MUST BE LAST } FIELDTYPE; -#ifndef offsetof +#if !defined(offsetof) && !defined(GNUC) #define offsetof(s,m) (size_t)&(((s *)0)->m) #endif diff --git a/engine/shake.h b/engine/shake.h index c644a476..b2e88a33 100644 --- a/engine/shake.h +++ b/engine/shake.h @@ -36,7 +36,7 @@ extern int gmsgFade; #define FFADE_OUT 0x0001 // Fade out (not in) #define FFADE_MODULATE 0x0002 // Modulate (don't blend) #define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received - +#define FFADE_LONGFADE 0x0008 // used to indicate the fade can be longer than 16 seconds (added for czero) // This structure is sent over the net to describe a screen fade event typedef struct @@ -47,4 +47,4 @@ typedef struct byte r, g, b, a; // fade to color ( max alpha ) } ScreenFade; -#endif // SHAKE_H \ No newline at end of file +#endif // SHAKE_H diff --git a/engine/studio.h b/engine/studio.h index b5b709bb..cd572419 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -33,14 +33,14 @@ Studio models are position independent, so the cache manager can move them. // studio limits #define MAXSTUDIOTRIANGLES 32768 // max triangles per model #define MAXSTUDIOVERTS 4096 // max vertices per submodel -#define MAXSTUDIOSEQUENCES 256 // total animation sequences +#define MAXSTUDIOSEQUENCES 2048 // total animation sequences #define MAXSTUDIOSKINS 256 // 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 // body parts per submodel #define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) -#define MAXSTUDIOANIMATIONS 512 // max frames per sequence +#define MAXSTUDIOANIMATIONS 2048 // max frames per sequence #define MAXSTUDIOMESHES 256 // max textures per model #define MAXSTUDIOEVENTS 1024 // events per model #define MAXSTUDIOPIVOTS 256 // pivot points @@ -214,10 +214,8 @@ typedef struct { char label[32]; // textual name char name[64]; // file name - cache_user_t cache; // cache index pointer -#ifndef __amd64 - int data; // hack for group 0 -#endif + int unused1; // // was "cache" - index pointer + int unused2; // was "data" - hack for group 0 } mstudioseqgroup_t; // sequence descriptions diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index d29bff19..cd17ce54 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -201,7 +201,7 @@ typedef struct playermove_s pmtrace_t (*PM_PlayerTrace)( float *start, float *end, int traceFlags, int ignore_pe ); #endif struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); - long (*RandomLong)( long lLow, long lHigh ); + int (*RandomLong)( int lLow, int 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 ); diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index cd1051d2..e625b4fc 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -28,4 +28,5 @@ #define CHAR_TEX_COMPUTER 'P' #define CHAR_TEX_GLASS 'Y' #define CHAR_TEX_FLESH 'F' +#define CHAR_TEX_SNOW 'N' #endif//PM_MATERIALS_H diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index de855a50..7a1fb966 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -87,6 +87,8 @@ playermove_t *pmove = NULL; #define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump +#define PLAYER_DUCKING_MULTIPLIER 0.333 + // double to float warning #pragma warning(disable : 4244) #define max(a, b) (((a) > (b)) ? (a) : (b)) @@ -2017,9 +2019,9 @@ void PM_Duck( void ) if( pmove->flags & FL_DUCKING ) { - pmove->cmd.forwardmove *= 0.333; - pmove->cmd.sidemove *= 0.333; - pmove->cmd.upmove *= 0.333; + 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 ) ) @@ -2110,16 +2112,24 @@ void PM_LadderMove( physent_t *pLadder ) { 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 -= MAX_CLIMB_SPEED; + forward -= flSpeed; if( pmove->cmd.buttons & IN_FORWARD ) - forward += MAX_CLIMB_SPEED; + forward += flSpeed; if( pmove->cmd.buttons & IN_MOVELEFT ) - right -= MAX_CLIMB_SPEED; + right -= flSpeed; if( pmove->cmd.buttons & IN_MOVERIGHT ) - right += MAX_CLIMB_SPEED; + right += flSpeed; if( pmove->cmd.buttons & IN_JUMP ) { From ecaba0de22483417add665dfbd47271ed058ff10 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 26 Jun 2017 07:06:27 +0500 Subject: [PATCH 100/227] Upload missing file. Fix build. --- cl_dll/com_weapons.cpp | 2 +- cl_dll/com_weapons.h | 2 +- cl_dll/hl/hl_baseentity.cpp | 1 + cl_dll/hl/hl_weapons.cpp | 21 --- dlls/Android.mk | 1 + dlls/CMakeLists.txt | 1 + dlls/Makefile | 1 + dlls/observer.cpp | 268 ++++++++++++++++++++++++++++++++++++ engine/cdll_int.h | 4 +- engine/menu_int.h | 4 +- 10 files changed, 278 insertions(+), 27 deletions(-) create mode 100644 dlls/observer.cpp diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index 4f539df9..cc693b88 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -283,7 +283,7 @@ unsigned short stub_PrecacheEvent( int type, const char *s ) return 0; } -const char *stub_NameForFunction( unsigned long function ) +const char *stub_NameForFunction( unsigned int function ) { return "func"; } diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index 7e1fdd77..4dd75203 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -34,7 +34,7 @@ void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); int stub_PrecacheModel( char* s ); int stub_PrecacheSound( char* s ); unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction( unsigned long function ); +const char *stub_NameForFunction( unsigned int function ); void stub_SetModel( struct edict_s *e, const char *m ); extern cvar_t *cl_lw; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 9a47110f..fc306838 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -314,6 +314,7 @@ int CBasePlayerItem::Restore( class CRestore & ) { return 1; } int CBasePlayerItem::Save( class CSave & ) { return 1; } int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +float CBasePlayerWeapon::GetNextAttackDelay( float flTime ) { return flTime; } void CBasePlayerItem::SetObjectCollisionBox( void ) { } void CBasePlayerItem::FallInit( void ) { } void CBasePlayerItem::FallThink( void ) { } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 6d555b4c..8c6909e3 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -560,27 +560,6 @@ void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float lif gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); } -/* -===================== -CBasePlayerWeapon::PrintState - -For debugging, print out state variables to log file -===================== -*/ -void CBasePlayerWeapon::PrintState( void ) -{ - COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); - COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); - COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time ); - COM_Log( "c:\\hl.log", "%i ", m_iClip ); -} - -int RandomLong( int a, int b ) -{ - return gEngfuncs.pfnRandomLong( a, b ); -} - /* ===================== HUD_InitClientWeapons diff --git a/dlls/Android.mk b/dlls/Android.mk index 7fcdf581..b160c424 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -90,6 +90,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ multiplay_gamerules.cpp \ nihilanth.cpp \ nodes.cpp \ + observer.cpp \ osprey.cpp \ pathcorner.cpp \ plane.cpp \ diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index cc0063b4..e0b6a8b3 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -92,6 +92,7 @@ set (SVDLL_SOURCES multiplay_gamerules.cpp nihilanth.cpp nodes.cpp + observer.cpp osprey.cpp pathcorner.cpp plane.cpp diff --git a/dlls/Makefile b/dlls/Makefile index c75731d5..9c3a84f2 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -129,6 +129,7 @@ OBJ = \ $(DLL_OBJDIR)/multiplay_gamerules.o \ $(DLL_OBJDIR)/nihilanth.o \ $(DLL_OBJDIR)/nodes.o \ + $(DLL_OBJDIR)/observer.cpp \^M $(DLL_OBJDIR)/osprey.o \ $(DLL_OBJDIR)/pathcorner.o \ $(DLL_OBJDIR)/plane.o \ diff --git a/dlls/observer.cpp b/dlls/observer.cpp new file mode 100644 index 00000000..0eda7490 --- /dev/null +++ b/dlls/observer.cpp @@ -0,0 +1,268 @@ +//=========== (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 == NULL ) + { + Observer_FindNextPlayer( false ); + + if( m_hObserverTarget == NULL ) + { + // 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 != NULL ) + { + 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 != NULL ) + { + CBaseEntity *pEnt = m_hObserverTarget; + + if( ( pEnt == this ) || ( pEnt == NULL ) ) + m_hObserverTarget = NULL; + else if( ( (CBasePlayer*)pEnt )->IsObserver() || ( pEnt->pev->effects & EF_NODRAW ) ) + m_hObserverTarget = NULL; + } + + // set spectator mode + pev->iuser1 = iMode; + + // if we are not roaming, we need a valid target to track + if( ( iMode != OBS_ROAMING ) && ( m_hObserverTarget == NULL ) ) + { + Observer_FindNextPlayer( false ); + + // if we didn't find a valid target switch to roaming + if( m_hObserverTarget == NULL ) + { + 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/engine/cdll_int.h b/engine/cdll_int.h index eaa7f4e8..a0dc59c2 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -211,7 +211,7 @@ typedef struct cl_enginefuncs_s void (*pfnPlaybackEvent)( 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 ); void (*pfnWeaponAnim)( int iAnim, int body ); float (*pfnRandomFloat)( float flLow, float flHigh ); - long (*pfnRandomLong)( long lLow, long lHigh ); + int (*pfnRandomLong)( int lLow, int lHigh ); void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); int (*Con_IsVisible) (); const char *(*pfnGetGameDirectory)( void ); @@ -311,4 +311,4 @@ typedef struct cl_enginefuncs_s } #endif -#endif//CDLL_INT_H \ No newline at end of file +#endif//CDLL_INT_H diff --git a/engine/menu_int.h b/engine/menu_int.h index 53b0725a..69c10ce4 100644 --- a/engine/menu_int.h +++ b/engine/menu_int.h @@ -155,7 +155,7 @@ typedef struct ui_enginefuncs_s // menu interface is freezed at version 0.75 // new functions starts here float (*pfnRandomFloat)( float flLow, float flHigh ); - long (*pfnRandomLong)( long lLow, long lHigh ); + int (*pfnRandomLong)( int lLow, int lHigh ); void (*pfnSetCursor)( void *hCursor ); // change cursor int (*pfnIsMapValid)( char *filename ); @@ -185,4 +185,4 @@ typedef struct typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); -#endif//MENU_INT_H \ No newline at end of file +#endif//MENU_INT_H From d217780789a2ca207bde3e8f50f7ec142f274b92 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 26 Jun 2017 07:41:01 +0500 Subject: [PATCH 101/227] Try fix build again. --- dlls/client.cpp | 3 ++- dlls/util.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/client.cpp b/dlls/client.cpp index 74be0ea3..72538b02 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -38,6 +38,7 @@ #include "weaponinfo.h" #include "usercmd.h" #include "netadr.h" +#include "pm_shared.h" extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; extern DLL_GLOBAL BOOL g_fGameOver; @@ -550,7 +551,7 @@ void ClientCommand( edict_t *pEntity ) { GetClassPtr( (CBasePlayer *)pev )->SelectLastItem(); } - else if( FStrEq( pcmd, "spectate" ) // clients wants to become a spectator + 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 ) diff --git a/dlls/util.cpp b/dlls/util.cpp index 4fc0d51a..9c7d9803 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1890,7 +1890,7 @@ void CSave::WriteFunction( const char *pname, void **data, int count ) { const char *functionName; - functionName = NAME_FOR_FUNCTION( *data ); + functionName = NAME_FOR_FUNCTION( (unsigned int)(size_t)*data ); if( functionName ) BufferField( pname, strlen( functionName ) + 1, functionName ); else From 2faa732aa1d3fa90937c0aac01e82cb836e2f34c Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 29 Jun 2017 18:56:03 +0500 Subject: [PATCH 102/227] Apply some @AlliedModders's patches. --- cl_dll/ammo.cpp | 4 +-- cl_dll/com_weapons.cpp | 8 ++--- cl_dll/com_weapons.h | 8 ++--- cl_dll/death.cpp | 17 +++++----- cl_dll/entity.cpp | 16 ++++----- cl_dll/ev_hldm.cpp | 30 ++++++++-------- cl_dll/geiger.cpp | 56 +++++++++++++++--------------- cl_dll/hl/hl_baseentity.cpp | 12 +++---- cl_dll/hl/hl_weapons.cpp | 8 ++--- cl_dll/hud.h | 12 +++---- cl_dll/hud_redraw.cpp | 10 +++--- cl_dll/message.cpp | 6 ++-- cl_dll/status_icons.cpp | 4 +-- cl_dll/text_message.cpp | 20 +++++------ cl_dll/view.cpp | 8 ++--- common/cvardef.h | 4 +-- dlls/activity.h | 2 +- dlls/activitymap.h | 2 +- dlls/aflock.cpp | 1 - dlls/agrunt.cpp | 6 ++-- dlls/animation.cpp | 6 ++-- dlls/apache.cpp | 5 ++- dlls/barnacle.cpp | 6 ++-- dlls/barney.cpp | 16 ++++----- dlls/basemonster.h | 4 +-- dlls/bigmomma.cpp | 7 ++-- dlls/bmodels.cpp | 4 +-- dlls/bullsquid.cpp | 12 +++---- dlls/buttons.cpp | 20 +++++------ dlls/cbase.cpp | 4 +-- dlls/cbase.h | 7 ++-- dlls/client.cpp | 26 ++++++-------- dlls/combat.cpp | 19 ++++++----- dlls/controller.cpp | 9 +++-- dlls/crossbow.cpp | 3 +- dlls/crowbar.cpp | 4 +-- dlls/decals.h | 2 +- dlls/doors.cpp | 24 ++++++------- dlls/effects.cpp | 18 +++++----- dlls/effects.h | 8 ++--- dlls/egon.cpp | 10 +++--- dlls/enginecallback.h | 8 +++++ dlls/extdll.h | 6 ++++ dlls/func_break.cpp | 13 ++++--- dlls/func_tank.cpp | 24 ++++++------- dlls/gargantua.cpp | 3 +- dlls/gauss.cpp | 9 +++-- dlls/genericmonster.cpp | 2 +- dlls/ggrenade.cpp | 14 ++++---- dlls/gman.cpp | 8 ++--- dlls/h_battery.cpp | 6 ++-- dlls/h_cine.cpp | 4 +-- dlls/h_cycler.cpp | 6 ++-- dlls/hassassin.cpp | 6 ++-- dlls/headcrab.cpp | 4 +-- dlls/healthkit.cpp | 6 ++-- dlls/hgrunt.cpp | 26 +++++++------- dlls/hornet.cpp | 6 ++-- dlls/houndeye.cpp | 2 +- dlls/ichthyosaur.cpp | 8 ++--- dlls/islave.cpp | 20 +++++------ dlls/leech.cpp | 2 +- dlls/lights.cpp | 17 +++++----- dlls/maprules.cpp | 14 ++++---- dlls/monsters.cpp | 22 ++++++------ dlls/monsterstate.cpp | 6 ++-- dlls/mpstubb.cpp | 4 +-- dlls/multiplay_gamerules.cpp | 16 ++++----- dlls/nihilanth.cpp | 44 ++++++++++++------------ dlls/nodes.cpp | 19 +++++++---- dlls/nodes.h | 4 ++- dlls/observer.cpp | 18 +++++----- dlls/osprey.cpp | 8 ++--- dlls/plats.cpp | 8 ++--- dlls/player.cpp | 66 ++++++++++++++++++------------------ dlls/player.h | 4 +-- dlls/satchel.cpp | 4 +-- dlls/saverestore.h | 11 ++++-- dlls/schedule.cpp | 22 ++++++------ dlls/scientist.cpp | 18 +++++----- dlls/scripted.cpp | 4 +-- dlls/skill.cpp | 5 ++- dlls/skill.h | 2 +- dlls/sound.cpp | 12 +++---- dlls/squadmonster.cpp | 12 +++---- dlls/squadmonster.h | 2 +- dlls/squeakgrenade.cpp | 18 +++++----- dlls/talkmonster.cpp | 32 ++++++++--------- dlls/talkmonster.h | 4 +-- dlls/teamplay_gamerules.cpp | 10 +++--- dlls/tentacle.cpp | 9 ++--- dlls/triggers.cpp | 10 +++--- dlls/tripmine.cpp | 8 ++--- dlls/turret.cpp | 18 +++++----- dlls/util.cpp | 20 +++++------ dlls/util.h | 9 ++--- dlls/vector.h | 14 ++++---- dlls/weapons.cpp | 4 +-- dlls/weapons.h | 8 +++-- dlls/world.cpp | 4 +-- dlls/xen.cpp | 6 ++-- dlls/zombie.cpp | 2 +- engine/custom.h | 6 ++++ engine/edict.h | 8 ++++- engine/eiface.h | 50 ++++++++++++++------------- engine/progdefs.h | 8 ++++- pm_shared/pm_debug.c | 2 ++ pm_shared/pm_debug.h | 6 ++++ pm_shared/pm_defs.h | 6 ++++ pm_shared/pm_info.h | 6 ++++ pm_shared/pm_math.c | 2 ++ pm_shared/pm_shared.c | 26 +++++++++----- pm_shared/pm_shared.h | 6 ++++ 113 files changed, 671 insertions(+), 604 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 988bd6fa..860cde42 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -877,11 +877,11 @@ int CHudAmmo::Draw( float flTime ) x = ScreenWidth - ( 8 * AmmoWidth ) - iIconWidth; x = gHUD.DrawHudNumber( x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b ); - wrect_t rc; + /*wrect_t rc; rc.top = 0; rc.left = 0; rc.right = AmmoWidth; - rc.bottom = 100; + rc.bottom = 100;*/ int iBarWidth = AmmoWidth / 10; diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index cc693b88..e50de419 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -41,7 +41,7 @@ COM_Log Log debug messages to file ( appends ) ==================== */ -void COM_Log( char *pszFile, char *fmt, ... ) +void COM_Log( const char *pszFile, const char *fmt, ... ) { va_list argptr; char string[1024]; @@ -111,7 +111,7 @@ HUD_PlaySound Play a sound, if we are seeing this command for the first time ===================== */ -void HUD_PlaySound( char *sound, float volume ) +void HUD_PlaySound( const char *sound, float volume ) { if( !g_runfuncs || !g_finalstate ) return; @@ -268,12 +268,12 @@ stub functions for such things as precaching. So we don't have to modify weapon is compiled into both game and client .dlls. ====================== */ -int stub_PrecacheModel( char* s ) +int stub_PrecacheModel( const char* s ) { return 0; } -int stub_PrecacheSound( char* s ) +int stub_PrecacheSound( const char* s ) { return 0; } diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index 4dd75203..8559e20b 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -20,7 +20,7 @@ extern "C" void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); } -void COM_Log( char *pszFile, char *fmt, ... ); +void COM_Log( const char *pszFile, const char *fmt, ... ); int CL_IsDead( void ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); @@ -28,11 +28,11 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); int HUD_GetWeaponAnim( void ); void HUD_SendWeaponAnim( int iAnim, int body, int force ); -void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaySound( const char *sound, float volume ); void HUD_PlaybackEvent( 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 ); void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); -int stub_PrecacheModel( char* s ); -int stub_PrecacheSound( char* s ); +int stub_PrecacheModel( const char* s ); +int stub_PrecacheSound( const char* s ); unsigned short stub_PrecacheEvent( int type, const char *s ); const char *stub_NameForFunction( unsigned int function ); void stub_SetModel( struct edict_s *e, const char *m ); diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 455dfd36..579fc255 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -187,7 +187,8 @@ int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbu gHUD.m_Scoreboard.GetAllPlayersInfo(); // Get the Killer's name - char *killer_name = g_PlayerInfoList[killer].name; + const char *killer_name = ""; + killer_name = g_PlayerInfoList[killer].name; if( !killer_name ) { killer_name = ""; @@ -201,11 +202,11 @@ int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbu } // Get the Victim's name - char *victim_name = NULL; + const char *victim_name = ""; // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) - if ( ( (char)victim ) != -1 ) + if( ( (char)victim ) != -1 ) victim_name = g_PlayerInfoList[victim].name; - if ( !victim_name ) + if( !victim_name ) { victim_name = ""; rgDeathNoticeList[i].szVictim[0] = 0; @@ -218,7 +219,7 @@ int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbu } // Is it a non-player object kill? - if ( ( (char)victim ) == -1 ) + if( ( (char)victim ) == -1 ) { rgDeathNoticeList[i].iNonPlayerKill = TRUE; @@ -227,10 +228,10 @@ int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbu } else { - if ( killer == victim || killer == 0 ) + if( killer == victim || killer == 0 ) rgDeathNoticeList[i].iSuicide = TRUE; - if ( !strcmp( killedwith, "d_teammate" ) ) + if( !strcmp( killedwith, "d_teammate" ) ) rgDeathNoticeList[i].iTeamKill = TRUE; } @@ -285,7 +286,7 @@ int CHudDeathNotice::MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbu // replace the code names with the 'real' names if( !strcmp( killedwith + 2, "egon" ) ) strcpy( killedwith, "d_gluon gun" ); - if ( !strcmp( killedwith + 2, "gauss" ) ) + if( !strcmp( killedwith + 2, "gauss" ) ) strcpy( killedwith, "d_tau cannon" ); ConsolePrint( killedwith + 2 ); // skip over the "d_" part diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index 07bd0ff3..303a9d25 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -585,10 +585,10 @@ void DLLEXPORT HUD_TempEntUpdate ( static int gTempEntFrame = 0; int i; TEMPENTITY *pTemp, *pnext, *pprev; - float freq, gravity, gravitySlow, life, fastFreq; + float /*freq,*/ gravity, gravitySlow, life, fastFreq; // Nothing to simulate - if ( !*ppTempEntActive ) + if( !*ppTempEntActive ) return; // in order to have tents collide with players, we have to run the player prediction code so @@ -601,7 +601,7 @@ void DLLEXPORT HUD_TempEntUpdate ( gEngfuncs.pEventAPI->EV_PushPMStates(); // Now add in all of the players. - gEngfuncs.pEventAPI->EV_SetSolidPlayers( -1 ); + gEngfuncs.pEventAPI->EV_SetSolidPlayers( -1 ); // !!!BUGBUG -- This needs to be time based gTempEntFrame = ( gTempEntFrame + 1 ) & 31; @@ -623,7 +623,7 @@ void DLLEXPORT HUD_TempEntUpdate ( } pprev = NULL; - freq = client_time * 0.01; + //freq = client_time * 0.01; fastFreq = client_time * 5.5; gravity = -frametime * cl_gravity; gravitySlow = gravity * 0.5; @@ -709,12 +709,12 @@ void DLLEXPORT HUD_TempEntUpdate ( } else if( pTemp->flags & FTENT_SPIRAL ) { - float s, c; + /*float s, c; s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); - c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq );*/ - pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)(size_t)pTemp ); - pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)(size_t)pTemp ); + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (size_t)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (size_t)pTemp ); pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; } else diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 9787a839..787e1be8 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -94,7 +94,7 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v char chTextureType = CHAR_TEX_CONCRETE; float fvol; float fvolbar; - char *rgsz[4]; + const char *rgsz[4]; int cnt; float fattn = ATTN_NORM; int entity; @@ -568,7 +568,7 @@ void EV_FireShotGunDouble( event_args_t *args ) vec3_t vecSrc, vecAiming; vec3_t vecSpread; vec3_t up, right, forward; - float flSpread = 0.01; + //float flSpread = 0.01; idx = args->entindex; VectorCopy( args->origin, origin ); @@ -622,7 +622,7 @@ void EV_FireShotGunSingle( event_args_t *args ) vec3_t vecSrc, vecAiming; vec3_t vecSpread; vec3_t up, right, forward; - float flSpread = 0.01; + //float flSpread = 0.01; idx = args->entindex; VectorCopy( args->origin, origin ); @@ -679,7 +679,7 @@ void EV_FireMP5( event_args_t *args ) int shell; vec3_t vecSrc, vecAiming; vec3_t up, right, forward; - float flSpread = 0.01; + //float flSpread = 0.01; idx = args->entindex; VectorCopy( args->origin, origin ); @@ -769,7 +769,7 @@ void EV_FirePython( event_args_t *args ) vec3_t vecSrc, vecAiming; vec3_t up, right, forward; - float flSpread = 0.01; + //float flSpread = 0.01; idx = args->entindex; VectorCopy( args->origin, origin ); @@ -860,16 +860,16 @@ void EV_FireGauss( event_args_t *args ) vec3_t angles; vec3_t velocity; float flDamage = args->fparam1; - int primaryfire = args->bparam1; + //int primaryfire = args->bparam1; int m_fPrimaryFire = args->bparam1; - int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + //int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; vec3_t vecSrc; vec3_t vecDest; - edict_t *pentIgnore; + //edict_t *pentIgnore; pmtrace_t tr, beam_tr; float flMaxFrac = 1.0; - int nTotal = 0; + //int nTotal = 0; int fHasPunched = 0; int fFirstBeam = 1; int nMaxHits = 10; @@ -980,7 +980,7 @@ void EV_FireGauss( event_args_t *args ) { float n; - pentIgnore = NULL; + //pentIgnore = NULL; n = -DotProduct( tr.plane.normal, forward ); @@ -1412,12 +1412,12 @@ BEAM *pBeam2; void EV_EgonFire( event_args_t *args ) { - int idx, iFireState, iFireMode; + int idx, /*iFireState,*/ iFireMode; vec3_t origin; idx = args->entindex; VectorCopy( args->origin, origin ); - iFireState = args->iparam1; + //iFireState = args->iparam1; iFireMode = args->iparam2; int iStartup = args->bparam1; @@ -1539,13 +1539,13 @@ enum hgun_e void EV_HornetGunFire( event_args_t *args ) { - int idx, iFireMode; + int idx; //, iFireMode; vec3_t origin, angles, vecSrc, forward, right, up; idx = args->entindex; VectorCopy( args->origin, origin ); VectorCopy( args->angles, angles ); - iFireMode = args->iparam1; + //iFireMode = args->iparam1; //Only play the weapon anims if I shot it. if( EV_IsLocal( idx ) ) @@ -1554,7 +1554,7 @@ void EV_HornetGunFire( event_args_t *args ) gEngfuncs.pEventAPI->EV_WeaponAnimation( HGUN_SHOOT, 1 ); } - switch( gEngfuncs.pfnRandomLong( 0 , 2 ) ) + switch( gEngfuncs.pfnRandomLong( 0, 2 ) ) { case 0: gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 ); diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 7ccaf1d3..097889b9 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -65,7 +65,7 @@ int CHudGeiger::Draw( float flTime ) { int pct; float flvol = 0.0f; - int rg[3]; + //int rg[3]; int i; if( m_iGeigerRange < 1000 && m_iGeigerRange > 0 ) @@ -79,61 +79,61 @@ int CHudGeiger::Draw( float flTime ) { pct = 2; flvol = 0.4; //Con_Printf( "range > 600\n" ); - rg[0] = 1; - rg[1] = 1; + //rg[0] = 1; + //rg[1] = 1; i = 2; } else if( m_iGeigerRange > 500 ) { pct = 4; flvol = 0.5; //Con_Printf( "range > 500\n" ); - rg[0] = 1; - rg[1] = 2; + //rg[0] = 1; + //rg[1] = 2; i = 2; } else if( m_iGeigerRange > 400 ) { pct = 8; flvol = 0.6; //Con_Printf( "range > 400\n" ); - rg[0] = 1; - rg[1] = 2; - rg[2] = 3; + //rg[0] = 1; + //rg[1] = 2; + //rg[2] = 3; i = 3; } else if( m_iGeigerRange > 300 ) { pct = 8; flvol = 0.7; //Con_Printf( "range > 300\n" ); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; + //rg[0] = 2; + //rg[1] = 3; + //rg[2] = 4; i = 3; } else if( m_iGeigerRange > 200 ) { pct = 28; flvol = 0.78; //Con_Printf( "range > 200\n" ); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; + //rg[0] = 2; + //rg[1] = 3; + //rg[2] = 4; i = 3; } else if( m_iGeigerRange > 150 ) { pct = 40; flvol = 0.80; //Con_Printf( "range > 150\n" ); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; + //rg[0] = 3; + //rg[1] = 4; + //rg[2] = 5; i = 3; } else if( m_iGeigerRange > 100 ) { pct = 60; flvol = 0.85; //Con_Printf( "range > 100\n" ); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; + //rg[0] = 3; + //rg[1] = 4; + //rg[2] = 5; i = 3; } else if( m_iGeigerRange > 75 ) @@ -141,29 +141,29 @@ int CHudGeiger::Draw( float flTime ) pct = 80; flvol = 0.9; //Con_Printf( "range > 75\n" ); //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; - rg[0] = 4; - rg[1] = 5; - rg[2] = 6; + //rg[0] = 4; + //rg[1] = 5; + //rg[2] = 6; i = 3; } else if( m_iGeigerRange > 50 ) { pct = 90; flvol = 0.95; //Con_Printf( "range > 50\n" ); - rg[0] = 5; - rg[1] = 6; + //rg[0] = 5; + //rg[1] = 6; i = 2; } else { pct = 95; flvol = 1.0; //Con_Printf( "range < 50\n" ); - rg[0] = 5; - rg[1] = 6; + //rg[0] = 5; + //rg[1] = 6; i = 2; } - flvol = ( flvol * ( (rand() & 127) ) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); + flvol = ( flvol * ( ( rand() & 127 ) ) / 255 ) + 0.25; // UTIL_RandomFloat( 0.25, 0.5 ); if( ( rand() & 127 ) < pct || ( rand() & 127 ) < pct ) { diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index fc306838..d24c0ef4 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -54,7 +54,7 @@ int CBaseEntity::IsDormant( void ) { return 0; } BOOL CBaseEntity::IsInWorld( void ) { return TRUE; } int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } int CBaseEntity::DamageDecal( int bitsDamageType ) { return -1; } -CBaseEntity *CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +CBaseEntity *CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } void CBaseEntity::SUB_Remove( void ) { } // CBaseDelay Stubs @@ -146,7 +146,7 @@ int CBaseMonster::CheckEnemy( CBaseEntity *pEnemy ) { return 0; } void CBaseMonster::PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } BOOL CBaseMonster::PopEnemy() { return FALSE; } void CBaseMonster::SetActivity( Activity NewActivity ) { } -void CBaseMonster::SetSequenceByName( char *szSequence ) { } +void CBaseMonster::SetSequenceByName( const char *szSequence ) { } int CBaseMonster::CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } float CBaseMonster::OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } void CBaseMonster::AdvanceRoute( float distance ) { } @@ -214,7 +214,7 @@ void CBaseMonster::MonsterInitDead( void ) { } BOOL CBaseMonster::BBoxFlat( void ) { return TRUE; } BOOL CBaseMonster::GetEnemy( void ) { return FALSE; } void CBaseMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } -CBaseEntity* CBaseMonster::DropItem( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } +CBaseEntity* CBaseMonster::DropItem( const char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } BOOL CBaseMonster::ShouldFadeOnDeath( void ) { return FALSE; } void CBaseMonster::RadiusDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } void CBaseMonster::RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } @@ -258,8 +258,8 @@ void CBasePlayer::PreThink(void) { } void CBasePlayer::CheckTimeBasedDamage() { } void CBasePlayer::UpdateGeigerCounter( void ) { } void CBasePlayer::CheckSuitUpdate() { } -void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } -void CBasePlayer::UpdatePlayerSound ( void ) { } +void CBasePlayer::SetSuitUpdate( const char *name, int fgroup, int iNoRepeatTime ) { } +void CBasePlayer::UpdatePlayerSound( void ) { } void CBasePlayer::PostThink() { } void CBasePlayer::Precache( void ) { } int CBasePlayer::Save( CSave &save ) { return 0; } @@ -298,7 +298,7 @@ BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } Vector CBasePlayer::GetGunPosition( void ) { return g_vecZero; } const char *CBasePlayer::TeamID( void ) { return ""; } -int CBasePlayer::GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +int CBasePlayer::GiveAmmo( int iCount, const char *szName, int iMax ) { return 0; } void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 8c6909e3..8f8baea7 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -75,7 +75,7 @@ AlertMessage Print debug messages to console ====================== */ -void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +void AlertMessage( ALERT_TYPE atype, const char *szFmt, ... ) { va_list argptr; static char string[1024]; @@ -96,7 +96,7 @@ bool bIsMultiplayer( void ) } //Just loads a v_ model. -void LoadVModel( char *szViewModel, CBasePlayer *m_pPlayer ) +void LoadVModel( const char *szViewModel, CBasePlayer *m_pPlayer ) { gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); } @@ -208,7 +208,7 @@ CBasePlayerWeapon::DefaultDeploy ===================== */ -BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, const char *szWeaponModel, int iAnim, const char *szAnimExt, int skiplocal, int body ) { if( !CanDeploy() ) return FALSE; @@ -288,7 +288,7 @@ Only produces random numbers to match the server ones. */ 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 ) { - float x = 0, y = 0, z; + float x = 0.0f, y = 0.0f, z; for( ULONG iShot = 1; iShot <= cShots; iShot++ ) { diff --git a/cl_dll/hud.h b/cl_dll/hud.h index ec236003..ab179bbb 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -480,7 +480,7 @@ public: int Init( void ); static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); static char *BufferedLocaliseTextString( const char *msg ); - char *LookupString( const char *msg_name, int *msg_dest = NULL ); + const char *LookupString( const char *msg_name, int *msg_dest = NULL ); int MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ); }; @@ -541,8 +541,8 @@ public: //had to make these public so CHud could access them (to enable concussion icon) //could use a friend declaration instead... - void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); - void DisableIcon( char *pszIconName ); + void EnableIcon( const char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); + void DisableIcon( const char *pszIconName ); private: typedef struct @@ -588,11 +588,11 @@ public: int m_iFontHeight; int DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b ); - int DrawHudString( int x, int y, int iMaxX, char *szString, int r, int g, int b ); - int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); + int DrawHudString( int x, int y, int iMaxX, const char *szString, int r, int g, int b ); + int DrawHudStringReverse( int xpos, int ypos, int iMinX, const char *szString, int r, int g, int b ); int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); int GetNumWidth( int iNumber, int iFlags ); - int DrawHudStringLen( char *szIt ); + int DrawHudStringLen( const char *szIt ); void DrawDarkRectangle( int x, int y, int wide, int tall ); private: diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index c30df36d..5182b484 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -199,7 +199,7 @@ const unsigned char colors[8][3] = {240, 180, 24} }; -int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +int CHud::DrawHudString( int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) { if( hud_textmode->value == 2 ) { @@ -233,9 +233,7 @@ int CHud::DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g return xpos; } - - -int DrawUtfString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +int DrawUtfString( int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) { // xash3d: reset unicode state gEngfuncs.pfnVGUI2DrawCharacterAdditive( 0, 0, 0, 0, 0, 0, 0 ); @@ -262,7 +260,7 @@ int DrawUtfString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int return xpos; } -int CHud::DrawHudStringLen( char *szIt ) +int CHud::DrawHudStringLen( const char *szIt ) { int l = 0; for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) @@ -280,7 +278,7 @@ int CHud::DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r } // draws a string from right to left (right-aligned) -int CHud::DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +int CHud::DrawHudStringReverse( int xpos, int ypos, int iMinX, const char *szString, int r, int g, int b ) { // find the end of the string for( char *szIt = szString; *szIt != 0; szIt++ ) diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index 5d52d413..ff8d97bf 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -29,7 +29,7 @@ DECLARE_MESSAGE( m_Message, GameTitle ) // 1 Global client_textmessage_t for custom messages that aren't in the titles.txt client_textmessage_t g_pCustomMessage; -char *g_pCustomName = "Custom"; +const char *g_pCustomName = "Custom"; char g_pCustomText[1024]; int CHudMessage::Init( void ) @@ -260,7 +260,7 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) width = 0; } else - width += gHUD.m_scrinfo.charWidths[*pText]; + width += gHUD.m_scrinfo.charWidths[(unsigned char)*pText]; pText++; length++; } @@ -310,7 +310,7 @@ int CHudMessage::Draw( float fTime ) { int i, drawn; client_textmessage_t *pMessage; - float endTime = 0; + float endTime = 0.0f; drawn = 0; diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index c960d5ef..4b2d9726 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -104,7 +104,7 @@ int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *p } // add the icon to the icon list, and set it's drawing color -void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) +void CHudStatusIcons::EnableIcon( const char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) { int i; @@ -149,7 +149,7 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned } } -void CHudStatusIcons::DisableIcon( char *pszIconName ) +void CHudStatusIcons::DisableIcon( const char *pszIconName ) { // find the sprite is in the current list for( int i = 0; i < MAX_ICONSPRITES; i++ ) diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index af62a915..13b62577 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -45,7 +45,7 @@ int CHudTextMessage::Init( void ) char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) { char *dst = dst_buffer; - for( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + for( char *src = msg; *src != 0 && buffer_size > 0; buffer_size-- ) { if( *src == '#' ) { @@ -91,12 +91,12 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) { static char dst_buffer[1024]; - LocaliseTextString( msg, dst_buffer, 1024 ); + LocaliseTextString( msg, dst_buffer, sizeof(dst_buffer) ); return dst_buffer; } // Simplified version of LocaliseTextString; assumes string is only one word -char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) +const char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) { if( !msg ) return ""; @@ -108,7 +108,7 @@ char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) client_textmessage_t *clmsg = TextMessageGet( msg + 1 ); if( !clmsg || !(clmsg->pMessage) ) - return (char*)msg; // lookup failed, so return the original string + return msg; // lookup failed, so return the original string if( msg_dest ) { @@ -118,12 +118,12 @@ char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) *msg_dest = -clmsg->effect; } - return (char*)clmsg->pMessage; + return clmsg->pMessage; } else { // nothing special about this message, so just return the same string - return (char*)msg; + return msg; } } @@ -167,16 +167,16 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf msg_text = strcpy( szBuf[0], msg_text ); // keep reading strings and using C format strings for subsituting the strings into the localised text string - char *sstr1 = LookupString( READ_STRING() ); + const char *sstr1 = LookupString( READ_STRING() ); sstr1 = strcpy( szBuf[1], sstr1 ); StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines - char *sstr2 = LookupString( READ_STRING() ); + const char *sstr2 = LookupString( READ_STRING() ); sstr2 = strcpy( szBuf[2], sstr2 ); StripEndNewlineFromString( sstr2 ); - char *sstr3 = LookupString( READ_STRING() ); + const char *sstr3 = LookupString( READ_STRING() ); sstr3 = strcpy( szBuf[3], sstr3 ); StripEndNewlineFromString( sstr3 ); - char *sstr4 = LookupString( READ_STRING() ); + const char *sstr4 = LookupString( READ_STRING() ); sstr4 = strcpy( szBuf[4], sstr4 ); StripEndNewlineFromString( sstr4 ); char *psz = szBuf[5]; diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index b581cc82..dcd2b1af 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -351,11 +351,11 @@ V_CalcIntermissionRefdef */ void V_CalcIntermissionRefdef( struct ref_params_s *pparams ) { - cl_entity_t *ent, *view; + cl_entity_t /**ent,*/ *view; float old; // ent is the player model ( visible when out of body ) - ent = gEngfuncs.GetLocalPlayer(); + //ent = gEngfuncs.GetLocalPlayer(); // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); @@ -1307,7 +1307,7 @@ void V_GetMapChasePosition( int target, float *cl_angles, float *origin, float * int V_FindViewModelByWeaponModel( int weaponindex ) { - static char *modelmap[][2] = + static const char *modelmap[][2] = { { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, @@ -1327,7 +1327,7 @@ int V_FindViewModelByWeaponModel( int weaponindex ) { NULL, NULL } }; - struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); + struct model_s *weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); if( weaponModel ) { diff --git a/common/cvardef.h b/common/cvardef.h index c57b97a7..e8a24581 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -28,8 +28,8 @@ typedef struct cvar_s { - char *name; - char *string; + const char *name; + const char *string; int flags; float value; struct cvar_s *next; diff --git a/dlls/activity.h b/dlls/activity.h index 58b2d8cd..5382d70d 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -99,7 +99,7 @@ typedef enum { typedef struct { int type; - char *name; + const char *name; } activity_map_t; extern activity_map_t activity_map[]; diff --git a/dlls/activitymap.h b/dlls/activitymap.h index 92cadae7..5f77c55a 100644 --- a/dlls/activitymap.h +++ b/dlls/activitymap.h @@ -93,5 +93,5 @@ _A( ACT_FLINCH_LEFTARM ), _A( ACT_FLINCH_RIGHTARM ), _A( ACT_FLINCH_LEFTLEG ), _A( ACT_FLINCH_RIGHTLEG ), -0, NULL +{ 0, NULL } }; diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index 1e317632..19998a9d 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -567,7 +567,6 @@ void CFlockingFlyer::FlockLeaderThink( void ) TraceResult tr; Vector vecDist;// used for general measurements Vector vecDir;// used for general measurements - int cProcessed = 0;// keep track of how many other boids we've processed float flLeftSide; float flRightSide; diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index 97804f68..c6583fb7 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -608,7 +608,7 @@ void CAGrunt::Spawn() //========================================================= void CAGrunt::Precache() { - int i; + size_t i; PRECACHE_MODEL( "models/agrunt.mdl" ); @@ -909,7 +909,7 @@ BOOL CAGrunt::FCanCheckAttacks( void ) //========================================================= BOOL CAGrunt::CheckMeleeAttack1( float flDot, float flDist ) { - if( HasConditions( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != NULL ) + if( HasConditions( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != 0 ) { return TRUE; } @@ -1160,7 +1160,7 @@ Schedule_t *CAGrunt::GetScheduleOfType( int Type ) case SCHED_FAIL: // no fail schedule specified, so pick a good generic one. { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // I have an enemy // !!!LATER - what if this enemy is really far away and i'm chasing him? diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 86cb78ae..5454f0e8 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -268,8 +268,6 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve if( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) return 0; - int events = 0; - mstudioseqdesc_t *pseqdesc; mstudioevent_t *pevent; @@ -351,7 +349,7 @@ float SetController( void *pmodel, entvars_t *pev, int iController, float flValu } } - int setting = 255 * ( flValue - pbonecontroller->start ) / ( pbonecontroller->end - pbonecontroller->start ); + int setting = (int)( 255 * ( flValue - pbonecontroller->start ) / ( pbonecontroller->end - pbonecontroller->start ) ); if( setting < 0 ) setting = 0; @@ -393,7 +391,7 @@ float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) } } - int setting = 255 * ( flValue - pseqdesc->blendstart[iBlender] ) / ( pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender] ); + int setting = (int)( 255 * ( flValue - pseqdesc->blendstart[iBlender] ) / ( pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender] ) ); if( setting < 0 ) setting = 0; diff --git a/dlls/apache.cpp b/dlls/apache.cpp index b64a8bae..aeeea30e 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -458,7 +458,7 @@ void CApache::HuntThink( void ) if( m_flGoalSpeed < 800 ) m_flGoalSpeed += 5; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); if( FVisible( m_hEnemy ) ) @@ -552,7 +552,7 @@ void CApache::HuntThink( void ) { if( m_flLastSeen + 60 > gpGlobals->time ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // make sure it's a good shot if( DotProduct( m_vecTarget, vecEst ) > .965 ) @@ -732,7 +732,6 @@ void CApache::Flight( void ) void CApache::FireRocket( void ) { static float side = 1.0; - static int count; if( m_iRockets <= 0 ) return; diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp index 1e2aa785..ecc1f5d4 100644 --- a/dlls/barnacle.cpp +++ b/dlls/barnacle.cpp @@ -170,7 +170,7 @@ void CBarnacle::BarnacleThink( void ) #endif pev->nextthink = gpGlobals->time + 0.1; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // barnacle has prey. if( !m_hEnemy->IsAlive() ) @@ -183,7 +183,7 @@ void CBarnacle::BarnacleThink( void ) if( m_fLiftingPrey ) { - if( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) + if( m_hEnemy != 0 && m_hEnemy->pev->deadflag != DEAD_NO ) { // crap, someone killed the prey on the way up. m_hEnemy = NULL; @@ -352,7 +352,7 @@ void CBarnacle::Killed( entvars_t *pevAttacker, int iGib ) pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { pVictim = m_hEnemy->MyMonsterPointer(); diff --git a/dlls/barney.cpp b/dlls/barney.cpp index b1c97090..3fc5aef0 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -221,7 +221,7 @@ void CBarney::RunTask( Task_t *pTask ) switch( pTask->iTask ) { case TASK_RANGE_ATTACK1: - if( m_hEnemy != NULL && ( m_hEnemy->IsPlayer() ) ) + if( m_hEnemy != 0 && ( m_hEnemy->IsPlayer() ) ) { pev->framerate = 1.5; } @@ -262,7 +262,7 @@ int CBarney::Classify( void ) //========================================================= void CBarney::AlertSound( void ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( FOkToSpeak() ) { @@ -504,7 +504,7 @@ int CBarney::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float // 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 == NULL ) + 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 ) ) @@ -616,7 +616,7 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib ) GetAttachment( 0, vecGunPos, vecGunAngles ); - CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); + DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); } SetUse( NULL ); @@ -633,7 +633,7 @@ Schedule_t *CBarney::GetScheduleOfType( int Type ) switch( Type ) { case SCHED_ARM_WEAPON: - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // face enemy, then draw. return slBarneyEnemyDraw; @@ -721,7 +721,7 @@ Schedule_t *CBarney::GetSchedule( void ) return GetScheduleOfType( SCHED_SMALL_FLINCH ); } - if( m_hEnemy == NULL && IsFollowing() ) + if( m_hEnemy == 0 && IsFollowing() ) { if( !m_hTargetEnt->IsAlive() ) { @@ -783,10 +783,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; + static const char *m_szPoses[3]; }; -char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; +const char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; void CDeadBarney::KeyValue( KeyValueData *pkvd ) { diff --git a/dlls/basemonster.h b/dlls/basemonster.h index ad05fccf..0d22104f 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -195,7 +195,7 @@ public: Task_t *GetTask( void ); virtual MONSTERSTATE GetIdealState( void ); virtual void SetActivity( Activity NewActivity ); - void SetSequenceByName( char *szSequence ); + void SetSequenceByName( const char *szSequence ); void SetState( MONSTERSTATE State ); virtual void ReportAIState( void ); @@ -327,6 +327,6 @@ public: BOOL ExitScriptedSequence(); BOOL CineCleanup(); - CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. + CBaseEntity* DropItem( const char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. }; #endif // BASEMONSTER_H diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index 59f6cae2..a038c776 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -677,7 +677,7 @@ void CBigMomma::Precache() void CBigMomma::Activate( void ) { - if( m_hTargetEnt == NULL ) + if( m_hTargetEnt == 0 ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up } @@ -985,7 +985,7 @@ void CBigMomma::RunTask( Task_t *pTask ) { float distance; - if( m_hTargetEnt == NULL ) + if( m_hTargetEnt == 0 ) TaskFail(); else { @@ -1002,7 +1002,7 @@ void CBigMomma::RunTask( Task_t *pTask ) } break; case TASK_WAIT_NODE: - if( m_hTargetEnt != NULL && ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) ) + if( m_hTargetEnt != 0 && ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) ) return; if( gpGlobals->time > m_flWaitFinished ) @@ -1056,7 +1056,6 @@ Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot float time = speed / flGravity; vecGrenadeVel = vecSpot2 - vecSpot1; vecGrenadeVel.z = 0; - float distance = vecGrenadeVel.Length(); // Travel half the distance to the target in that time (apex is at the midpoint) vecGrenadeVel = vecGrenadeVel * ( 0.5 / time ); diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index ee676679..6e8526f9 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -210,7 +210,7 @@ void CFuncIllusionary::KeyValue( KeyValueData *pkvd ) { if( FStrEq( pkvd->szKeyName, "skin" ) )//skin is used for content type { - pev->skin = atof( pkvd->szValue ); + pev->skin = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else @@ -614,7 +614,7 @@ void CFuncRotating::SpinDown( void ) // stop sound, we're done EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING( pev->noiseRunning /* Stop */ ), - 0, 0, SND_STOP, m_pitch ); + 0, 0, SND_STOP, (int)m_pitch ); SetThink( &CFuncRotating::Rotate ); Rotate(); diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp index 18026b43..af3ab88a 100644 --- a/dlls/bullsquid.cpp +++ b/dlls/bullsquid.cpp @@ -248,7 +248,7 @@ int CBullsquid::IgnoreConditions( void ) iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; } - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) { @@ -287,7 +287,7 @@ int CBullsquid::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo // 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 != NULL && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) + if( m_hEnemy != 0 && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) { flDist = ( pev->origin - m_hEnemy->pev->origin ).Length2D(); @@ -324,7 +324,7 @@ BOOL CBullsquid::CheckRangeAttack1( float flDot, float flDist ) if( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) { @@ -383,7 +383,7 @@ BOOL CBullsquid::CheckMeleeAttack2( float flDot, float flDist ) //========================================================= BOOL CBullsquid::FValidateHintType( short sHint ) { - int i; + size_t i; static short sSquidHints[] = { @@ -784,7 +784,7 @@ void CBullsquid::RunAI( void ) pev->skin = 1; } - if( m_hEnemy != NULL && m_Activity == ACT_RUN ) + 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 ) @@ -1247,7 +1247,7 @@ MONSTERSTATE CBullsquid::GetIdealState( void ) COMBAT goes to ALERT upon death of enemy */ { - if( m_hEnemy != NULL && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) + 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 = NULL; diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 3027f10e..76f4ad91 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -275,7 +275,7 @@ IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ) void CBaseButton::Precache( void ) { - char *pszSound; + const char *pszSound; if( FBitSet( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state { @@ -381,22 +381,22 @@ void CBaseButton::KeyValue( KeyValueData *pkvd ) } else if( FStrEq( pkvd->szKeyName, "locked_sound" ) ) { - m_bLockedSound = atof( pkvd->szValue ); + m_bLockedSound = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "locked_sentence" ) ) { - m_bLockedSentence = atof( pkvd->szValue ); + m_bLockedSentence = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "unlocked_sound" ) ) { - m_bUnlockedSound = atof( pkvd->szValue ); + m_bUnlockedSound = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "unlocked_sentence" ) ) { - m_bUnlockedSentence = atof( pkvd->szValue ); + m_bUnlockedSentence = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "sounds" ) ) @@ -421,7 +421,7 @@ int CBaseButton::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl SetTouch( NULL ); m_hActivator = CBaseEntity::Instance( pevAttacker ); - if( m_hActivator == NULL ) + if( m_hActivator == 0 ) return 0; if( code == BUTTON_RETURN ) @@ -461,7 +461,7 @@ LINK_ENTITY_TO_CLASS( func_button, CBaseButton ) void CBaseButton::Spawn() { - char *pszSound; + const char *pszSound; //---------------------------------------------------- //determine sounds for buttons @@ -527,7 +527,7 @@ void CBaseButton::Spawn() char *ButtonSound( int sound ) { - char *pszSound; + const char *pszSound; switch( sound ) { @@ -869,7 +869,7 @@ LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ) void CRotButton::Spawn( void ) { - char *pszSound; + const char *pszSound; //---------------------------------------------------- //determine sounds for buttons //a sound of 0 should not make a sound @@ -1010,7 +1010,7 @@ void CMomentaryRotButton::Spawn( void ) UTIL_SetOrigin( pev, pev->origin ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); - char *pszSound = ButtonSound( m_sounds ); + const char *pszSound = ButtonSound( m_sounds ); PRECACHE_SOUND( pszSound ); pev->noise = ALLOC_STRING( pszSound ); m_lastUsed = 0; diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 62b4eaa1..0cc10bdb 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -26,7 +26,7 @@ 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( char *name ); +extern "C" char PM_FindTextureType( const char *name ); extern Vector VecBModelOrigin( entvars_t* pevBModel ); extern DLL_GLOBAL Vector g_vecAttackDir; @@ -739,7 +739,7 @@ int CBaseEntity::DamageDecal( int bitsDamageType ) // 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( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) +CBaseEntity *CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { edict_t *pent; CBaseEntity *pEntity; diff --git a/dlls/cbase.h b/dlls/cbase.h index 617bbab9..6c738bf5 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -177,7 +177,7 @@ public: 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, char *szName, int iMax ) { return -1; }; + 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 ) {} @@ -314,7 +314,7 @@ public: // used by monsters that are created by the MonsterMaker virtual void UpdateOwner( void ) { return; }; - static CBaseEntity *Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); + 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 ); }; @@ -655,8 +655,7 @@ class CSound; #include "basemonster.h" - -char *ButtonSound( int sound ); // get string of button sound number +const char *ButtonSound( int sound ); // get string of button sound number // // Generic Button diff --git a/dlls/client.cpp b/dlls/client.cpp index 72538b02..99f1913b 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -215,7 +215,7 @@ bool Q_IsValidUChar32( unsigned int 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 < 0x110000u ) && ( ( uVal - 0x00D800u ) > 0x7FFu ) && ( ( uVal & 0xFFFFu ) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu ); + 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 @@ -423,7 +423,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) // echo to server console g_engfuncs.pfnServerPrint( text ); - char *temp; + const char *temp; if( teamonly ) temp = "say_team"; else @@ -744,7 +744,6 @@ void PlayerPreThink( edict_t *pEntity ) { //ALERT( at_console, "PreThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - entvars_t *pev = &pEntity->v; CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); if( pPlayer ) @@ -762,7 +761,6 @@ void PlayerPostThink( edict_t *pEntity ) { //ALERT( at_console, "PostThink( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); - entvars_t *pev = &pEntity->v; CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); if( pPlayer ) @@ -950,7 +948,6 @@ animation right now. */ void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) { - entvars_t *pev = &pEntity->v; CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE( pEntity ); if( !pPlayer ) @@ -990,7 +987,6 @@ A spectator has joined the game */ void SpectatorConnect( edict_t *pEntity ) { - entvars_t *pev = &pEntity->v; CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); if( pPlayer ) @@ -1006,7 +1002,6 @@ A spectator has left the game */ void SpectatorDisconnect( edict_t *pEntity ) { - entvars_t *pev = &pEntity->v; CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); if( pPlayer ) @@ -1022,7 +1017,6 @@ A spectator has sent a usercmd */ void SpectatorThink( edict_t *pEntity ) { - entvars_t *pev = &pEntity->v; CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE( pEntity ); if( pPlayer ) @@ -1235,11 +1229,11 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h } state->rendermode = ent->v.rendermode; - state->renderamt = ent->v.renderamt; + state->renderamt = (int)ent->v.renderamt; state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor.x; - state->rendercolor.g = ent->v.rendercolor.y; - state->rendercolor.b = ent->v.rendercolor.z; + state->rendercolor.r = (byte)ent->v.rendercolor.x; + state->rendercolor.g = (byte)ent->v.rendercolor.y; + state->rendercolor.b = (byte)ent->v.rendercolor.z; state->aiment = 0; if( ent->v.aiment ) @@ -1286,7 +1280,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h //state->team = ent->v.team; state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; - state->health = ent->v.health; + state->health = (int)ent->v.health; } return 1; @@ -1834,7 +1828,7 @@ ConnectionlessPacket int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) { // Parse stuff from args - int max_buffer_size = *response_buffer_size; + //int max_buffer_size = *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 @@ -1888,10 +1882,10 @@ to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, et */ void CreateInstancedBaselines( void ) { - int iret = 0; + /*int iret = 0; entity_state_t state; - memset( &state, 0, sizeof(state) ); + memset( &state, 0, sizeof(state) );*/ // Create any additional baselines here for things like grendates, etc. // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 3a59844f..d8830c20 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -460,11 +460,11 @@ Activity CBaseMonster::GetSmallFlinchActivity( void ) { Activity flinchActivity; BOOL fTriedDirection; - float flDot; + //float flDot; fTriedDirection = FALSE; UTIL_MakeVectors( pev->angles ); - flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1 ); + //flDot = DotProduct( gpGlobals->v_forward, g_vecAttackDir * -1 ); switch( m_LastHitGroup ) { @@ -576,8 +576,8 @@ Killed */ void CBaseMonster::Killed( entvars_t *pevAttacker, int iGib ) { - unsigned int cCount = 0; - BOOL fDone = FALSE; + //unsigned int cCount = 0; + //BOOL fDone = FALSE; if( HasMemory( bits_MEMORY_KILLED ) ) { @@ -920,7 +920,7 @@ int CBaseMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f // enemy's last known position is somewhere down the vector that the attack came from. if( pevInflictor ) { - if( m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions( bits_COND_SEE_ENEMY ) ) + if( m_hEnemy == 0 || pevInflictor == m_hEnemy->pev || !HasConditions( bits_COND_SEE_ENEMY ) ) { m_vecEnemyLKP = pevInflictor->origin; } @@ -1463,7 +1463,7 @@ void CBaseEntity::FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShootin } } // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, ( flDistance * tr.flFraction ) / 64.0 ); + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0 ); } ApplyMultiDamage( pev, pevAttacker ); } @@ -1483,7 +1483,8 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi TraceResult tr; Vector vecRight = gpGlobals->v_right; Vector vecUp = gpGlobals->v_up; - float x, y, z; + float x = 0.0f, y = 0.0f; + float z; if( pevAttacker == NULL ) pevAttacker = pev; // the default attacker is ourselves @@ -1497,7 +1498,7 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi // 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; + //z = x * x + y * y; Vector vecDir = vecDirShooting + x * vecSpread.x * vecRight + @@ -1548,7 +1549,7 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi } } // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, ( flDistance * tr.flFraction ) / 64.0 ); + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0 ) ); } ApplyMultiDamage( pev, pevAttacker ); diff --git a/dlls/controller.cpp b/dlls/controller.cpp index 3d56325f..bfa119d3 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -614,7 +614,7 @@ void CController::RunTask( Task_t *pTask ) Vector vecSrc = vecHand + pev->velocity * ( m_flShootTime - gpGlobals->time ); Vector vecDir; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( HasConditions( bits_COND_SEE_ENEMY ) ) { @@ -707,7 +707,7 @@ Schedule_t *CController::GetSchedule( void ) { case MONSTERSTATE_COMBAT: { - Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); + // Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); // dead enemy if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) @@ -1095,7 +1095,6 @@ class CControllerHeadBall : public CBaseMonster void EXPORT BounceTouch( CBaseEntity *pOther ); void MovetoTarget( Vector vecTarget ); void Crawl( void ); - int m_iTrail; int m_flNextAttack; Vector m_vecIdeal; EHANDLE m_hOwner; @@ -1160,7 +1159,7 @@ void CControllerHeadBall::HuntThink( void ) MESSAGE_END(); // check world boundaries - if( gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == NULL || m_hOwner == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) + 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 ); @@ -1340,7 +1339,7 @@ void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) entvars_t *pevOwner; - if( m_hOwner != NULL ) + if( m_hOwner != 0 ) { pevOwner = m_hOwner->pev; } diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 7a4686e7..d749c785 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -425,10 +425,11 @@ void CCrossbow::FireBolt() UTIL_MakeVectors( anglesAim ); anglesAim.x = -anglesAim.x; + +#ifndef CLIENT_DLL Vector vecSrc = m_pPlayer->GetGunPosition() - gpGlobals->v_up * 2; Vector vecDir = gpGlobals->v_forward; -#ifndef CLIENT_DLL CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); pBolt->pev->origin = vecSrc; pBolt->pev->angles = anglesAim; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 80a18d65..00b16d57 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -183,7 +183,7 @@ int CCrowbar::Swing( int fFirst ) #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, 0.0 ); + 0, 0, 0 ); if( tr.flFraction >= 1.0 ) { @@ -294,7 +294,7 @@ int CCrowbar::Swing( int fFirst ) m_trHit = tr; } - m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; + m_pPlayer->m_iWeaponVolume = (int)( flVol * CROWBAR_WALLHIT_VOLUME ); #endif m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); diff --git a/dlls/decals.h b/dlls/decals.h index ce5a2b53..97f5f29f 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -66,7 +66,7 @@ enum decal_e typedef struct { - char *name; + const char *name; int index; } DLL_DECALLIST; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index bdc82f06..dcb04e00 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -189,42 +189,42 @@ void CBaseDoor::KeyValue( KeyValueData *pkvd ) { if( FStrEq( pkvd->szKeyName, "skin" ) )//skin is used for content type { - pev->skin = atof( pkvd->szValue ); + pev->skin = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof( pkvd->szValue ); + m_bMoveSnd = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) { - m_bStopSnd = atof( pkvd->szValue ); + m_bStopSnd = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "healthvalue" ) ) { - m_bHealthValue = atof( pkvd->szValue ); + m_bHealthValue = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "locked_sound" ) ) { - m_bLockedSound = atof( pkvd->szValue ); + m_bLockedSound = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "locked_sentence" ) ) { - m_bLockedSentence = atof( pkvd->szValue ); + m_bLockedSentence = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "unlocked_sound" ) ) { - m_bUnlockedSound = atof( pkvd->szValue ); + m_bUnlockedSound = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "unlocked_sentence" ) ) { - m_bUnlockedSentence = atof( pkvd->szValue ); + m_bUnlockedSentence = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "WaveHeight" ) ) @@ -328,7 +328,7 @@ void CBaseDoor::SetToggleState( int state ) void CBaseDoor::Precache( void ) { - char *pszSound; + const char *pszSound; // set the door's "in-motion" sound switch( m_bMoveSnd ) @@ -581,7 +581,7 @@ int CBaseDoor::DoorActivate() else { // door should open - if( m_hActivator != NULL && m_hActivator->IsPlayer() ) + if( m_hActivator != 0 && m_hActivator->IsPlayer() ) { // give health if player opened the door (medikit) //VARS( m_eoActivator )->health += m_bHealthValue; @@ -623,7 +623,7 @@ void CBaseDoor::DoorGoUp( void ) { float sign = 1.0; - if( m_hActivator != NULL ) + if( m_hActivator != 0 ) { pevActivator = m_hActivator->pev; @@ -1070,7 +1070,7 @@ void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof( pkvd->szValue ); + m_bMoveSnd = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) diff --git a/dlls/effects.cpp b/dlls/effects.cpp index ecc04a19..2977a3ed 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -75,7 +75,7 @@ void CBubbling::Spawn( void ) 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 ? pev->speed : -pev->speed; + int speed = fabs( pev->speed ); // HACKHACK!!! - Speed in rendercolor pev->rendercolor.x = speed >> 8; @@ -701,7 +701,7 @@ void CLightning::StrikeThink( void ) 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( pev->renderamt ); // brightness + WRITE_BYTE( (int)pev->renderamt ); // brightness WRITE_BYTE( m_speed ); // speed MESSAGE_END(); DoSparks( pStart->pev->origin, pEnd->pev->origin ); @@ -763,7 +763,7 @@ void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) 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( pev->renderamt ); // brightness + WRITE_BYTE( (int)pev->renderamt ); // brightness WRITE_BYTE( m_speed ); // speed MESSAGE_END(); #else @@ -944,7 +944,7 @@ void CLaser::Spawn( void ) m_pSprite = NULL; if( m_pSprite ) - m_pSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); + m_pSprite->SetTransparency( kRenderGlow, (int)pev->rendercolor.x, (int)pev->rendercolor.y, (int)pev->rendercolor.z, (int)pev->renderamt, (int)pev->renderfx ); if( pev->targetname && !( pev->spawnflags & SF_BEAM_STARTON ) ) TurnOff(); @@ -1619,7 +1619,7 @@ void CTestEffect::TestThink( void ) for( i = 0; i < m_iBeam; i++ ) { t = ( gpGlobals->time - m_flBeamTime[i] ) / ( 3 + m_flStartTime - m_flBeamTime[i] ); - m_pBeam[i]->SetBrightness( 255 * t ); + m_pBeam[i]->SetBrightness( (int)( 255 * t ) ); // m_pBeam[i]->SetScrollRate( 20 * t ); } pev->nextthink = gpGlobals->time + 0.1; @@ -1749,9 +1749,9 @@ Vector CBlood::BloodPosition( CBaseEntity *pActivator ) 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(), BloodAmount() ); + UTIL_BloodStream( BloodPosition( pActivator ), Direction(), ( Color() == BLOOD_COLOR_RED ) ? 70 : Color(), (int)BloodAmount() ); else - UTIL_BloodDrips( BloodPosition( pActivator ), Direction(), Color(), BloodAmount() ); + UTIL_BloodDrips( BloodPosition( pActivator ), Direction(), Color(), (int)BloodAmount() ); if( pev->spawnflags & SF_BLOOD_DECAL ) { @@ -1947,12 +1947,12 @@ void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType { if( pActivator->IsNetClient() ) { - UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); + UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), (int)pev->renderamt, fadeFlags ); } } else { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags ); + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), (int)pev->renderamt, fadeFlags ); } SUB_UseTargets( this, USE_TOGGLE, 0 ); } diff --git a/dlls/effects.h b/dlls/effects.h index 031b8273..68f0ea29 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -238,7 +238,7 @@ public: inline int GetWidth( void ) { - return pev->scale; + return (int)pev->scale; } inline int GetNoise( void ) @@ -255,17 +255,17 @@ public: inline int GetBrightness( void ) { - return pev->renderamt; + return (int)pev->renderamt; } inline int GetFrame( void ) { - return pev->frame; + return (int)pev->frame; } inline int GetScrollRate( void ) { - return pev->animtime; + return (int)pev->animtime; } // Call after you change start/end positions diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 433704ce..9a4de49b 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -270,7 +270,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) } } #endif - float timedist; + float timedist = 0.0f; switch( m_fireMode ) { @@ -380,13 +380,13 @@ void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, floa } m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( 255 - ( timeBlend * 180 ) ); - m_pBeam->SetWidth( 40 - ( timeBlend * 20 ) ); + m_pBeam->SetBrightness( (int)( 255 - ( timeBlend * 180 )) ); + m_pBeam->SetWidth( (int)( 40 - ( timeBlend * 20 ) ) ); if( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + ( 25 * timeBlend ), 30 + ( 30 * timeBlend ), 64 + 80 * fabs( sin( gpGlobals->time * 10 ) ) ); + m_pBeam->SetColor( (int)( 30 + ( 25 * timeBlend ) ), (int)( 30 + ( 30 * timeBlend ) ), (int)( 64 + 80 * fabs( sin( gpGlobals->time * 10 ) ) ) ); else - m_pBeam->SetColor( 60 + ( 25 * timeBlend ), 120 + ( 30 * timeBlend ), 64 + 80 * fabs( sin( gpGlobals->time *10 ) ) ); + m_pBeam->SetColor( (int)( 60 + ( 25 * timeBlend ) ), (int)( 120 + ( 30 * timeBlend ) ), (int)( 64 + 80 * fabs( sin( gpGlobals->time *10 ) ) ) ); UTIL_SetOrigin( m_pSprite->pev, endPoint ); m_pSprite->pev->frame += 8 * gpGlobals->frametime; diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index 1c5ec1b2..9bef0d48 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -14,10 +14,18 @@ ****/ #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; diff --git a/dlls/extdll.h b/dlls/extdll.h index 58349e32..ea176aab 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -25,11 +25,13 @@ #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 +#endif // Prevent tons of unused windows definitions #ifdef _WIN32 @@ -42,8 +44,12 @@ #include "windows.h" #undef HSPRITE #else // _WIN32 +#ifndef FALSE #define FALSE 0 +#endif +#ifndef TRUE #define TRUE (!FALSE) +#endif typedef unsigned int ULONG; typedef unsigned char BYTE; typedef int BOOL; diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 38b05f7b..6abf1b44 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -104,7 +104,7 @@ void CBreakable::KeyValue( KeyValueData* pkvd ) else if( FStrEq( pkvd->szKeyName, "spawnobject" ) ) { int object = atoi( pkvd->szValue ); - if( object > 0 && object < ARRAYSIZE( pSpawnObjects ) ) + if( object > 0 && object < (int)ARRAYSIZE( pSpawnObjects ) ) m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); pkvd->fHandled = TRUE; } @@ -353,7 +353,7 @@ void CBreakable::DamageSound( void ) { int pitch; float fvol; - char *rgpsz[6]; + const char *rgpsz[6]; int i = 0; int material = m_Material; @@ -574,7 +574,6 @@ void CBreakable::Die( void ) { Vector vecSpot;// shard origin Vector vecVelocity;// shard velocity - CBaseEntity *pEntity = NULL; char cFlag = 0; int pitch; float fvol; @@ -794,7 +793,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; - static char *m_soundNames[3]; + 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; @@ -810,7 +809,7 @@ IMPLEMENT_SAVERESTORE( CPushable, CBreakable ) LINK_ENTITY_TO_CLASS( func_pushable, CPushable ) -char *CPushable::m_soundNames[3] = +const char *CPushable::m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", @@ -839,7 +838,7 @@ void CPushable::Spawn( void ) UTIL_SetOrigin( pev, pev->origin ); // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = ( pev->skin * ( pev->maxs.x - pev->mins.x ) * ( pev->maxs.y - pev->mins.y ) ) * 0.0005; + pev->skin = (int)( ( pev->skin * ( pev->maxs.x - pev->mins.x ) * ( pev->maxs.y - pev->mins.y ) ) * 0.0005 ); m_soundTime = 0; } @@ -882,7 +881,7 @@ void CPushable::KeyValue( KeyValueData *pkvd ) } else if( FStrEq( pkvd->szKeyName, "buoyancy" ) ) { - pev->skin = atof( pkvd->szValue ); + pev->skin = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index eab9e621..ab295e0c 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -190,7 +190,7 @@ void CFuncTank::Spawn( void ) if( m_fireRate <= 0 ) m_fireRate = 1; - if( m_spread > MAX_FIRING_SPREADS ) + if( m_spread > (int)MAX_FIRING_SPREADS ) m_spread = 0; pev->oldorigin = pev->origin; @@ -328,7 +328,7 @@ BOOL CFuncTank::OnControls( entvars_t *pevTest ) if( !( pev->spawnflags & SF_TANK_CANCONTROL ) ) return FALSE; - Vector offset = pevTest->origin - pev->origin; + //Vector offset = pevTest->origin - pev->origin; if( ( m_vecControllerUsePos - pevTest->origin ).Length() < 30 ) return TRUE; @@ -476,9 +476,9 @@ void CFuncTank::TrackTarget( void ) { TraceResult tr; edict_t *pPlayer = FIND_CLIENT_IN_PVS( edict() ); - BOOL updateTime = FALSE, lineOfSight; + BOOL updateTime = FALSE; Vector angles, direction, targetPosition, barrelEnd; - edict_t *pTarget; + edict_t *pTarget = NULL; // Get a position to aim for if( m_pController ) @@ -515,12 +515,8 @@ void CFuncTank::TrackTarget( void ) UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - lineOfSight = FALSE; - // No line of sight, don't track if( tr.flFraction == 1.0 || tr.pHit == pTarget ) { - lineOfSight = TRUE; - CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); if( InRange( range ) && pInstance && pInstance->IsAlive() ) { @@ -644,7 +640,7 @@ void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t { CSprite *pSprite = CSprite::SpriteCreate( STRING( m_iszSpriteSmoke ), barrelEnd, TRUE ); pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); - pSprite->SetTransparency( kRenderTransAlpha, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, 255, kRenderFxNone ); + pSprite->SetTransparency( kRenderTransAlpha, (int)pev->rendercolor.x, (int)pev->rendercolor.y, (int)pev->rendercolor.z, 255, kRenderFxNone ); pSprite->pev->velocity.z = RANDOM_FLOAT( 40, 80 ); pSprite->SetScale( m_spriteScale ); } @@ -714,7 +710,7 @@ void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars // FireBullets needs gpGlobals->v_up, etc. UTIL_MakeAimVectors( pev->angles ); - int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + int bulletCount = (int)( ( gpGlobals->time - m_fireLast ) * m_fireRate ); if( bulletCount > 0 ) { for( i = 0; i < bulletCount; i++ ) @@ -835,7 +831,7 @@ void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entva // TankTrace needs gpGlobals->v_up, etc. UTIL_MakeAimVectors( pev->angles ); - int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + int bulletCount = (int)( ( gpGlobals->time - m_fireLast ) * m_fireRate ); if( bulletCount ) { for( i = 0; i < bulletCount; i++ ) @@ -879,12 +875,12 @@ void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entv if( m_fireLast != 0 ) { - int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + int bulletCount = (int)( ( gpGlobals->time - m_fireLast ) * m_fireRate ); if( bulletCount > 0 ) { for( i = 0; i < bulletCount; i++ ) { - CBaseEntity *pRocket = CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); + CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); } CFuncTank::Fire( barrelEnd, forward, pev ); } @@ -917,7 +913,7 @@ void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entv { if( m_fireLast != 0 ) { - int bulletCount = ( gpGlobals->time - m_fireLast ) * m_fireRate; + int bulletCount = (int)( ( gpGlobals->time - m_fireLast ) * m_fireRate ); // Only create 1 explosion if( bulletCount > 0 ) { diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index 6c65b06f..7f60b401 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -538,7 +538,6 @@ void CGargantua::FlameControls( float angleX, float angleY ) void CGargantua::FlameUpdate( void ) { int i; - static float offset[2] = { 60, -60 }; TraceResult trace; Vector vecStart, angleGun; BOOL streaks = FALSE; @@ -759,7 +758,7 @@ void CGargantua::Spawn() //========================================================= void CGargantua::Precache() { - int i; + size_t i; PRECACHE_MODEL( "models/garg.mdl" ); PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 10149202..93352b57 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -259,7 +259,7 @@ void CGauss::SecondaryAttack() m_pPlayer->m_flNextAmmoBurn = 1000; } - int pitch = ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; + int pitch = (int)( ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100 ); if( pitch > 250 ) pitch = 250; @@ -359,11 +359,11 @@ void CGauss::StartFire( void ) 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; edict_t *pentIgnore; - TraceResult tr, beam_tr; float flMaxFrac = 1.0; int nTotal = 0; int fHasPunched = 0; @@ -371,8 +371,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) int nMaxHits = 10; pentIgnore = ENT( m_pPlayer->pev ); - -#ifdef CLIENT_DLL +#else if( m_fPrimaryFire == false ) g_irunninggausspred = true; #endif diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index c40bb802..23622120 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -88,7 +88,7 @@ void CGenericMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= int CGenericMonster::ISoundMask( void ) { - return NULL; + return 0; } //========================================================= diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 64d9f3cf..0ca516c4 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -49,7 +49,7 @@ void CGrenade::Explode( Vector vecSrc, Vector vecAim ) // UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) { - float flRndSound;// sound randomizer + // float flRndSound;// sound randomizer pev->model = iStringNull;//invisible pev->solid = SOLID_NOT;// intangible @@ -102,7 +102,7 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); } - flRndSound = RANDOM_FLOAT( 0, 1 ); + //flRndSound = RANDOM_FLOAT( 0, 1 ); switch( RANDOM_LONG( 0, 2 ) ) { @@ -144,8 +144,8 @@ void CGrenade::Smoke( void ) WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( ( pev->dmg - 50 ) * 0.80 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate + WRITE_BYTE( (int)( ( pev->dmg - 50 ) * 0.80 ) ); // scale * 10 + WRITE_BYTE( 12 ); // framerate MESSAGE_END(); } UTIL_Remove( this ); @@ -165,7 +165,7 @@ void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T void CGrenade::PreDetonate( void ) { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); + CSoundEnt::InsertSound( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); SetThink( &CGrenade::Detonate ); pev->nextthink = gpGlobals->time + 1; @@ -207,7 +207,7 @@ void CGrenade::DangerSoundThink( void ) return; } - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length(), 0.2 ); + CSoundEnt::InsertSound( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, (int)pev->velocity.Length(), 0.2 ); pev->nextthink = gpGlobals->time + 0.2; if( pev->waterlevel != 0 ) @@ -253,7 +253,7 @@ void CGrenade::BounceTouch( CBaseEntity *pOther ) // 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, pev->dmg / 0.4, 0.3 ); + CSoundEnt::InsertSound( bits_SOUND_DANGER, pev->origin, (int)( pev->dmg / 0.4 ), 0.3 ); m_fRegisteredSound = TRUE; } diff --git a/dlls/gman.cpp b/dlls/gman.cpp index bdfb60d4..377755f6 100644 --- a/dlls/gman.cpp +++ b/dlls/gman.cpp @@ -109,7 +109,7 @@ void CGMan::HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= int CGMan::ISoundMask( void ) { - return NULL; + return 0; } //========================================================= @@ -149,7 +149,7 @@ void CGMan::StartTask( Task_t *pTask ) switch( pTask->iTask ) { case TASK_WAIT: - if( m_hPlayer == NULL ) + if( m_hPlayer == 0 ) { m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); } @@ -164,7 +164,7 @@ void CGMan::RunTask( Task_t *pTask ) { case TASK_WAIT: // look at who I'm talking to - if( m_flTalkTime > gpGlobals->time && m_hTalkTarget != NULL ) + if( m_flTalkTime > gpGlobals->time && m_hTalkTarget != 0 ) { float yaw = VecToYaw( m_hTalkTarget->pev->origin - pev->origin ) - pev->angles.y; @@ -177,7 +177,7 @@ void CGMan::RunTask( Task_t *pTask ) SetBoneController( 0, yaw ); } // look at player, but only if playing a "safe" idle animation - else if( m_hPlayer != NULL && pev->sequence == 0 ) + else if( m_hPlayer != 0 && pev->sequence == 0 ) { float yaw = VecToYaw( m_hPlayer->pev->origin - pev->origin ) - pev->angles.y; diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index fdb7c645..976a5733 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -91,7 +91,7 @@ void CRecharge::Spawn() 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 = gSkillData.suitchargerCapacity; + m_iJuice = (int)gSkillData.suitchargerCapacity; pev->frame = 0; } @@ -172,7 +172,7 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use void CRecharge::Recharge( void ) { - m_iJuice = gSkillData.suitchargerCapacity; + m_iJuice = (int)gSkillData.suitchargerCapacity; pev->frame = 0; SetThink( &CBaseEntity::SUB_DoNothing ); } @@ -185,7 +185,7 @@ void CRecharge::Off( void ) m_iOn = 0; - if( ( !m_iJuice ) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0 ) ) + if( ( !m_iJuice ) && ( ( m_iReactivate = (int)g_pGameRules->FlHEVChargerRechargeTime() ) > 0 ) ) { pev->nextthink = pev->ltime + m_iReactivate; SetThink( &CRecharge::Recharge ); diff --git a/dlls/h_cine.cpp b/dlls/h_cine.cpp index fc503171..bb07e02c 100644 --- a/dlls/h_cine.cpp +++ b/dlls/h_cine.cpp @@ -31,7 +31,7 @@ class CLegacyCineMonster : public CBaseMonster { public: - void CineSpawn( char *szModel ); + void CineSpawn( const char *szModel ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT CineThink( void ); void Pain( void ); @@ -103,7 +103,7 @@ LINK_ENTITY_TO_CLASS( monster_cine3_barney, CCine3Barney ) // ********** Scientist SPAWN ********** // -void CLegacyCineMonster :: CineSpawn( char *szModel ) +void CLegacyCineMonster :: CineSpawn( const char *szModel ) { PRECACHE_MODEL(szModel); SET_MODEL(ENT(pev), szModel); diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index d685ac36..e920abfa 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -34,7 +34,7 @@ class CCycler : public CBaseMonster { public: - void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax); + 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 ); @@ -92,7 +92,7 @@ void CCyclerProbe::Spawn( void ) } // Cycler member functions -void CCycler::GenericCyclerSpawn( char *szModel, Vector vecMin, Vector vecMax ) +void CCycler::GenericCyclerSpawn( const char *szModel, Vector vecMin, Vector vecMax ) { if( !szModel || !*szModel ) { @@ -406,7 +406,7 @@ void CWreckage::Spawn( void ) } // pev->scale = 5.0; - m_flStartTime = gpGlobals->time; + m_flStartTime = (int)gpGlobals->time; } void CWreckage::Precache() diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index 5aac1e53..ff053595 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -185,7 +185,7 @@ void CHAssassin::SetYawSpeed( void ) //========================================================= void CHAssassin::Shoot( void ) { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { return; } @@ -597,7 +597,7 @@ IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ) //========================================================= BOOL CHAssassin::CheckMeleeAttack1( float flDot, float flDist ) { - if( m_flNextJump < gpGlobals->time && ( flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP ) ) && m_hEnemy != NULL ) + if( m_flNextJump < gpGlobals->time && ( flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP ) ) && m_hEnemy != 0 ) { TraceResult tr; @@ -687,7 +687,7 @@ void CHAssassin::RunAI( void ) // always visible if moving // always visible is not on hard - if( g_iSkillLevel != SKILL_HARD || m_hEnemy == NULL || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !( pev->flags & FL_ONGROUND ) ) + 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; diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index d84a692e..60e03c10 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -226,7 +226,7 @@ void CHeadCrab::HandleAnimEvent( MonsterEvent_t *pEvent ) UTIL_MakeVectors( pev->angles ); Vector vecJumpDir; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { float gravity = g_psv_gravity->value; if( gravity <= 1 ) @@ -538,7 +538,7 @@ Schedule_t *CBabyCrab::GetScheduleOfType( int Type ) switch( Type ) { case SCHED_FAIL: // If you fail, try to jump! - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) return slHCRangeAttack1Fast; break; case SCHED_RANGE_ATTACK1: diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index e1b22467..99d53d35 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -159,7 +159,7 @@ void CWallHealth::Spawn() 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 = gSkillData.healthchargerCapacity; + m_iJuice = (int)gSkillData.healthchargerCapacity; pev->frame = 0; } @@ -230,7 +230,7 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u void CWallHealth::Recharge( void ) { EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); - m_iJuice = gSkillData.healthchargerCapacity; + m_iJuice = (int)gSkillData.healthchargerCapacity; pev->frame = 0; SetThink( &CBaseEntity::SUB_DoNothing ); } @@ -243,7 +243,7 @@ void CWallHealth::Off( void ) m_iOn = 0; - if( ( !m_iJuice ) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0 ) ) + if( ( !m_iJuice ) && ( ( m_iReactivate = (int)g_pGameRules->FlHealthChargerRechargeTime() ) > 0 ) ) { pev->nextthink = pev->ltime + m_iReactivate; SetThink( &CWallHealth::Recharge ); diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 7b0eaa2c..4cb85c2c 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -217,7 +217,7 @@ const char *CHGrunt::pGruntSentences[] = "HG_TAUNT", // say rude things }; -enum +typedef enum { HGRUNT_SENT_NONE = -1, HGRUNT_SENT_GREN = 0, @@ -366,7 +366,7 @@ void CHGrunt::JustSpoke( void ) //========================================================= void CHGrunt::PrescheduleThink( void ) { - if( InSquad() && m_hEnemy != NULL ) + if( InSquad() && m_hEnemy != 0 ) { if( HasConditions( bits_COND_SEE_ENEMY ) ) { @@ -413,9 +413,9 @@ BOOL CHGrunt::FCanCheckAttacks( void ) //========================================================= BOOL CHGrunt::CheckMeleeAttack1( float flDot, float flDist ) { - CBaseMonster *pEnemy; + CBaseMonster *pEnemy = 0; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { pEnemy = m_hEnemy->MyMonsterPointer(); @@ -787,7 +787,7 @@ Vector CHGrunt::GetGunPosition() //========================================================= void CHGrunt::Shoot( void ) { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { return; } @@ -814,7 +814,7 @@ void CHGrunt::Shoot( void ) //========================================================= void CHGrunt::Shotgun( void ) { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { return; } @@ -1834,7 +1834,7 @@ IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ) void CHGrunt::SetActivity( Activity NewActivity ) { int iSequence = ACTIVITY_NOT_AVAILABLE; - void *pmodel = GET_MODEL_PTR( ENT( pev ) ); + //void *pmodel = GET_MODEL_PTR( ENT( pev ) ); switch( NewActivity ) { @@ -2032,10 +2032,10 @@ Schedule_t *CHGrunt::GetSchedule( void ) // before he starts pluggin away. if( FOkToSpeak() )// && RANDOM_LONG( 0, 1 ) ) { - if( ( m_hEnemy != NULL ) && m_hEnemy->IsPlayer() ) + 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 != NULL ) && + else if( ( m_hEnemy != 0 ) && ( m_hEnemy->Classify() != CLASS_PLAYER_ALLY ) && ( m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE ) && ( m_hEnemy->Classify() != CLASS_MACHINE ) ) @@ -2072,7 +2072,7 @@ Schedule_t *CHGrunt::GetSchedule( void ) // 10% chance of flinch. int iPercent = RANDOM_LONG( 0, 99 ); - if( iPercent <= 90 && m_hEnemy != NULL ) + if( iPercent <= 90 && m_hEnemy != 0 ) { // only try to take cover if we actually have an enemy! @@ -2308,7 +2308,7 @@ Schedule_t *CHGrunt::GetScheduleOfType( int Type ) } case SCHED_FAIL: { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // grunt has an enemy, so pick a different default fail schedule most likely to help recover. return &slGruntCombatFail[0]; @@ -2408,10 +2408,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; + static const char *m_szPoses[3]; }; -char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; +const char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) { diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index 1e7025a0..d968b79b 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -258,14 +258,14 @@ void CHornet::TrackTarget( void ) } // UNDONE: The player pointer should come back after returning from another level - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { // enemy is dead. Look( 512 ); m_hEnemy = BestVisibleEnemy(); } - if( m_hEnemy != NULL && FVisible( m_hEnemy ) ) + if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) { m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); } @@ -335,7 +335,7 @@ void CHornet::TrackTarget( void ) // 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 != NULL && !g_pGameRules->IsMultiplayer() ) + if( m_hEnemy != 0 && !g_pGameRules->IsMultiplayer() ) { if( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) { diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index f35b0740..cedee258 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -137,7 +137,7 @@ int CHoundeye::Classify( void ) //========================================================= BOOL CHoundeye::FValidateHintType( short sHint ) { - int i; + size_t i; static short sHoundHints[] = { diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index cbc86d50..53f57a27 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -416,7 +416,7 @@ void CIchthyosaur::HandleAnimEvent( MonsterEvent_t *pEvent ) case ICHTHYOSAUR_AE_SHAKE_RIGHT: case ICHTHYOSAUR_AE_SHAKE_LEFT: { - if( m_hEnemy != NULL && FVisible( m_hEnemy ) ) + if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) { CBaseEntity *pHurt = m_hEnemy; @@ -622,7 +622,7 @@ void CIchthyosaur::RunTask( Task_t *pTask ) switch( pTask->iTask ) { case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { TaskComplete(); } @@ -864,7 +864,7 @@ void CIchthyosaur::Stop( void ) void CIchthyosaur::Swim() { - int retValue = 0; + //int retValue = 0; Vector start = pev->origin; @@ -1072,7 +1072,7 @@ Vector CIchthyosaur::DoProbe( const Vector &Probe ) } } - if( bBumpedSomething && ( m_hEnemy == NULL || tr.pHit != m_hEnemy->edict() ) ) + if( bBumpedSomething && ( m_hEnemy == 0 || tr.pHit != m_hEnemy->edict() ) ) { Vector ProbeDir = Probe - pev->origin; diff --git a/dlls/islave.cpp b/dlls/islave.cpp index cfb1df1b..3b4343d3 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -51,7 +51,7 @@ public: void HandleAnimEvent( MonsterEvent_t *pEvent ); BOOL CheckRangeAttack1( float flDot, float flDist ); BOOL CheckRangeAttack2( float flDot, float flDist ); - void CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ); + 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 ); @@ -155,7 +155,7 @@ int CISlave::IRelationship( CBaseEntity *pTarget ) return CBaseMonster::IRelationship( pTarget ); } -void CISlave::CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) +void CISlave::CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) { // ALERT( at_aiconsole, "help " ); @@ -185,7 +185,7 @@ void CISlave::CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vect //========================================================= void CISlave::AlertSound( void ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { SENTENCEG_PlayRndSz( ENT( pev ), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch ); @@ -365,7 +365,7 @@ void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent ) WRITE_BYTE( 0 ); // decay * 0.1 MESSAGE_END(); } - if( m_hDead != NULL ) + if( m_hDead != 0 ) { WackBeam( -1, m_hDead ); WackBeam( 1, m_hDead ); @@ -385,7 +385,7 @@ void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent ) { ClearBeams(); - if( m_hDead != NULL ) + if( m_hDead != 0 ) { Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); TraceResult trace; @@ -394,7 +394,7 @@ void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent ) if( !trace.fStartSolid ) { CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); - CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); + //CBaseMonster *pNewMonster = pNew->MyMonsterPointer(); pNew->pev->spawnflags |= 1; WackBeam( -1, pNew ); WackBeam( 1, pNew ); @@ -484,7 +484,7 @@ BOOL CISlave::CheckRangeAttack2( float flDot, float flDist ) } } } - if( m_hDead != NULL ) + if( m_hDead != 0 ) return TRUE; else return FALSE; @@ -530,7 +530,7 @@ void CISlave::Spawn() //========================================================= void CISlave::Precache() { - int i; + size_t i; PRECACHE_MODEL( "models/islave.mdl" ); PRECACHE_MODEL( "sprites/lgtning.spr" ); @@ -756,8 +756,8 @@ void CISlave::BeamGlow() //========================================================= void CISlave::WackBeam( int side, CBaseEntity *pEntity ) { - Vector vecDest; - float flDist = 1.0; + //Vector vecDest; + //float flDist = 1.0; if( m_iBeams >= ISLAVE_MAX_BEAMS ) return; diff --git a/dlls/leech.cpp b/dlls/leech.cpp index ea524aaa..dccffcf4 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -271,7 +271,7 @@ void CLeech::AlertSound( void ) void CLeech::Precache( void ) { - int i; + size_t i; //PRECACHE_MODEL( "models/icky.mdl" ); PRECACHE_MODEL( "models/leech.mdl" ); diff --git a/dlls/lights.cpp b/dlls/lights.cpp index 2a8b0683..e6b03125 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -99,7 +99,7 @@ void CLight::Spawn( void ) if( FBitSet( pev->spawnflags, SF_LIGHT_START_OFF ) ) LIGHT_STYLE( m_iStyle, "a" ); else if( m_iszPattern ) - LIGHT_STYLE( m_iStyle, (char *)STRING( m_iszPattern ) ); + LIGHT_STYLE( m_iStyle, STRING( m_iszPattern ) ); else LIGHT_STYLE( m_iStyle, "m" ); } @@ -115,7 +115,7 @@ void CLight::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTyp if( FBitSet( pev->spawnflags, SF_LIGHT_START_OFF ) ) { if( m_iszPattern ) - LIGHT_STYLE( m_iStyle, (char *)STRING( m_iszPattern ) ); + LIGHT_STYLE( m_iStyle, STRING( m_iszPattern ) ); else LIGHT_STYLE( m_iStyle, "m" ); ClearBits( pev->spawnflags, SF_LIGHT_START_OFF ); @@ -155,15 +155,16 @@ void CEnvLight::KeyValue( KeyValueData* pkvd ) } else if( j == 4 ) { - r = r * ( v / 255.0 ); - g = g * ( v / 255.0 ); - b = b * ( v / 255.0 ); + v /= 255; + r *= v; + g *= v; + b *= v; } // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling - r = pow( r / 114.0, 0.6 ) * 264; - g = pow( g / 114.0, 0.6 ) * 264; - b = pow( b / 114.0, 0.6 ) * 264; + r = (int)( pow( r / 114.0, 0.6 ) * 264.0 ); + g = (int)( pow( g / 114.0, 0.6 ) * 264.0 ); + b = (int)( pow( b / 114.0, 0.6 ) * 264.0 ); pkvd->fHandled = TRUE; sprintf( szColor, "%d", r ); diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index 3eea7486..2230acac 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -64,9 +64,9 @@ void CRuleEntity::Spawn( void ) void CRuleEntity::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "master")) + if( FStrEq(pkvd->szKeyName, "master" ) ) { - SetMaster( ALLOC_STRING(pkvd->szValue) ); + SetMaster( ALLOC_STRING( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else @@ -75,9 +75,9 @@ void CRuleEntity::KeyValue( KeyValueData *pkvd ) BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) { - if ( m_iszMaster ) + if( m_iszMaster ) { - if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) + if( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) return TRUE; else return FALSE; @@ -135,7 +135,7 @@ public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void KeyValue( KeyValueData *pkvd ); - inline int Points( void ) { return pev->frags; } + inline int Points( void ) { return (int)pev->frags; } inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } @@ -643,8 +643,8 @@ public: 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 pev->frags; } - inline int LimitValue( void ) { return pev->health; } + inline int CountValue( void ) { return (int)pev->frags; } + inline int LimitValue( void ) { return (int)pev->health; } inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index d034abd6..cfe4c561 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -133,7 +133,7 @@ int CBaseMonster::Restore( CRestore &restore ) m_Activity = ACT_RESET; // If we don't have an enemy, clear conditions like see enemy, etc. - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) m_afConditions = 0; return status; @@ -672,7 +672,7 @@ BOOL CBaseMonster::FRefreshRoute( void ) returnCode = BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, NULL ); break; case MOVEGOAL_TARGETENT: - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); } @@ -954,7 +954,7 @@ BOOL CBaseMonster::CheckRangeAttack2( float flDot, float flDist ) 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 != NULL && FBitSet( m_hEnemy->pev->flags, FL_ONGROUND ) ) + if( flDist <= 64 && flDot >= 0.7 && m_hEnemy != 0 && FBitSet( m_hEnemy->pev->flags, FL_ONGROUND ) ) { return TRUE; } @@ -1165,7 +1165,7 @@ void CBaseMonster::PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { if( m_hOldEnemy[i] == pEnemy ) return; - if( m_hOldEnemy[i] == NULL ) // someone died, reuse their slot + if( m_hOldEnemy[i] == 0 ) // someone died, reuse their slot break; } if( i >= MAX_OLD_ENEMIES ) @@ -1183,7 +1183,7 @@ 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] != NULL ) + if( m_hOldEnemy[i] != 0 ) { if( m_hOldEnemy[i]->IsAlive()) // cheat and know when they die { @@ -1240,7 +1240,7 @@ void CBaseMonster::SetActivity( Activity NewActivity ) //========================================================= // SetSequenceByName //========================================================= -void CBaseMonster::SetSequenceByName( char *szSequence ) +void CBaseMonster::SetSequenceByName( const char *szSequence ) { int iSequence; @@ -2863,7 +2863,7 @@ void CBaseMonster::ReportAIState( void ) else ALERT( level, "No Schedule, " ); - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) ALERT( level, "\nEnemy is %s", STRING( m_hEnemy->pev->classname ) ); else ALERT( level, "No enemy" ); @@ -2950,7 +2950,7 @@ BOOL CBaseMonster::FCheckAITrigger( void ) switch( m_iTriggerCondition ) { case AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER: - if( m_hEnemy != NULL && m_hEnemy->IsPlayer() && HasConditions( bits_COND_SEE_ENEMY ) ) + if( m_hEnemy != 0 && m_hEnemy->IsPlayer() && HasConditions( bits_COND_SEE_ENEMY ) ) { fFireTarget = TRUE; } @@ -3321,7 +3321,7 @@ BOOL CBaseMonster::GetEnemy( void ) } // remember old enemies - if( m_hEnemy == NULL && PopEnemy() ) + if( m_hEnemy == 0 && PopEnemy() ) { if( m_pSchedule ) { @@ -3332,7 +3332,7 @@ BOOL CBaseMonster::GetEnemy( void ) } } - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { // monster has an enemy. return TRUE; @@ -3344,7 +3344,7 @@ BOOL CBaseMonster::GetEnemy( void ) //========================================================= // DropItem - dead monster drops named item //========================================================= -CBaseEntity *CBaseMonster::DropItem( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) +CBaseEntity *CBaseMonster::DropItem( const char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { if( !pszItemName ) { diff --git a/dlls/monsterstate.cpp b/dlls/monsterstate.cpp index f29664dc..cec29b79 100644 --- a/dlls/monsterstate.cpp +++ b/dlls/monsterstate.cpp @@ -42,7 +42,7 @@ void CBaseMonster::SetState( MONSTERSTATE State ) // Drop enemy pointers when going to idle case MONSTERSTATE_IDLE: - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { m_hEnemy = NULL;// not allowed to have an enemy anymore. ALERT( at_aiconsole, "Stripped\n" ); @@ -92,7 +92,7 @@ void CBaseMonster::RunAI( void ) } // do these calculations if monster has an enemy. - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { CheckEnemy( m_hEnemy ); } @@ -198,7 +198,7 @@ MONSTERSTATE CBaseMonster::GetIdealState( void ) COMBAT goes to ALERT upon death of enemy */ { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { m_IdealMonsterState = MONSTERSTATE_ALERT; // pev->effects = EF_BRIGHTFIELD; diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index 703a4dba..12b3a82f 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -230,7 +230,7 @@ CBaseEntity *CBaseMonster::BestVisibleEnemy( void ) // 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(); + (int)iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); pReturn = pNextEnt; } else if( IRelationship( pNextEnt ) == iBestRelationship ) @@ -238,7 +238,7 @@ CBaseEntity *CBaseMonster::BestVisibleEnemy( void ) // 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(); + (int)iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); if( iDist <= iNearest ) { diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index ebef51de..9da8d0b4 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -256,7 +256,7 @@ void CHalfLifeMultiplay::Think( void ) if( pPlayer ) { - remain = flFragLimit - pPlayer->pev->frags; + remain = (int)( flFragLimit - pPlayer->pev->frags ); if( remain < bestfrags ) { bestfrags = remain; @@ -300,7 +300,7 @@ BOOL CHalfLifeMultiplay::IsDeathmatch( void ) //========================================================= BOOL CHalfLifeMultiplay::IsCoOp( void ) { - return gpGlobals->coop; + return gpGlobals->coop ? TRUE : FALSE; } //========================================================= @@ -467,7 +467,7 @@ void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) { MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); WRITE_BYTE( i ); // client number - WRITE_SHORT( plr->pev->frags ); + WRITE_SHORT( (int)plr->pev->frags ); WRITE_SHORT( plr->m_iDeaths ); WRITE_SHORT( 0 ); WRITE_SHORT( GetTeamIndex( plr->m_szTeamName ) + 1 ); @@ -652,7 +652,7 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, // killed scores MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); WRITE_BYTE( ENTINDEX(pVictim->edict()) ); - WRITE_SHORT( pVictim->pev->frags ); + WRITE_SHORT( (int)pVictim->pev->frags ); WRITE_SHORT( pVictim->m_iDeaths ); WRITE_SHORT( 0 ); WRITE_SHORT( GetTeamIndex( pVictim->m_szTeamName ) + 1 ); @@ -666,7 +666,7 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); WRITE_BYTE( ENTINDEX( PK->edict() ) ); - WRITE_SHORT( PK->pev->frags ); + WRITE_SHORT( (int)PK->pev->frags ); WRITE_SHORT( PK->m_iDeaths ); WRITE_SHORT( 0 ); WRITE_SHORT( GetTeamIndex( PK->m_szTeamName ) + 1 ); @@ -689,14 +689,14 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, 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 *Killer = CBaseEntity::Instance( pKiller ); + 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 - char *tau = "tau_cannon"; - char *gluon = "gluon gun"; + const char *tau = "tau_cannon"; + const char *gluon = "gluon gun"; if( pKiller->flags & FL_CLIENT ) { diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index ba1c6192..479a2b34 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -587,7 +587,7 @@ void CNihilanth::ShootBalls( void ) while( m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { Vector vecSrc, vecDir; CNihilanthHVR *pEntity; @@ -742,7 +742,7 @@ void CNihilanth::NextActivity() float flDist = ( m_posDesired - pev->origin ).Length(); float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); - if( m_hRecharger != NULL ) + if( m_hRecharger != 0 ) { // at we at power up yet? if( flDist < 128.0 ) @@ -767,23 +767,23 @@ void CNihilanth::NextActivity() return; } - if( m_hEnemy != NULL && !m_hEnemy->IsAlive() ) + if( m_hEnemy != 0 && !m_hEnemy->IsAlive() ) { - m_hEnemy = NULL; + m_hEnemy = 0; } if( m_flLastSeen + 15 < gpGlobals->time ) { - m_hEnemy = NULL; + m_hEnemy = 0; } - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { Look( 4096 ); m_hEnemy = BestVisibleEnemy(); } - if( m_hEnemy != NULL && m_irritation != 0 ) + if( m_hEnemy != 0 && m_irritation != 0 ) { if( m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0 ) { @@ -860,7 +860,7 @@ void CNihilanth::HuntThink( void ) } // look for current enemy - if( m_hEnemy != NULL && m_hRecharger == NULL ) + if( m_hEnemy != 0 && m_hRecharger == NULL ) { if( FVisible( m_hEnemy ) ) { @@ -928,7 +928,7 @@ void CNihilanth::Flight( void ) if( flDir < 0 ) flSpeed = -flSpeed; - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); + //float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); // sideways drag m_velocity.x = m_velocity.x * ( 1.0 - fabs( gpGlobals->v_right.x ) * 0.05 ); @@ -959,7 +959,7 @@ BOOL CNihilanth::AbsorbSphere( void ) { for( int i = 0; i < N_SPHERES; i++ ) { - if( m_hSphere[i] != NULL ) + if( m_hSphere[i] != 0 ) { CNihilanthHVR *pSphere = (CNihilanthHVR *)( (CBaseEntity *)m_hSphere[i] ); pSphere->AbsorbInit(); @@ -978,7 +978,7 @@ BOOL CNihilanth::EmitSphere( void ) for( int i = 0; i < N_SPHERES; i++ ) { - if( m_hSphere[i] != NULL ) + if( m_hSphere[i] != 0 ) { m_iActiveSpheres++; } @@ -1007,10 +1007,10 @@ void CNihilanth::TargetSphere( USE_TYPE useType, float value ) for( i = 0; i < N_SPHERES; i++ ) { - if( m_hSphere[i] != NULL ) + if( m_hSphere[i] != 0 ) { pSphere = m_hSphere[i]->MyMonsterPointer(); - if( pSphere->m_hEnemy == NULL ) + if( pSphere->m_hEnemy == 0 ) break; } } @@ -1141,7 +1141,7 @@ void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) case 4: // get a sphere { - if( m_hRecharger != NULL ) + if( m_hRecharger != 0 ) { if( !EmitSphere() ) { @@ -1340,7 +1340,7 @@ void CNihilanthHVR::HoverThink( void ) { pev->nextthink = gpGlobals->time + 0.1; - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); } @@ -1424,7 +1424,7 @@ void CNihilanthHVR::ZapThink( void ) pev->nextthink = gpGlobals->time + 0.05; // check world boundaries - if( m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) + 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 ); @@ -1561,7 +1561,7 @@ void CNihilanthHVR::TeleportThink( void ) pev->nextthink = gpGlobals->time + 0.1; // check world boundaries - if( m_hEnemy == NULL || !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 ) + 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 ); @@ -1573,10 +1573,10 @@ void CNihilanthHVR::TeleportThink( void ) STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); UTIL_Remove( this ); - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - if( m_hTouch != NULL && m_hEnemy != NULL ) + if( m_hTouch != 0 && m_hEnemy != NULL ) m_hTouch->Touch( m_hEnemy ); } else @@ -1630,10 +1630,10 @@ void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) if( pOther == pEnemy ) { - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - if( m_hTouch != NULL && pEnemy != NULL ) + if( m_hTouch != 0 && pEnemy != NULL ) m_hTouch->Touch( pEnemy ); } else @@ -1656,7 +1656,7 @@ void CNihilanthHVR::DissipateThink( void ) pev->renderamt -= 2; pev->scale += 0.1; - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); } diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index a97b6a80..68a1c267 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -214,7 +214,7 @@ entvars_t *CGraph::LinkEntForLink( CLink *pLink, CNode *pNode ) //========================================================= int CGraph::HandleLinkEnt( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ) { - edict_t *pentWorld; + //edict_t *pentWorld; CBaseEntity *pDoor; TraceResult tr; @@ -230,7 +230,7 @@ int CGraph::HandleLinkEnt( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODE ALERT( at_aiconsole, "dead path ent!\n" ); return TRUE; } - pentWorld = NULL; + //pentWorld = NULL; // func_door if( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) @@ -586,7 +586,7 @@ int CGraph::FindShortestPath( int *piPath, int iStart, int iDest, int iHull, int int iVisitNode; int iCurrentNode; int iNumPathNodes; - int iHullMask; + int iHullMask = 0; if( !m_fGraphPresent || !m_fGraphPointersSet ) { @@ -1665,10 +1665,10 @@ void CTestHull::BuildNodeGraph( void ) int iBadNode;// this is the node that caused graph generation to fail - int cMaxInitialLinks = 0; - int cMaxValidLinks = 0; + //int cMaxInitialLinks = 0; + //int cMaxValidLinks = 0; - int iPoolIndex = 0; + //int iPoolIndex = 0; int cPoolLinks;// number of links in the pool. Vector vecDirToCheckNode; @@ -2058,11 +2058,16 @@ void CTestHull::BuildNodeGraph( void ) 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: %d bytes\n", sizeof(CLink) * cPoolLinks ); + 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 ); diff --git a/dlls/nodes.h b/dlls/nodes.h index 27b890ed..2b582a6f 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -15,7 +15,8 @@ //========================================================= // nodes.h //========================================================= - +#ifndef NODES_H +#define NODES_H //========================================================= // DEFINE //========================================================= @@ -370,3 +371,4 @@ enum }; extern CGraph WorldGraph; +#endif // NODES_H diff --git a/dlls/observer.cpp b/dlls/observer.cpp index 0eda7490..f3fc54a0 100644 --- a/dlls/observer.cpp +++ b/dlls/observer.cpp @@ -35,7 +35,7 @@ void CBasePlayer::Observer_FindNextPlayer( bool bReverse ) else iStart = ENTINDEX( edict() ); int iCurrent = iStart; - m_hObserverTarget = NULL; + m_hObserverTarget = 0; int iDir = bReverse ? -1 : 1; do @@ -125,11 +125,11 @@ void CBasePlayer::Observer_CheckTarget() return; // try to find a traget if we have no current one - if( m_hObserverTarget == NULL ) + if( m_hObserverTarget == 0 ) { Observer_FindNextPlayer( false ); - if( m_hObserverTarget == NULL ) + if( m_hObserverTarget == 0 ) { // no target found at all @@ -166,7 +166,7 @@ void CBasePlayer::Observer_CheckTarget() void CBasePlayer::Observer_CheckProperties() { // try to find a traget if we have no current one - if( pev->iuser1 == OBS_IN_EYE && m_hObserverTarget != NULL ) + if( pev->iuser1 == OBS_IN_EYE && m_hObserverTarget != 0 ) { CBasePlayer* target = (CBasePlayer*)( UTIL_PlayerByIndex( ENTINDEX( m_hObserverTarget->edict() ) ) ); @@ -222,26 +222,26 @@ void CBasePlayer::Observer_SetMode( int iMode ) if( iMode < OBS_CHASE_LOCKED || iMode > OBS_MAP_CHASE ) iMode = OBS_IN_EYE; // now it is // verify observer target again - if( m_hObserverTarget != NULL ) + if( m_hObserverTarget != 0 ) { CBaseEntity *pEnt = m_hObserverTarget; if( ( pEnt == this ) || ( pEnt == NULL ) ) - m_hObserverTarget = NULL; + m_hObserverTarget = 0; else if( ( (CBasePlayer*)pEnt )->IsObserver() || ( pEnt->pev->effects & EF_NODRAW ) ) - m_hObserverTarget = NULL; + 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 == NULL ) ) + if( ( iMode != OBS_ROAMING ) && ( m_hObserverTarget == 0 ) ) { Observer_FindNextPlayer( false ); // if we didn't find a valid target switch to roaming - if( m_hObserverTarget == NULL ) + if( m_hObserverTarget == 0 ) { ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); pev->iuser1 = OBS_ROAMING; diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp index 95088d2b..6a421645 100644 --- a/dlls/osprey.cpp +++ b/dlls/osprey.cpp @@ -261,7 +261,7 @@ BOOL COsprey::HasDead() { for( int i = 0; i < m_iUnits; i++ ) { - if( m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive() ) + if( m_hGrunt[i] == 0 || !m_hGrunt[i]->IsAlive() ) { return TRUE; } @@ -285,9 +285,9 @@ CBaseMonster *COsprey::MakeGrunt( Vector vecSrc ) for( int i = 0; i < m_iUnits; i++ ) { - if( m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive() ) + if( m_hGrunt[i] == 0 || !m_hGrunt[i]->IsAlive() ) { - if( m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal ) + if( m_hGrunt[i] != 0 && m_hGrunt[i]->pev->rendermode == kRenderNormal ) { m_hGrunt[i]->SUB_StartFadeOut(); } @@ -319,7 +319,7 @@ void COsprey::HoverThink( void ) int i; for( i = 0; i < 4; i++ ) { - if( m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && !( m_hRepel[i]->pev->flags & FL_ONGROUND ) ) + if( m_hRepel[i] != 0 && m_hRepel[i]->pev->health > 0 && !( m_hRepel[i]->pev->flags & FL_ONGROUND ) ) { break; } diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 93fb22fe..8fecf684 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -82,12 +82,12 @@ void CBasePlatTrain::KeyValue( KeyValueData *pkvd ) } else if( FStrEq( pkvd->szKeyName, "movesnd" ) ) { - m_bMoveSnd = atof( pkvd->szValue ); + m_bMoveSnd = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "stopsnd" ) ) { - m_bStopSnd = atof( pkvd->szValue ); + m_bStopSnd = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "volume" ) ) @@ -1437,7 +1437,7 @@ void CFuncTrackTrain::Spawn( void ) pev->speed = 0; pev->velocity = g_vecZero; pev->avelocity = g_vecZero; - pev->impulse = m_speed; + pev->impulse = (int)m_speed; m_dir = 1; @@ -2212,7 +2212,7 @@ void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us { pev->takedamage = DAMAGE_AIM; m_hTargetEnt = GetNextTarget(); - if( m_hTargetEnt == NULL ) + if( m_hTargetEnt == 0 ) return; pev->health = pev->max_health; Next(); diff --git a/dlls/player.cpp b/dlls/player.cpp index 7d7363b5..51995acf 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -459,7 +459,7 @@ int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl } // keep track of amount of damage last sustained - m_lastDamageAmount = flDamage; + m_lastDamageAmount = (int)flDamage; // Armor. if( pev->armorvalue && !( bitsDamageType & ( DMG_FALL | DMG_DROWN ) ) )// armor doesn't protect against fall or drown damage! @@ -787,7 +787,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) m_pLastItem = NULL; - if( m_pTank != NULL ) + if( m_pTank != 0 ) { m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; @@ -847,7 +847,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - if( m_pTank != NULL ) + if( m_pTank != 0 ) { m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; @@ -1172,7 +1172,7 @@ void CBasePlayer::WaterMove() // track drowning damage, give it back when // player finally takes a breath - m_idrowndmg += pev->dmg; + m_idrowndmg += (int)pev->dmg; } } else @@ -1393,7 +1393,7 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) if( m_pActiveItem ) m_pActiveItem->Holster(); - if( m_pTank != NULL ) + if( m_pTank != 0 ) { m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; @@ -1468,7 +1468,7 @@ void CBasePlayer::PlayerUse( void ) // Hit Use on a train? if( m_afButtonPressed & IN_USE ) { - if( m_pTank != NULL ) + if( m_pTank != 0 ) { // Stop controlling the tank // TODO: Send HUD Update @@ -1491,7 +1491,7 @@ void CBasePlayer::PlayerUse( void ) 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( pTrain->pev->speed, pTrain->pev->impulse ); + m_iTrain = TrainSpeed( (int)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; @@ -1662,7 +1662,7 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) if( -score > pev->frags ) // Will this go negative? { - score = -pev->frags; // Sum will be 0 + score = (int)( -pev->frags ); // Sum will be 0 } } } @@ -1671,7 +1671,7 @@ void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); WRITE_BYTE( ENTINDEX( edict() ) ); - WRITE_SHORT( pev->frags ); + WRITE_SHORT( (int)pev->frags ); WRITE_SHORT( m_iDeaths ); WRITE_SHORT( 0 ); WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 ); @@ -1733,8 +1733,8 @@ void CBasePlayer::UpdateStatusBar() // allies and medics get to see the targets health if( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) { - newSBarState[SBAR_ID_TARGETHEALTH] = 100 * ( pEntity->pev->health / pEntity->pev->max_health ); - newSBarState[SBAR_ID_TARGETARMOR] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. + newSBarState[SBAR_ID_TARGETHEALTH] = (int)( 100 * ( pEntity->pev->health / pEntity->pev->max_health ) ); + newSBarState[SBAR_ID_TARGETARMOR] = (int)pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max. } m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; @@ -1899,7 +1899,7 @@ void CBasePlayer::PreThink( void ) if( vel ) { - m_iTrain = TrainSpeed( pTrain->pev->speed, pTrain->pev->impulse ); + m_iTrain = TrainSpeed( (int)pTrain->pev->speed, pTrain->pev->impulse ); m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; } } @@ -2010,7 +2010,7 @@ void CBasePlayer::CheckTimeBasedDamage() int i; BYTE bDuration = 0; - static float gtbdPrev = 0.0; + //static float gtbdPrev = 0.0; if( !( m_bitsDamageType & DMG_TIMEBASED ) ) return; @@ -2271,7 +2271,7 @@ void CBasePlayer::CheckSuitUpdate() // seconds, then we won't repeat playback of this word or sentence // for at least that number of seconds. -void CBasePlayer::SetSuitUpdate( char *name, int fgroup, int iNoRepeatTime ) +void CBasePlayer::SetSuitUpdate( const char *name, int fgroup, int iNoRepeatTime ) { int i; int isentence; @@ -2399,7 +2399,7 @@ void CBasePlayer::UpdatePlayerSound( void ) // is louder than his body/movement, use the weapon volume, else, use the body volume. if( FBitSet( pev->flags, FL_ONGROUND ) ) { - iBodyVolume = pev->velocity.Length(); + iBodyVolume = (int)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. @@ -2432,7 +2432,7 @@ void CBasePlayer::UpdatePlayerSound( void ) } // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while - m_iWeaponVolume -= 250 * gpGlobals->frametime; + m_iWeaponVolume -= (int)( 250 * gpGlobals->frametime ); if( m_iWeaponVolume < 0 ) { iVolume = 0; @@ -2450,7 +2450,7 @@ void CBasePlayer::UpdatePlayerSound( void ) } else if( iVolume > m_iTargetVolume ) { - iVolume -= 250 * gpGlobals->frametime; + iVolume -= (int)( 250 * gpGlobals->frametime ); if( iVolume < m_iTargetVolume ) { @@ -2479,7 +2479,7 @@ void CBasePlayer::UpdatePlayerSound( void ) } // keep track of virtual muzzle flash - m_iWeaponFlash -= 256 * gpGlobals->frametime; + m_iWeaponFlash -= (int)( 256 * gpGlobals->frametime ); if( m_iWeaponFlash < 0 ) m_iWeaponFlash = 0; @@ -2501,7 +2501,7 @@ void CBasePlayer::PostThink() goto pt_end; // Handle Tank controlling - if( m_pTank != NULL ) + 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 ) @@ -2565,7 +2565,7 @@ void CBasePlayer::PostThink() { if( m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer() ) { - CSoundEnt::InsertSound( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 ); + CSoundEnt::InsertSound( bits_SOUND_PLAYER, pev->origin, (int)m_flFallVelocity, 0.2 ); // ALERT( at_console, "fall %f\n", m_flFallVelocity ); } m_flFallVelocity = 0; @@ -3195,7 +3195,7 @@ void CSprayCan::Think( void ) } else { - UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE ); + UTIL_PlayerDecalTrace( &tr, playernum, (int)pev->frame, TRUE ); // Just painted last custom frame. if( pev->frame++ >= ( nFrames - 1 ) ) UTIL_Remove( this ); @@ -3682,7 +3682,7 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) // // Returns the unique ID for the ammo, or -1 if error // -int CBasePlayer::GiveAmmo( int iCount, char *szName, int iMax ) +int CBasePlayer::GiveAmmo( int iCount, const char *szName, int iMax ) { if( !szName ) { @@ -3756,10 +3756,10 @@ Called every frame by the player PostThink */ void CBasePlayer::ItemPostFrame() { - static int fInSelect = FALSE; + //static int fInSelect = FALSE; // check if the player is using a tank - if( m_pTank != NULL ) + if( m_pTank != 0 ) return; #if defined( CLIENT_WEAPONS ) @@ -3912,12 +3912,12 @@ void CBasePlayer::UpdateClientData( void ) WRITE_BYTE( iHealth ); MESSAGE_END(); - m_iClientHealth = pev->health; + m_iClientHealth = (int)pev->health; } if( pev->armorvalue != m_iClientBattery ) { - m_iClientBattery = pev->armorvalue; + m_iClientBattery = (int)pev->armorvalue; ASSERT( gmsgBattery > 0 ); @@ -3945,8 +3945,8 @@ void CBasePlayer::UpdateClientData( void ) int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; MESSAGE_BEGIN( MSG_ONE, gmsgDamage, NULL, pev ); - WRITE_BYTE( pev->dmg_save ); - WRITE_BYTE( pev->dmg_take ); + WRITE_BYTE( (int)pev->dmg_save ); + WRITE_BYTE( (int)pev->dmg_take ); WRITE_LONG( visibleDamageBits ); WRITE_COORD( damageOrigin.x ); WRITE_COORD( damageOrigin.y ); @@ -4211,8 +4211,8 @@ Vector CBasePlayer::GetAutoaimVector( float flDelta ) { SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - m_lastx = m_vecAutoAim.x; - m_lasty = m_vecAutoAim.y; + m_lastx = (int)m_vecAutoAim.x; + m_lasty = (int)m_vecAutoAim.y; } } @@ -4556,10 +4556,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[4]; + static const char *m_szPoses[4]; }; -char *CDeadHEV::m_szPoses[] = +const char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", @@ -4701,7 +4701,7 @@ void CRevertSaved::KeyValue( KeyValueData *pkvd ) void CRevertSaved::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT ); + UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), (int)pev->renderamt, FFADE_OUT ); pev->nextthink = gpGlobals->time + MessageTime(); SetThink( &CRevertSaved::MessageThink ); } diff --git a/dlls/player.h b/dlls/player.h index cb2bddf8..b2dce868 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -273,7 +273,7 @@ public: void GiveNamedItem( const char *szName ); void EnableControl(BOOL fControl); - int GiveAmmo( int iAmount, char *szName, int iMax ); + int GiveAmmo( int iAmount, const char *szName, int iMax ); void SendAmmoUpdate(void); void WaterMove( void ); @@ -281,7 +281,7 @@ public: void PlayerUse( void ); void CheckSuitUpdate(); - void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); + void SetSuitUpdate( const char *name, int fgroup, int iNoRepeat ); void UpdateGeigerCounter( void ); void CheckTimeBasedDamage( void ); diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 05d1fc8c..458ac532 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -92,7 +92,7 @@ void CSatchelCharge::Spawn( void ) void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) { - entvars_t *pevOther = pOther->pev; + //entvars_t *pevOther = pOther->pev; // don't hit the guy that launched this grenade if( pOther->edict() == pev->owner ) @@ -377,11 +377,11 @@ 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; -#ifndef CLIENT_DLL CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0 ), m_pPlayer->edict() ); pSatchel->pev->velocity = vecThrow; pSatchel->pev->avelocity.y = 400; diff --git a/dlls/saverestore.h b/dlls/saverestore.h index a9ad2c54..4295871d 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -23,7 +23,7 @@ class CSaveRestoreBuffer public: CSaveRestoreBuffer( void ); CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); - ~CSaveRestoreBuffer( void ); + virtual ~CSaveRestoreBuffer( void ); int EntityIndex( entvars_t *pevLookup ); int EntityIndex( edict_t *pentLookup ); @@ -41,6 +41,10 @@ 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 @@ -81,7 +85,7 @@ typedef struct class CRestore : public CSaveRestoreBuffer { public: - CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) { m_global = 0; m_precache = TRUE; } + 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 ); @@ -160,6 +164,9 @@ 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; diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index c28a88fa..4a5cefca 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -238,7 +238,7 @@ void CBaseMonster::MaintainSchedule( void ) { if( (m_afConditions && !HasConditions( bits_COND_SCHEDULE_DONE ) ) || ( m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE ) ) || - ( ( m_MonsterState == MONSTERSTATE_COMBAT ) && ( m_hEnemy == NULL ) ) ) + ( ( m_MonsterState == MONSTERSTATE_COMBAT ) && ( m_hEnemy == 0 ) ) ) { GetIdealState(); } @@ -407,7 +407,7 @@ void CBaseMonster::RunTask( Task_t *pTask ) { float distance; - if( m_hTargetEnt == NULL ) + if( m_hTargetEnt == 0 ) TaskFail(); else { @@ -675,7 +675,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { TaskFail(); return; @@ -695,7 +695,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) } case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { TaskFail(); return; @@ -715,7 +715,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) } case TASK_FIND_NODE_COVER_FROM_ENEMY: { - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { TaskFail(); return; @@ -737,7 +737,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) { entvars_t *pevCover; - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { // Find cover from self if no enemy available pevCover = pev; @@ -821,7 +821,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) SetTurnActivity(); break; case TASK_FACE_TARGET: - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { MakeIdealYaw( m_hTargetEnt->pev->origin ); SetTurnActivity(); @@ -904,7 +904,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) TaskComplete(); else { - if( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) + if( m_hTargetEnt == 0 || !MoveToTarget( newActivity, 2 ) ) { TaskFail(); ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING( pev->classname ) ); @@ -1043,7 +1043,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) case TASK_GET_PATH_TO_TARGET: { RouteClear(); - if( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) + if( m_hTargetEnt != 0 && MoveToTarget( m_movementActivity, 1 ) ) { TaskComplete(); } @@ -1272,7 +1272,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) } case TASK_PLANT_ON_SCRIPT: { - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { pev->origin = m_hTargetEnt->pev->origin; // Plant on target } @@ -1282,7 +1282,7 @@ void CBaseMonster::StartTask( Task_t *pTask ) } case TASK_FACE_SCRIPT: { - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); } diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 4e60c58e..d7659c61 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -434,7 +434,7 @@ void CScientist::Scream( void ) Activity CScientist::GetStoppedActivity( void ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) return ACT_EXCITED; return CTalkMonster::GetStoppedActivity(); } @@ -510,7 +510,7 @@ void CScientist::RunTask( Task_t *pTask ) if( RANDOM_LONG( 0, 63 ) < 8 ) Scream(); - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { TaskFail(); } @@ -893,8 +893,8 @@ Schedule_t *CScientist::GetSchedule( void ) m_fearTime = gpGlobals->time; else if( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert { - m_hEnemy = NULL; - pEnemy = NULL; + m_hEnemy = 0; + pEnemy = 0; } } @@ -1021,12 +1021,12 @@ MONSTERSTATE CScientist::GetIdealState( void ) { // Strip enemy when going to alert m_IdealMonsterState = MONSTERSTATE_ALERT; - m_hEnemy = NULL; + m_hEnemy = 0; return m_IdealMonsterState; } // Follow if only scared a little - if( m_hTargetEnt != NULL ) + if( m_hTargetEnt != 0 ) { m_IdealMonsterState = MONSTERSTATE_ALERT; return m_IdealMonsterState; @@ -1050,7 +1050,7 @@ MONSTERSTATE CScientist::GetIdealState( void ) BOOL CScientist::CanHeal( void ) { - if( ( m_healTime > gpGlobals->time ) || ( m_hTargetEnt == NULL ) || ( m_hTargetEnt->pev->health > ( m_hTargetEnt->pev->max_health * 0.5 ) ) ) + if( ( m_healTime > gpGlobals->time ) || ( m_hTargetEnt == 0 ) || ( m_hTargetEnt->pev->health > ( m_hTargetEnt->pev->max_health * 0.5 ) ) ) return FALSE; return TRUE; @@ -1093,10 +1093,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display - static char *m_szPoses[7]; + static const char *m_szPoses[7]; }; -char *CDeadScientist::m_szPoses[] = +const char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index f3cf37c5..da9708d1 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -1068,7 +1068,7 @@ BOOL CScriptedSentence::AcceptableSpeaker( CBaseMonster *pMonster ) { if( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) { - if( pMonster->m_hTargetEnt == NULL || !FClassnameIs( pMonster->m_hTargetEnt->pev, "player" ) ) + if( pMonster->m_hTargetEnt == 0 || !FClassnameIs( pMonster->m_hTargetEnt->pev, "player" ) ) return FALSE; } BOOL override; @@ -1124,7 +1124,7 @@ BOOL CScriptedSentence::StartSentence( CBaseMonster *pTarget ) if( !pTarget ) { ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING( m_iszSentence ) ); - return NULL; + return FALSE; } BOOL bConcurrent = FALSE; diff --git a/dlls/skill.cpp b/dlls/skill.cpp index 2a68e1a5..689bbadb 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -25,13 +25,12 @@ 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( char *pName ) +float GetSkillCvar( const char *pName ) { - int iCount; float flValue; char szBuffer[64]; - iCount = sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); + sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); flValue = CVAR_GET_FLOAT( szBuffer ); diff --git a/dlls/skill.h b/dlls/skill.h index 5e784bed..12b784e3 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -136,7 +136,7 @@ struct skilldata_t }; extern DLL_GLOBAL skilldata_t gSkillData; -float GetSkillCvar( char *pName ); +float GetSkillCvar( const char *pName ); extern DLL_GLOBAL int g_iSkillLevel; diff --git a/dlls/sound.cpp b/dlls/sound.cpp index b97eee12..f6110a8d 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -448,7 +448,7 @@ void CAmbientGeneric::InitModulationParms( void ) { int pitchinc; - m_dpv.volrun = pev->health * 10; // 0 - 100 + m_dpv.volrun = (int)( pev->health * 10 ); // 0 - 100 if( m_dpv.volrun > 100 ) m_dpv.volrun = 100; if( m_dpv.volrun < 0 ) @@ -553,7 +553,7 @@ void CAmbientGeneric::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, if( fraction < 0.0 ) fraction = 0.01; - m_dpv.pitch = fraction * 255; + m_dpv.pitch = (int)( fraction * 255 ); UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, 0, 0, SND_CHANGE_PITCH, m_dpv.pitch ); return; @@ -1610,7 +1610,7 @@ float TEXTURETYPE_PlaySound( TraceResult *ptr, Vector vecSrc, Vector vecEnd, in const char *pTextureName; float rgfl1[3]; float rgfl2[3]; - char *rgsz[4]; + const char *rgsz[4]; int cnt; float fattn = ATTN_NORM; @@ -1822,7 +1822,7 @@ IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ) // void CSpeaker::Spawn( void ) { - char *szSoundFile = (char*) STRING( pev->message ); + const char *szSoundFile = STRING( pev->message ); if( !m_preset && ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) ) { @@ -1854,7 +1854,7 @@ void CSpeaker::Precache( void ) } void CSpeaker::SpeakerThink( void ) { - char* szSoundFile; + const char* szSoundFile = NULL; float flvolume = pev->health * 0.1; float flattenuation = 0.3; int flags = 0; @@ -1911,7 +1911,7 @@ void CSpeaker::SpeakerThink( void ) } } else - szSoundFile = (char*)STRING( pev->message ); + szSoundFile = STRING( pev->message ); if( szSoundFile[0] == '!' ) { diff --git a/dlls/squadmonster.cpp b/dlls/squadmonster.cpp index a89f39f9..3d476b50 100644 --- a/dlls/squadmonster.cpp +++ b/dlls/squadmonster.cpp @@ -192,7 +192,7 @@ BOOL CSquadMonster::SquadAdd( CSquadMonster *pAdd ) for( int i = 0; i < MAX_SQUAD_MEMBERS - 1; i++ ) { - if( m_hSquadMember[i] == NULL ) + if( m_hSquadMember[i] == 0 ) { m_hSquadMember[i] = pAdd; pAdd->m_hSquadLeader = this; @@ -258,7 +258,7 @@ void CSquadMonster::SquadMakeEnemy( CBaseEntity *pEnemy ) // reset members who aren't activly engaged in fighting if( pMember->m_hEnemy != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY ) ) { - if( pMember->m_hEnemy != NULL ) + if( pMember->m_hEnemy != 0 ) { // remember their current enemy pMember->PushEnemy( pMember->m_hEnemy, pMember->m_vecEnemyLKP ); @@ -459,7 +459,7 @@ BOOL CSquadMonster::NoFriendlyFire( void ) 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 != NULL ) + if( m_hEnemy != 0 ) { UTIL_MakeVectors( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); } @@ -508,9 +508,7 @@ BOOL CSquadMonster::NoFriendlyFire( void ) //========================================================= MONSTERSTATE CSquadMonster::GetIdealState ( void ) { - int iConditions; - - iConditions = IScheduleFlags(); + IScheduleFlags(); // If no schedule conditions, the new ideal state is probably the reason we're in here. switch( m_MonsterState ) @@ -565,7 +563,7 @@ BOOL CSquadMonster::SquadEnemySplit( void ) for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) { CSquadMonster *pMember = pSquadLeader->MySquadMember( i ); - if( pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy ) + if( pMember != NULL && pMember->m_hEnemy != 0 && pMember->m_hEnemy != pEnemy ) { return TRUE; } diff --git a/dlls/squadmonster.h b/dlls/squadmonster.h index ecd75ee5..707910c2 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -88,7 +88,7 @@ public: else return (CSquadMonster *)( (CBaseEntity *)m_hSquadMember[i] ); } - int InSquad( void ) { return m_hSquadLeader != NULL; } + int InSquad( void ) { return m_hSquadLeader != 0; } int IsLeader( void ) { return m_hSquadLeader == this; } int SquadJoin( int searchRadius ); int SquadRecruit( int searchRadius, int maxMembers ); diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 30ddda62..830cfab8 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -94,7 +94,7 @@ int CSqueakGrenade::Classify( void ) if( m_iMyClass != 0 ) return m_iMyClass; // protect against recursion - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { m_iMyClass = CLASS_INSECT; // no one cares about it switch( m_hEnemy->Classify() ) @@ -180,13 +180,13 @@ void CSqueakGrenade::Killed( entvars_t *pevAttacker, int iGib ) UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); - if( m_hOwner != NULL ) + 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 != NULL ) + if( m_hOwner != 0 ) pev->owner = m_hOwner->edict(); CBaseMonster::Killed( pevAttacker, GIB_ALWAYS ); @@ -230,7 +230,7 @@ void CSqueakGrenade::HuntThink( void ) pev->velocity = pev->velocity * 0.9; pev->velocity.z += 8.0; } - else if( ( pev->movetype = MOVETYPE_FLY ) ) + else if( pev->movetype == MOVETYPE_FLY ) { pev->movetype = MOVETYPE_BOUNCE; } @@ -241,7 +241,7 @@ void CSqueakGrenade::HuntThink( void ) m_flNextHunt = gpGlobals->time + 2.0; - CBaseEntity *pOther = NULL; + //CBaseEntity *pOther = NULL; Vector vecDir; TraceResult tr; @@ -251,7 +251,7 @@ void CSqueakGrenade::HuntThink( void ) UTIL_MakeVectors( pev->angles ); - if( m_hEnemy == NULL || !m_hEnemy->IsAlive() ) + if( m_hEnemy == 0 || !m_hEnemy->IsAlive() ) { // find target, bounce a bit towards it. Look( 512 ); @@ -270,7 +270,7 @@ void CSqueakGrenade::HuntThink( void ) if( flpitch < 80 ) flpitch = 80; - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( FVisible( m_hEnemy ) ) { @@ -350,9 +350,9 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) if( tr.pHit->v.modelindex != pev->modelindex ) { // ALERT( at_console, "hit enemy\n" ); - ClearMultiDamage( ); + ClearMultiDamage(); pOther->TraceAttack( pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if( m_hOwner != NULL ) + if( m_hOwner != 0 ) ApplyMultiDamage( pev, m_hOwner->pev ); else ApplyMultiDamage( pev, pev ); diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index d832c2cc..35bf3856 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -51,7 +51,7 @@ TYPEDESCRIPTION CTalkMonster::m_SaveData[] = IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ) // array of friend names -char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = +const char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = { "monster_barney", "monster_scientist", @@ -391,7 +391,7 @@ void CTalkMonster::StartTask( Task_t *pTask ) case TASK_TLK_EYECONTACT: break; case TASK_TLK_IDEALYAW: - if( m_hTalkTarget != NULL ) + if( m_hTalkTarget != 0 ) { pev->yaw_speed = 60; float yaw = VecToYaw( m_hTalkTarget->pev->origin - pev->origin ) - pev->angles.y; @@ -536,7 +536,7 @@ void CTalkMonster::RunTask( Task_t *pTask ) } break; case TASK_TLK_EYECONTACT: - if( !IsMoving() && IsTalking() && m_hTalkTarget != NULL ) + if( !IsMoving() && IsTalking() && m_hTalkTarget != 0 ) { // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); IdleHeadTurn( m_hTalkTarget->pev->origin ); @@ -561,7 +561,7 @@ void CTalkMonster::RunTask( Task_t *pTask ) } break; case TASK_WAIT_FOR_MOVEMENT: - if( IsTalking() && m_hTalkTarget != NULL ) + if( IsTalking() && m_hTalkTarget != 0 ) { // ALERT( at_console, "walking, talking\n" ); IdleHeadTurn( m_hTalkTarget->pev->origin ); @@ -582,7 +582,7 @@ void CTalkMonster::RunTask( Task_t *pTask ) IdleHeadTurn( pev->origin ); break; default: - if( IsTalking() && m_hTalkTarget != NULL ) + if( IsTalking() && m_hTalkTarget != 0 ) { IdleHeadTurn( m_hTalkTarget->pev->origin ); } @@ -603,7 +603,7 @@ void CTalkMonster::Killed( entvars_t *pevAttacker, int iGib ) LimitFollowers( CBaseEntity::Instance( pevAttacker ), 0 ); } - m_hTargetEnt = NULL; + m_hTargetEnt = 0; // Don't finish that sentence StopTalking(); SetUse( NULL ); @@ -613,7 +613,7 @@ void CTalkMonster::Killed( entvars_t *pevAttacker, int iGib ) CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) { CBaseEntity *pFriend = pPrevious; - char *pszFriend; + const char *pszFriend; TraceResult tr; Vector vecCheck; @@ -712,7 +712,7 @@ void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) float CTalkMonster::TargetDistance( void ) { // If we lose the player, or he dies, return a really large distance - if( m_hTargetEnt == NULL || !m_hTargetEnt->IsAlive() ) + if( m_hTargetEnt == 0 || !m_hTargetEnt->IsAlive() ) return 1e6; return ( m_hTargetEnt->pev->origin - pev->origin ).Length(); @@ -764,7 +764,7 @@ CBaseEntity *CTalkMonster::FindNearestFriend( BOOL fPlayer ) Vector vecStart = pev->origin; Vector vecCheck; int i; - char *pszFriend; + const char *pszFriend; int cfriends; vecStart.z = pev->absmax.z; @@ -855,7 +855,7 @@ void CTalkMonster::Touch( CBaseEntity *pOther ) //========================================================= void CTalkMonster::IdleRespond( void ) { - int pitch = GetVoicePitch(); + //int pitch = GetVoicePitch(); // play response PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE ); @@ -890,7 +890,7 @@ int CTalkMonster::FOkToSpeak( void ) return FALSE; // don't talk if you're in combat - if( m_hEnemy != NULL && FVisible( m_hEnemy ) ) + if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) return FALSE; return TRUE; @@ -977,7 +977,7 @@ void CTalkMonster::IdleHeadTurn( Vector &vecFriend ) int CTalkMonster::FIdleSpeak( void ) { // try to start a conversation, or make statement - int pitch; + //int pitch; const char *szIdleGroup; const char *szQuestionGroup; float duration; @@ -1001,7 +1001,7 @@ int CTalkMonster::FIdleSpeak( void ) duration = RANDOM_FLOAT( 2.8, 3.2 ); } - pitch = GetVoicePitch(); + //pitch = GetVoicePitch(); // player using this entity is alive and wounded? CBaseEntity *pTarget = m_hTargetEnt; @@ -1315,10 +1315,10 @@ void CTalkMonster::StopFollowing( BOOL clearSchedule ) if( m_movementGoal == MOVEGOAL_TARGETENT ) RouteClear(); // Stop him from walking toward the player - m_hTargetEnt = NULL; + m_hTargetEnt = 0; if( clearSchedule ) ClearSchedule(); - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) m_IdealMonsterState = MONSTERSTATE_COMBAT; } } @@ -1328,7 +1328,7 @@ void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) if( m_pCine ) m_pCine->CancelScript(); - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) m_IdealMonsterState = MONSTERSTATE_ALERT; m_hTargetEnt = pLeader; diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 57c417e4..72222aae 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -138,7 +138,7 @@ public: // For following BOOL CanFollow( void ); - BOOL IsFollowing( void ) { return m_hTargetEnt != NULL && m_hTargetEnt->IsPlayer(); } + BOOL IsFollowing( void ) { return m_hTargetEnt != 0 && m_hTargetEnt->IsPlayer(); } void StopFollowing( BOOL clearSchedule ); void StartFollowing( CBaseEntity *pLeader ); virtual void DeclineFollowing( void ) {} @@ -154,7 +154,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; - static char *m_szFriends[TLK_CFRIENDS]; // array of friend names + 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 diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index 614bd7bb..87b695e7 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -116,7 +116,7 @@ void CHalfLifeTeamplay::Think( void ) return; } - remain = flFragLimit - team_scores[i]; + remain = (int)( flFragLimit - team_scores[i] ); if( remain < bestfrags ) { bestfrags = remain; @@ -157,7 +157,7 @@ BOOL CHalfLifeTeamplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) if( CMD_ARGC() < 2 ) return TRUE; - int slot = atoi( CMD_ARGV( 1 ) ); + //int slot = atoi( CMD_ARGV( 1 ) ); // select the item from the current menu return TRUE; @@ -241,7 +241,7 @@ void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) ChangePlayerTeam( pPlayer, pPlayer->m_szTeamName, FALSE, FALSE ); UTIL_SayText( text, pPlayer ); - int clientIndex = pPlayer->entindex(); + //int clientIndex = pPlayer->entindex(); 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 @@ -300,7 +300,7 @@ void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTea MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); WRITE_BYTE( clientIndex ); - WRITE_SHORT( pPlayer->pev->frags ); + WRITE_SHORT( (int)pPlayer->pev->frags ); WRITE_SHORT( pPlayer->m_iDeaths ); WRITE_SHORT( 0 ); WRITE_SHORT( g_pGameRules->GetTeamIndex( pPlayer->m_szTeamName ) + 1 ); @@ -607,7 +607,7 @@ void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) if( tm >= 0 ) { - team_scores[tm] += plr->pev->frags; + team_scores[tm] += (int)plr->pev->frags; } if( bResendInfo ) //Someone's info changed, let's send the team info again. diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp index 637b8946..44b8b45b 100644 --- a/dlls/tentacle.cpp +++ b/dlls/tentacle.cpp @@ -486,12 +486,12 @@ void CTentacle::Cycle( void ) m_flSoundYaw += 360; if( m_flSoundYaw > 180 ) m_flSoundYaw -= 360; - +#if 0 // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); if( m_flSoundTime < gpGlobals->time ) { // play "I hear new something" sound - char *sound; + const char *sound; switch( RANDOM_LONG( 0, 1 ) ) { @@ -505,6 +505,7 @@ void CTentacle::Cycle( void ) // 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 ); } @@ -591,7 +592,7 @@ void CTentacle::Cycle( void ) if( m_flNextSong < gpGlobals->time ) { // play "I hear new something" sound - char *sound; + const char *sound; switch( RANDOM_LONG( 0, 1 ) ) { @@ -791,7 +792,7 @@ void CTentacle::DieThink( void ) void CTentacle::HandleAnimEvent( MonsterEvent_t *pEvent ) { - char *sound; + const char *sound; switch( pEvent->event ) { diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 958f899f..2959d96d 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1265,7 +1265,7 @@ 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 = NULL; + pev->model = 0; pev->modelindex = 0; } @@ -1438,7 +1438,7 @@ void CChangeLevel::UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) { edict_t *pentLandmark; - LEVELLIST levels[16]; + //LEVELLIST levels[16]; ASSERT( !FStrEq( m_szMapName, "" ) ); @@ -2224,7 +2224,7 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP } // Nothing to look at! - if( m_hTarget == NULL ) + if( m_hTarget == 0 ) { return; } @@ -2280,10 +2280,10 @@ void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP void CTriggerCamera::FollowTarget() { - if( m_hPlayer == NULL ) + if( m_hPlayer == 0 ) return; - if( m_hTarget == NULL || m_flReturnTime < gpGlobals->time ) + if( m_hTarget == 0 || m_flReturnTime < gpGlobals->time ) { if( m_hPlayer->IsAlive() ) { diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index e2ed0817..520206dd 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -162,7 +162,7 @@ void CTripmineGrenade::PowerupThink( void ) { TraceResult tr; - if( m_hOwner == NULL ) + if( m_hOwner == 0 ) { // find an owner edict_t *oldowner = pev->owner; @@ -217,7 +217,7 @@ void CTripmineGrenade::PowerupThink( void ) MakeBeam(); // play enabled sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1.0, 75 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1, 75 ); } pev->nextthink = gpGlobals->time + 0.1; } @@ -280,7 +280,7 @@ void CTripmineGrenade::BeamBreakThink( void ) } else { - if( m_hOwner == NULL ) + if( m_hOwner == 0 ) bBlowup = 1; else if( m_posOwner != m_hOwner->pev->origin ) bBlowup = 1; @@ -446,7 +446,7 @@ void CTripmine::PrimaryAttack( void ) { Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); - CBaseEntity *pEnt = CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); + CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; diff --git a/dlls/turret.cpp b/dlls/turret.cpp index 2dce87fb..5b9e1b77 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -456,7 +456,7 @@ void CBaseTurret::ActiveThink( void ) pev->nextthink = gpGlobals->time + 0.1; StudioFrameAdvance(); - if( ( !m_iOn ) || ( m_hEnemy == NULL ) ) + if( ( !m_iOn ) || ( m_hEnemy == 0 ) ) { m_hEnemy = NULL; m_flLastSight = gpGlobals->time + m_flMaxWait; @@ -826,21 +826,21 @@ void CBaseTurret::SearchThink( void ) Ping(); // If we have a target and we're still healthy - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( !m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target - if( m_hEnemy == NULL ) + 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 != NULL ) + if( m_hEnemy != 0 ) { m_flLastSight = 0; m_flSpinUpTime = 0; @@ -881,20 +881,20 @@ void CBaseTurret::AutoSearchThink( void ) pev->nextthink = gpGlobals->time + 0.3; // If we have a target and we're still healthy - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( !m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target - if( m_hEnemy == NULL ) + if( m_hEnemy == 0 ) { Look( TURRET_RANGE ); m_hEnemy = BestVisibleEnemy(); } - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { SetThink( &CBaseTurret::Deploy ); EMIT_SOUND( ENT( pev ), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM ); @@ -903,7 +903,7 @@ void CBaseTurret::AutoSearchThink( void ) void CBaseTurret::TurretDeath( void ) { - BOOL iActive = FALSE; + //BOOL iActive = FALSE; StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; @@ -1222,7 +1222,7 @@ void CSentry::SentryTouch( CBaseEntity *pOther ) void CSentry::SentryDeath( void ) { - BOOL iActive = FALSE; + //BOOL iActive = FALSE; StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; diff --git a/dlls/util.cpp b/dlls/util.cpp index 9c7d9803..d79c9f5a 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -118,7 +118,7 @@ float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) U_Random(); U_Random(); - range = high - low; + range = (int)( high - low ); if( !range ) { return low; @@ -625,7 +625,7 @@ static unsigned short FixedUnsigned16( float value, float scale ) { int output; - output = value * scale; + output = (int)( value * scale ); if( output < 0 ) output = 0; if( output > 0xFFFF ) @@ -638,7 +638,7 @@ static short FixedSigned16( float value, float scale ) { int output; - output = value * scale; + output = (int)( value * scale ); if( output > 32767 ) output = 32767; @@ -937,10 +937,10 @@ TraceResult UTIL_GetGlobalTrace( ) { TraceResult tr; - tr.fAllSolid = gpGlobals->trace_allsolid; - tr.fStartSolid = gpGlobals->trace_startsolid; - tr.fInOpen = gpGlobals->trace_inopen; - tr.fInWater = gpGlobals->trace_inwater; + tr.fAllSolid = (int)gpGlobals->trace_allsolid; + tr.fStartSolid = (int)gpGlobals->trace_startsolid; + tr.fInOpen = (int)gpGlobals->trace_inopen; + tr.fInWater = (int)gpGlobals->trace_inwater; tr.flFraction = gpGlobals->trace_fraction; tr.flPlaneDist = gpGlobals->trace_plane_dist; tr.pHit = gpGlobals->trace_ent; @@ -1033,7 +1033,7 @@ float UTIL_SplineFraction( float value, float scale ) return 3 * valueSquared - 2 * valueSquared * value; } -char *UTIL_VarArgs( char *format, ... ) +char *UTIL_VarArgs( const char *format, ... ) { va_list argptr; static char string[1024]; @@ -1536,7 +1536,7 @@ void UTIL_PrecacheOther( const char *szClassname ) // UTIL_LogPrintf - Prints a logged message to console. // Preceded by LOG: ( timestamp ) < message > //========================================================= -void UTIL_LogPrintf( char *fmt, ... ) +void UTIL_LogPrintf( const char *fmt, ... ) { va_list argptr; static char string[1024]; @@ -1902,7 +1902,7 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) int i; TYPEDESCRIPTION *pField; - for( i = 0; i < ENTVARS_COUNT; i++ ) + for( i = 0; i < (int)ENTVARS_COUNT; i++ ) { pField = &gEntvarsDescription[i]; diff --git a/dlls/util.h b/dlls/util.h index f8ae0b6a..fc345ae4 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -87,8 +87,9 @@ typedef int EOFFSET; 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 DLLEXPORT MethodName( void ) #define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void) @@ -304,7 +305,7 @@ 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( char *format, ... ); +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 ); @@ -364,7 +365,7 @@ 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, ... ); +extern void UTIL_LogPrintf( const char *fmt, ... ); // Sorta like FInViewCone, but for nonmonsters. extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); @@ -534,7 +535,7 @@ 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 < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } + { for (int i = 0; i < (int)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) ); diff --git a/dlls/vector.h b/dlls/vector.h index d3347983..265a9b00 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -22,8 +22,8 @@ class Vector2D { public: - inline Vector2D(void) { } - inline Vector2D(float X, float Y) { x = X; y = Y; } + inline Vector2D(void): x( 0.0f ), y( 0.0f ) { } + inline Vector2D(float X, float Y): x( 0.0f ), y( 0.0f ) { 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 ); } @@ -33,7 +33,7 @@ public: inline Vector2D Normalize ( void ) const { - Vector2D vec2; + //Vector2D vec2; float flLen = Length(); if( flLen == 0 ) @@ -60,12 +60,12 @@ class Vector // same data-layout as engine's vec3_t, { // which is a vec_t[3] public: // Construction/destruction - inline Vector( void ) { } - inline Vector( float X, float Y, float Z ) { x = X; y = Y; z = Z; } + inline Vector( void ): x( 0.0f ), y( 0.0f ), z( 0.0f ) { } + inline Vector( float X, float Y, float Z ): x( 0.0f ), y( 0.0f ), z( 0.0f ) { 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 = v.x; y = v.y; z = v.z; } - inline Vector( float rgfl[3] ) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + inline Vector( const Vector& v ): x( 0.0f ), y( 0.0f ), z( 0.0f ) { x = v.x; y = v.y; z = v.z; } + inline Vector( float rgfl[3] ): x( 0.0f ), y( 0.0f ), z( 0.0f ) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } // Operators inline Vector operator-( void ) const { return Vector( -x, -y, -z ); } diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ee2a8547..0b6f7de6 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -935,7 +935,7 @@ BOOL CBasePlayerWeapon::CanDeploy( void ) return TRUE; } -BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) +BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) { if( !CanDeploy() ) return FALSE; @@ -1400,7 +1400,7 @@ BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) //========================================================= // CWeaponBox - GiveAmmo //========================================================= -int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ ) +int CWeaponBox::GiveAmmo( int iCount, const char *szName, int iMax, int *pIndex/* = NULL*/ ) { int i; diff --git a/dlls/weapons.h b/dlls/weapons.h index 3e6fc5ce..8d60bad8 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -310,7 +310,7 @@ public: virtual BOOL CanDeploy( void ); virtual BOOL IsUseable( void ); - BOOL DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0, int body = 0 ); + BOOL DefaultDeploy( const char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0, int body = 0 ); int DefaultReload( int iClipSize, int iAnim, float fDelay, int body = 0 ); virtual void ItemPostFrame( void ); // called each frame by the player PostThink @@ -430,7 +430,7 @@ class CWeaponBox : public CBaseEntity void Touch( CBaseEntity *pOther ); void KeyValue( KeyValueData *pkvd ); BOOL IsEmpty( void ); - int GiveAmmo( int iCount, char *szName, int iMax, int *pIndex = NULL ); + int GiveAmmo( int iCount, const char *szName, int iMax, int *pIndex = NULL ); void SetObjectCollisionBox( void ); public: @@ -453,7 +453,7 @@ public: #ifdef CLIENT_DLL bool bIsMultiplayer ( void ); -void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ); +void LoadVModel ( const char *szViewModel, CBasePlayer *m_pPlayer ); #endif class CGlock : public CBasePlayerWeapon @@ -828,7 +828,9 @@ public: unsigned short m_usEgonStop; private: +#ifndef CLIENT_DLL float m_shootTime; +#endif EGON_FIREMODE m_fireMode; float m_shakeTime; BOOL m_deployed; diff --git a/dlls/world.cpp b/dlls/world.cpp index a065b5be..f352bd52 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -292,7 +292,7 @@ globalentity_t *CGlobalState::Find( string_t globalname ) //#ifdef _DEBUG void CGlobalState::DumpGlobals( void ) { - static char *estates[] = { "Off", "On", "Dead" }; + static const char *estates[] = { "Off", "On", "Dead" }; globalentity_t *pTest; ALERT( at_console, "-- Globals --\n" ); @@ -582,7 +582,7 @@ void CWorld::Precache( void ) // 63 testing LIGHT_STYLE( 63, "a" ); - for( int i = 0; i < ARRAYSIZE( gDecals ); i++ ) + for( int i = 0; i < (int)ARRAYSIZE( gDecals ); i++ ) gDecals[i].index = DECAL_INDEX( gDecals[i].name ); // init the WorldGraph. diff --git a/dlls/xen.cpp b/dlls/xen.cpp index 8e9c771c..4e9e1685 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -98,7 +98,7 @@ void CXenPLight::Spawn( void ) 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, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx ); + m_pGlow->SetTransparency( kRenderGlow, (int)pev->rendercolor.x, (int)pev->rendercolor.y, (int)pev->rendercolor.z, (int)pev->renderamt, (int)pev->renderfx ); m_pGlow->SetAttachment( edict(), 1 ); } @@ -497,7 +497,7 @@ void CXenSporeLarge::Spawn( void ) UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); // Rotate the leg hulls into position - for( int i = 0; i < ARRAYSIZE( m_hullSizes ); i++ ) + for( int i = 0; i < (int)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 ) ); } @@ -536,7 +536,7 @@ void CXenSpore::Touch( CBaseEntity *pOther ) void CXenSpore::Think( void ) { - float flInterval = StudioFrameAdvance(); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; #if 0 DispatchAnimEvents( flInterval ); diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index b20293c1..2611f881 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -286,7 +286,7 @@ void CZombie::Spawn() //========================================================= void CZombie::Precache() { - int i; + size_t i; PRECACHE_MODEL( "models/zombie.mdl" ); diff --git a/engine/custom.h b/engine/custom.h index d48ee72d..8f644e00 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -16,6 +16,12 @@ #ifndef CUSTOM_H #define CUSTOM_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + #include "const.h" ///////////////// diff --git a/engine/edict.h b/engine/edict.h index b0469b86..e89b6926 100644 --- a/engine/edict.h +++ b/engine/edict.h @@ -16,6 +16,12 @@ #ifndef EDICT_H #define EDICT_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + #define MAX_ENT_LEAFS 48 #include "progdefs.h" @@ -39,4 +45,4 @@ struct edict_s // other fields from progs come immediately after }; -#endif//EDICT_H \ No newline at end of file +#endif//EDICT_H diff --git a/engine/eiface.h b/engine/eiface.h index 3419e5bd..30f8a82a 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -94,13 +94,13 @@ typedef unsigned int CRC32_t; // Engine hands this to DLLs for functionality callbacks typedef struct enginefuncs_s { - int (*pfnPrecacheModel)( char* s ); - int (*pfnPrecacheSound)( char* s ); + int (*pfnPrecacheModel)( const char *s ); + int (*pfnPrecacheSound)( const char *s ); void (*pfnSetModel)( edict_t *e, const char *m ); int (*pfnModelIndex)( const char *m ); int (*pfnModelFrames)( int modelIndex ); void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); - void (*pfnChangeLevel)( char* s1, char* s2 ); + void (*pfnChangeLevel)( const char *s1, const char *s2 ); void (*pfnGetSpawnParms)( edict_t *ent ); void (*pfnSaveSpawnParms)( edict_t *ent ); float (*pfnVecToYaw)( const float *rgflVector ); @@ -132,12 +132,12 @@ typedef struct enginefuncs_s void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); 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)( char* str ); + void (*pfnGetAimVector)( edict_t *ent, float speed, float *rgflReturn ); + void (*pfnServerCommand)( const char *str ); void (*pfnServerExecute)( void ); - void (*pfnClientCommand)( edict_t* pEdict, char* szFmt, ... ); + void (*pfnClientCommand)( edict_t* pEdict, const char *szFmt, ... ); void (*pfnParticleEffect)( const float *org, const float *dir, float color, float count ); - void (*pfnLightStyle)( int style, char* val ); + void (*pfnLightStyle)( int style, const 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 ); @@ -155,8 +155,8 @@ typedef struct enginefuncs_s const char* (*pfnCVarGetString)( const char *szVarName ); void (*pfnCVarSetFloat)( const char *szVarName, float flValue ); void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); - void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); - void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); + void (*pfnAlertMessage)( ALERT_TYPE atype, const char *szFmt, ... ); + void (*pfnEngineFprintf)( FILE *pfile, const char *szFmt, ... ); void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, int cb ); void* (*pfnPvEntPrivateData)( edict_t *pEdict ); void (*pfnFreeEntPrivateData)( edict_t *pEdict ); @@ -189,7 +189,7 @@ 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)( char *filename, int *pLength ); + byte* (*pfnLoadFileForMe)( const char *filename, int *pLength ); void (*pfnFreeFile)( void *buffer ); void (*pfnEndSection)( const char *pszSectionName ); // trigger_endsection int (*pfnCompareFileTime)( char *filename1, char *filename2, int *iCompare ); @@ -201,12 +201,12 @@ typedef struct enginefuncs_s void (*pfnRunPlayerMove)( edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); int (*pfnNumberOfEntities)( void ); char* (*pfnGetInfoKeyBuffer)( edict_t *e ); // passing in NULL gets the serverinfo - char* (*pfnInfoKeyValue)( char *infobuffer, char *key ); - void (*pfnSetKeyValue)( char *infobuffer, char *key, char *value ); - void (*pfnSetClientKeyValue)( int clientIndex, char *infobuffer, char *key, char *value ); - int (*pfnIsMapValid)( char *filename ); + 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 ); void (*pfnStaticDecal)( const float *origin, int decalIndex, int entityIndex, int modelIndex ); - int (*pfnPrecacheGeneric)( char *s ); + int (*pfnPrecacheGeneric)( const 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? @@ -228,7 +228,7 @@ typedef struct enginefuncs_s void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); void (*pfnDeltaUnsetField)( struct delta_s *pFields, const char *fieldname ); - void (*pfnDeltaAddEncoder)( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); + void (*pfnDeltaAddEncoder)( const 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 ); @@ -236,7 +236,7 @@ typedef struct enginefuncs_s void (*pfnDeltaUnsetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); void (*pfnSetGroupMask)( int mask, int op ); int (*pfnCreateInstancedBaseline)( int classname, struct entity_state_s *baseline ); - void (*pfnCvar_DirectSet)( struct cvar_s *var, char *value ); + void (*pfnCvar_DirectSet)( struct cvar_s *var, const char *value ); // Forces the client and server to be running with the same version of the specified file // ( e.g., a player model ). @@ -245,7 +245,7 @@ typedef struct enginefuncs_s void (*pfnGetPlayerStats)( const edict_t *pClient, int *ping, int *packet_loss ); - void (*pfnAddServerCommand)( char *cmd_name, void (*function) (void) ); + void (*pfnAddServerCommand)( const char *cmd_name, void (*function) (void) ); // For voice communications, set which clients hear eachother. // NOTE: these functions take player entity indices (starting at 1). @@ -256,7 +256,7 @@ typedef struct enginefuncs_s void *(*pfnSequenceGet)( const char *fileName, const char *entryName ); void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked ); - int (*pfnGetFileSize)( char *filename ); + int (*pfnGetFileSize)( const char *filename ); unsigned int (*pfnGetApproxWavePlayLen)( const char *filepath ); int (*pfnIsCareerMatch)( void ); int (*pfnGetLocalizedStringLength)( const char *label ); @@ -274,9 +274,9 @@ typedef struct enginefuncs_s // Passed to pfnKeyValue typedef struct KeyValueData_s { - char *szClassName; // in: entity classname - char *szKeyName; // in: name of key - char *szValue; // in: value of key + const char *szClassName; // in: entity classname + const char *szKeyName; // in: name of key + const char *szValue; // in: value of key int fHandled; // out: DLL sets to true if key-value pair was understood } KeyValueData; @@ -374,13 +374,15 @@ typedef enum _fieldtypes typedef struct { FIELDTYPE fieldType; - char *fieldName; + const char *fieldName; int fieldOffset; short fieldSize; short flags; } TYPEDESCRIPTION; +#ifndef ARRAYSIZE #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) +#endif typedef struct { @@ -434,7 +436,7 @@ typedef struct void (*pfnPM_Move)( struct playermove_s *ppmove, qboolean server ); void (*pfnPM_Init)( struct playermove_s *ppmove ); - char (*pfnPM_FindTextureType)( char *name ); + char (*pfnPM_FindTextureType)( const 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 ); diff --git a/engine/progdefs.h b/engine/progdefs.h index 74004a27..cdbcc006 100644 --- a/engine/progdefs.h +++ b/engine/progdefs.h @@ -16,6 +16,12 @@ #ifndef PROGDEFS_H #define PROGDEFS_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + typedef struct { float time; @@ -215,4 +221,4 @@ typedef struct entvars_s edict_t *euser4; } entvars_t; -#endif//PROGDEFS_H \ No newline at end of file +#endif//PROGDEFS_H diff --git a/pm_shared/pm_debug.c b/pm_shared/pm_debug.c index 3baccaef..3b0879c7 100644 --- a/pm_shared/pm_debug.c +++ b/pm_shared/pm_debug.c @@ -23,8 +23,10 @@ #include +#ifdef _MSC_VER #pragma warning(disable : 4244) #pragma warning(disable : 4305) +#endif extern playermove_t *pmove; diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index 4959d165..cc130598 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -15,6 +15,12 @@ #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 ); diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index cd17ce54..b4c652ba 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -16,6 +16,12 @@ #ifndef PM_DEFS_H #define PM_DEFS_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + #define MAX_PHYSENTS 600 // Must have room for all entities in the world. #define MAX_MOVEENTS 64 #define MAX_CLIP_PLANES 5 diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index 321527f2..d9dbc03d 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -15,5 +15,11 @@ #ifndef PM_INFO_H #define PM_INFO_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + #define MAX_PHYSINFO_STRING 256 #endif//PM_INFO_H diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c index 3718dc63..5bbe0068 100644 --- a/pm_shared/pm_math.c +++ b/pm_shared/pm_math.c @@ -25,7 +25,9 @@ // fall over #define ROLL 2 +#ifdef _MSC_VER #pragma warning(disable : 4244) +#endif vec3_t vec3_origin = { 0,0,0 }; int nanmask = 255 << 23; diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 7a1fb966..c709ba14 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -36,7 +36,9 @@ extern float vJumpAngles[3]; static int pm_shared_initialized = 0; +#ifdef _MSC_VER #pragma warning( disable : 4305 ) +#endif playermove_t *pmove = NULL; @@ -90,7 +92,10 @@ playermove_t *pmove = NULL; #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 @@ -549,7 +554,7 @@ void PM_UpdateStepSound( void ) float fvol; vec3_t knee; vec3_t feet; - vec3_t center; + //vec3_t center; float height; float speed; float velrun; @@ -592,7 +597,7 @@ void PM_UpdateStepSound( void ) { fWalking = speed < velrun; - VectorCopy( pmove->origin, center ); + //VectorCopy( pmove->origin, center ); VectorCopy( pmove->origin, knee ); VectorCopy( pmove->origin, feet ); @@ -1062,7 +1067,7 @@ Only used by players. Moves along the ground when player is a MOVETYPE_WALK. */ void PM_WalkMove() { - int clip; + //int clip; int oldonground; int i; @@ -1072,7 +1077,7 @@ void PM_WalkMove() vec3_t wishdir; float wishspeed; - vec3_t dest, start; + vec3_t dest; //, start; vec3_t original, originalvel; vec3_t down, downvel; float downdist, updist; @@ -1135,7 +1140,7 @@ void PM_WalkMove() dest[2] = pmove->origin[2]; // first try moving directly to the next spot - VectorCopy( dest, start ); + //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. @@ -1158,7 +1163,8 @@ void PM_WalkMove() VectorCopy( pmove->velocity, originalvel ); // velocity. // Slide move - clip = PM_FlyMove(); + //clip = PM_FlyMove(); + PM_FlyMove(); // Copy the results out VectorCopy( pmove->origin, down ); @@ -1183,7 +1189,8 @@ void PM_WalkMove() } // slide move the rest of the way. - clip = PM_FlyMove(); + //clip = PM_FlyMove(); + PM_FlyMove(); // Now try going back down from the end point // press down the stepheight @@ -1994,8 +2001,8 @@ void PM_Duck( void ) 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" - int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; - int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; + //int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; + //int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; if( pmove->cmd.buttons & IN_DUCK ) { @@ -2261,6 +2268,7 @@ void PM_AddGravity() pmove->basevelocity[2] = 0; PM_CheckVelocity(); } + /* ============ PM_PushEntity diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index 124d37ba..1d0e4f38 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -16,6 +16,12 @@ #ifndef PM_SHARED_H #define PM_SHARED_H +#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 ); From d20c4ff32980ad5cfd999533165ed2f90a61075e Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 02:36:56 +0500 Subject: [PATCH 103/227] Fix build. --- cl_dll/cl_util.h | 10 +++++++--- cl_dll/com_weapons.cpp | 2 +- cl_dll/hud_redraw.cpp | 2 +- cl_dll/text_message.cpp | 12 ++++++------ dlls/buttons.cpp | 2 +- dlls/combat.cpp | 2 +- dlls/weapons.cpp | 2 +- dlls/weapons.h | 2 +- engine/cdll_int.h | 2 +- 9 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 54dcede0..22555caa 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -94,8 +94,12 @@ inline void DrawSetTextColor( float r, float g, float b ) inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } -inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } -inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) +inline client_textmessage_t *TextMessageGet( const char *pName ) +{ + return gEngfuncs.pfnTextMessageGet( pName ); +} + +inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) { return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); } @@ -115,7 +119,7 @@ inline void GetConsoleStringSize( const char *string, int *width, int *height ) gEngfuncs.pfnDrawConsoleStringLen( (char*)string, width, height ); } -int DrawUtfString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ); +int DrawUtfString( int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ); inline int ConsoleStringLen( const char *string ) { diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index e50de419..774df091 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -46,7 +46,7 @@ void COM_Log( const char *pszFile, const char *fmt, ... ) va_list argptr; char string[1024]; FILE *fp; - char *pfilename; + const char *pfilename; if( !pszFile ) { diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 5182b484..829fd4b2 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -281,7 +281,7 @@ int CHud::DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r int CHud::DrawHudStringReverse( int xpos, int ypos, int iMinX, const char *szString, int r, int g, int b ) { // find the end of the string - for( char *szIt = szString; *szIt != 0; szIt++ ) + for( const char *szIt = szString; *szIt != 0; szIt++ ) xpos -= gHUD.m_scrinfo.charWidths[(unsigned char)*szIt]; if( xpos < iMinX ) xpos = iMinX; diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index 13b62577..58dae6f7 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -45,7 +45,7 @@ int CHudTextMessage::Init( void ) char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) { char *dst = dst_buffer; - for( char *src = msg; *src != 0 && buffer_size > 0; buffer_size-- ) + for( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) { if( *src == '#' ) { @@ -163,22 +163,22 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf int msg_dest = READ_BYTE(); static char szBuf[6][128]; - char *msg_text = LookupString( READ_STRING(), &msg_dest ); + const char *msg_text = LookupString( READ_STRING(), &msg_dest ); msg_text = strcpy( szBuf[0], msg_text ); // keep reading strings and using C format strings for subsituting the strings into the localised text string const char *sstr1 = LookupString( READ_STRING() ); sstr1 = strcpy( szBuf[1], sstr1 ); - StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines + StripEndNewlineFromString( (char*)sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines const char *sstr2 = LookupString( READ_STRING() ); sstr2 = strcpy( szBuf[2], sstr2 ); - StripEndNewlineFromString( sstr2 ); + StripEndNewlineFromString( (char*)sstr2 ); const char *sstr3 = LookupString( READ_STRING() ); sstr3 = strcpy( szBuf[3], sstr3 ); - StripEndNewlineFromString( sstr3 ); + StripEndNewlineFromString( (char*)sstr3 ); const char *sstr4 = LookupString( READ_STRING() ); sstr4 = strcpy( szBuf[4], sstr4 ); - StripEndNewlineFromString( sstr4 ); + StripEndNewlineFromString( (char*)sstr4 ); char *psz = szBuf[5]; switch( msg_dest ) diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 76f4ad91..df7c51f3 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -525,7 +525,7 @@ void CBaseButton::Spawn() // Button sound table. // Also used by CBaseDoor to get 'touched' door lock/unlock sounds -char *ButtonSound( int sound ) +const char *ButtonSound( int sound ) { const char *pszSound; diff --git a/dlls/combat.cpp b/dlls/combat.cpp index d8830c20..35e4ffcf 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -1463,7 +1463,7 @@ void CBaseEntity::FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShootin } } // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0 ); + UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (int)( ( flDistance * tr.flFraction ) / 64.0 ) ); } ApplyMultiDamage( pev, pevAttacker ); } diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 0b6f7de6..989c32a8 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -935,7 +935,7 @@ BOOL CBasePlayerWeapon::CanDeploy( void ) return TRUE; } -BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) +BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, const char *szWeaponModel, int iAnim, const char *szAnimExt, int skiplocal /* = 0 */, int body ) { if( !CanDeploy() ) return FALSE; diff --git a/dlls/weapons.h b/dlls/weapons.h index 8d60bad8..7bb1b486 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -310,7 +310,7 @@ public: virtual BOOL CanDeploy( void ); virtual BOOL IsUseable( void ); - BOOL DefaultDeploy( const char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0, int body = 0 ); + BOOL DefaultDeploy( const char *szViewModel, const char *szWeaponModel, int iAnim, const char *szAnimExt, int skiplocal = 0, int body = 0 ); int DefaultReload( int iClipSize, int iAnim, float fDelay, int body = 0 ); virtual void ItemPostFrame( void ); // called each frame by the player PostThink diff --git a/engine/cdll_int.h b/engine/cdll_int.h index a0dc59c2..056146b4 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -205,7 +205,7 @@ typedef struct cl_enginefuncs_s int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); - void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); + void (*pfnPlaySoundByNameAtLocation)( const char *szSound, float volume, float *origin ); unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); void (*pfnPlaybackEvent)( 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 ); From c28d86f748362565baa82a522404e1ae7476fac8 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 02:42:30 +0500 Subject: [PATCH 104/227] Fix wrong check. --- dlls/cbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 0cc10bdb..cdf9a00f 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -511,7 +511,7 @@ int CBaseEntity::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl // (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 ); + vecTemp = pevAttacker->origin - VecBModelOrigin( pev ); } else // an actual missile was involved. From 4ae58b4170bc0f05e27baea53262ccbfc22e7fd4 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 05:37:14 +0500 Subject: [PATCH 105/227] Fix weapon reload bug. Use macros instead of magic numbers. --- dlls/crossbow.cpp | 4 ++-- dlls/egon.cpp | 2 +- dlls/glock.cpp | 8 ++++---- dlls/python.cpp | 4 ++-- dlls/rpg.cpp | 9 ++------- dlls/shotgun.cpp | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index d749c785..12d0ff8c 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -481,7 +481,7 @@ void CCrossbow::SecondaryAttack() void CCrossbow::Reload( void ) { - if( m_pPlayer->ammo_bolts <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == CROSSBOW_MAX_CLIP ) return; if( m_pPlayer->pev->fov != 0 ) @@ -489,7 +489,7 @@ void CCrossbow::Reload( void ) SecondaryAttack(); } - if( DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ) ) + if( DefaultReload( CROSSBOW_MAX_CLIP, 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 ) ); } diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 9a4de49b..b83c9086 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -143,7 +143,7 @@ float CEgon::GetDischargeInterval( void ) BOOL CEgon::HasAmmo( void ) { - if( m_pPlayer->ammo_uranium <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) return FALSE; return TRUE; diff --git a/dlls/glock.cpp b/dlls/glock.cpp index 1f4517e7..4e679750 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -169,15 +169,15 @@ void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ) void CGlock::Reload( void ) { - if( m_pPlayer->ammo_9mm <= 0 ) - return; + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == GLOCK_MAX_CLIP ) + return; int iResult; if( m_iClip == 0 ) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); + iResult = DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD, 1.5 ); else - iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + iResult = DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); if( iResult ) { diff --git a/dlls/python.cpp b/dlls/python.cpp index 7bb71325..b7e48386 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -212,7 +212,7 @@ void CPython::PrimaryAttack() void CPython::Reload( void ) { - if( m_pPlayer->ammo_357 <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == PYTHON_MAX_CLIP ) return; if( m_pPlayer->pev->fov != 0 ) @@ -227,7 +227,7 @@ void CPython::Reload( void ) #else bUseScope = g_pGameRules->IsMultiplayer(); #endif - if( DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope ) ) + if( DefaultReload( PYTHON_MAX_CLIP, PYTHON_RELOAD, 2.0, bUseScope ) ) { m_flSoundDelay = 1.5; } diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 95c9132a..fb2b39c8 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -278,13 +278,8 @@ 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 ) + // don't bother with any of this if don't need to reload. + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == RPG_MAX_CLIP ) return; // because the RPG waits to autoreload when no missiles are active while the LTD is on, the diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 595561e2..d6be007a 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -320,7 +320,7 @@ void CShotgun::WeaponIdle( void ) } else if( m_fInSpecialReload != 0 ) { - if( m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) + if( m_iClip != SHOTGUN_MAX_CLIP && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { Reload(); } From cabb03ad45de13063b0dc42255455d1eaab22eda Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 16:11:40 +0500 Subject: [PATCH 106/227] Merge https://github.com/ValveSoftware/halflife/pull/1598/commits/2257fa14e7b1cd1fffd0c9d058b7368799b8b2a3 --- dlls/hornet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index d968b79b..758ba7e9 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -407,7 +407,7 @@ void CHornet::DartTouch( CBaseEntity *pOther ) void CHornet::DieTouch( CBaseEntity *pOther ) { - if( pOther && pOther->pev->takedamage ) + if( pOther && pOther->pev->takedamage && pev->owner ) { // do the damage switch( RANDOM_LONG( 0, 2 ) ) From 7113204d5133ed67975bd9220fe50b6ae8b1fda9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 16:42:54 +0500 Subject: [PATCH 107/227] Merge https://github.com/ValveSoftware/halflife/pull/1600/commits/8903b33ef34cbe7e33bfbaa15f5c418bf9d01a02 --- dlls/crowbar.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 00b16d57..051d2309 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -220,8 +220,14 @@ int CCrowbar::Swing( int fFirst ) CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); ClearMultiDamage(); - + // If building with the clientside weapon prediction system, + // UTIL_WeaponTimeBase() is always 0 and m_flNextPrimaryAttack is >= -1.0f, thus making + // m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() always evaluate to false. +#ifdef CLIENT_WEAPONS + if( ( m_flNextPrimaryAttack + 1 == UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) +#else if( ( m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) +#endif { // first swing does full damage pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); From 13a691bdd85c692da49eb66cc1ea04cedd012950 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 19:02:52 +0500 Subject: [PATCH 108/227] Fix GetHullBounds() Same as in https://github.com/FWGS/cs16-client/commit/8d4515be429bfbff90b702d968ea9d57690b9ef4 --- cl_dll/cdll_int.cpp | 12 ++++++------ dlls/client.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 13200a89..ffd342d2 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -76,18 +76,18 @@ int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) switch( hullnumber ) { case 0: // Normal player - mins = Vector( -16, -16, -36 ); - maxs = Vector( 16, 16, 36 ); + Vector( -16, -16, -36 ).CopyToArray(mins); + Vector( 16, 16, 36 ).CopyToArray(maxs); iret = 1; break; case 1: // Crouched player - mins = Vector( -16, -16, -18 ); - maxs = Vector( 16, 16, 18 ); + Vector( -16, -16, -18 ).CopyToArray(mins); + Vector( 16, 16, 18 ).CopyToArray(maxs); iret = 1; break; case 2: // Point based hull - mins = Vector( 0, 0, 0 ); - maxs = Vector( 0, 0, 0 ); + Vector( 0, 0, 0 ).CopyToArray(mins); + Vector( 0, 0, 0 ).CopyToArray(maxs); iret = 1; break; } diff --git a/dlls/client.cpp b/dlls/client.cpp index 99f1913b..ea4eb590 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1853,18 +1853,18 @@ int GetHullBounds( int hullnumber, float *mins, float *maxs ) switch( hullnumber ) { case 0: // Normal player - mins = VEC_HULL_MIN; - maxs = VEC_HULL_MAX; + VEC_HULL_MIN.CopyToArray(mins); + VEC_HULL_MAX.CopyToArray(maxs); iret = 1; break; case 1: // Crouched player - mins = VEC_DUCK_HULL_MIN; - maxs = VEC_DUCK_HULL_MAX; + VEC_DUCK_HULL_MIN.CopyToArray(mins); + VEC_DUCK_HULL_MAX.CopyToArray(maxs); iret = 1; break; case 2: // Point based hull - mins = Vector( 0, 0, 0 ); - maxs = Vector( 0, 0, 0 ); + Vector( 0, 0, 0 ).CopyToArray(mins); + Vector( 0, 0, 0 ).CopyToArray(maxs); iret = 1; break; } From 3dfbd2a41f550b39acc382bac1bf436504577143 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 19:31:49 +0500 Subject: [PATCH 109/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/14fa5e81d0c327d3e2b43d2804b6c9377ce96ec4 --- dlls/world.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/world.cpp b/dlls/world.cpp index f352bd52..1cc645c9 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -484,9 +484,12 @@ void CWorld::Precache( void ) ///!!!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 ) + if( pSoundEnt ) + { + pSoundEnt->Spawn(); + } + else { ALERT ( at_console, "**COULD NOT CREATE SOUNDENT**\n" ); } From ac6d7c4384d12ce7ff59162db892139fc91109c1 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 19:35:16 +0500 Subject: [PATCH 110/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/5cade5b7607da186349ad4c49fd778cff40ea3ee --- dlls/monsters.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index cfe4c561..5f112a62 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -334,12 +334,10 @@ void CBaseMonster::Look( int iDistance ) { if( pev->spawnflags & SF_MONSTER_WAIT_TILL_SEEN ) { - CBaseMonster *pClient; - - pClient = pSightEnt->MyMonsterPointer(); + CBaseMonster *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 ) ) + if( pClient && !pClient->FInViewCone( this ) ) { // we're not in the player's view cone. continue; From d3ebe0ac46aedfd75a4ccafadfd70e3665361ac5 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 19:52:18 +0500 Subject: [PATCH 111/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/e7b5c6be5153ac402fc771d164808d2752105299 --- dlls/bigmomma.cpp | 2 +- dlls/crowbar.cpp | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index a038c776..6b594983 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -411,7 +411,7 @@ void CBigMomma::SetYawSpeed( void ) { int ys; - switch ( m_Activity ) + switch( m_Activity ) { case ACT_IDLE: ys = 100; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 051d2309..b00a0ad3 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -219,32 +219,32 @@ int CCrowbar::Swing( int fFirst ) fDidHit = TRUE; CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - ClearMultiDamage(); - // If building with the clientside weapon prediction system, - // UTIL_WeaponTimeBase() is always 0 and m_flNextPrimaryAttack is >= -1.0f, thus making - // m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() always evaluate to false. -#ifdef CLIENT_WEAPONS - if( ( m_flNextPrimaryAttack + 1 == UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) -#else - if( ( m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) -#endif - { - // 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; + float flVol = 1.0; + int fHitWorld = TRUE; if( pEntity ) { + ClearMultiDamage(); + // If building with the clientside weapon prediction system, + // UTIL_WeaponTimeBase() is always 0 and m_flNextPrimaryAttack is >= -1.0f, thus making + // m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() always evaluate to false. +#ifdef CLIENT_WEAPONS + if( ( m_flNextPrimaryAttack + 1 == UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) +#else + if( ( m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) +#endif + { + // 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 ); + if( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) { // play thwack or smack sound From 391c2aa2175d8e5511d80f68bac6d4b511739ca6 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 20:09:34 +0500 Subject: [PATCH 112/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/5a13e06f522b1aff363fd0b1d360c2ed725cc6e4 --- dlls/aflock.cpp | 6 +++--- dlls/client.cpp | 2 +- dlls/plats.cpp | 24 +++++++++++++----------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp index 19998a9d..d50a8165 100644 --- a/dlls/aflock.cpp +++ b/dlls/aflock.cpp @@ -839,11 +839,11 @@ void CFlockingFlyer::SquadRemove( CFlockingFlyer *pRemove ) { CFlockingFlyer *pLeader = m_pSquadNext; - // copy the enemy LKP to the new leader - pLeader->m_vecEnemyLKP = m_vecEnemyLKP; - if( pLeader ) { + // copy the enemy LKP to the new leader + pLeader->m_vecEnemyLKP = m_vecEnemyLKP; + CFlockingFlyer *pList = pLeader; while( pList ) diff --git a/dlls/client.cpp b/dlls/client.cpp index ea4eb590..5d41d6ad 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -353,7 +353,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) } // remove quotes if present - if( *p == '"' ) + if( p && *p == '"' ) { p++; p[strlen( p ) - 1] = 0; diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 8fecf684..203f5d9b 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -743,21 +743,21 @@ void CFuncTrain::Next( void ) pev->target = pTarg->pev->target; m_flWait = pTarg->GetDelay(); - if ( m_pevCurrentTarget && m_pevCurrentTarget->speed != 0 ) + 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 ); + 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)) + 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); + 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 @@ -767,13 +767,15 @@ void CFuncTrain::Next( void ) // 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); + if( pev->noiseMovement ) + { + STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING( 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); + LinearMove( pTarg->pev->origin - ( pev->mins + pev->maxs )* 0.5, pev->speed ); } } From 98a562c20e2add40c34973ed1be95f167120c10f Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 2 Jul 2017 21:17:51 +0500 Subject: [PATCH 113/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/9d2ae368aae3207dc9f66aca8a3c1505d5c3014a --- dlls/scientist.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index d7659c61..7cf9cc4d 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -464,7 +464,10 @@ void CScientist::StartTask( Task_t *pTask ) { Talk( 2 ); m_hTalkTarget = m_hEnemy; - if( m_hEnemy->IsPlayer() ) + + //The enemy can be null here. - Solokiller + //Discovered while testing the barnacle grapple on headcrabs with scientists in view. + if( m_hEnemy && m_hEnemy->IsPlayer() ) PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); else PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); From 4800c0d54ca8a9c5de8e0aa2b2f448b7c8b164ff Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 3 Jul 2017 03:24:14 +0500 Subject: [PATCH 114/227] Deactivate satchels on disconnect. --- dlls/client.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dlls/client.cpp b/dlls/client.cpp index 5d41d6ad..7354f68f 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -110,14 +110,12 @@ void ClientDisconnect( edict_t *pEntity ) WRITE_STRING( text ); MESSAGE_END(); - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); + CSound *pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); + + // since this client isn't around to think anymore, reset their sound. + if( pSound ) { - // since this client isn't around to think anymore, reset their sound. - if( pSound ) - { - pSound->Reset(); - } + pSound->Reset(); } // since the edict doesn't get deleted, fix it so it doesn't interfere. @@ -125,6 +123,12 @@ void ClientDisconnect( edict_t *pEntity ) pEntity->v.solid = SOLID_NOT;// nonsolid UTIL_SetOrigin( &pEntity->v, pEntity->v.origin ); + CBasePlayer *pl = (CBasePlayer *)CBaseEntity::Instance( pEntity ); + if( pl->HasNamedPlayerItem( "weapon_satchel" ) ) + { + DeactivateSatchels( pl ); + } + g_pGameRules->ClientDisconnected( pEntity ); } From 780b4616fe420f3d9ab24d68bcc51ab172e4b1d0 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 02:41:23 +0500 Subject: [PATCH 115/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/c98747a35e324dca2d88c13036f1f74947caba96 --- dlls/rpg.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index fb2b39c8..021ad534 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -460,6 +460,8 @@ void CRpg::PrimaryAttack() m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; + + ResetEmptySound(); } else { @@ -487,13 +489,13 @@ void CRpg::WeaponIdle( void ) { UpdateSpot(); - ResetEmptySound(); - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { + ResetEmptySound(); + int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if( flRand <= 0.75 || m_fSpotActive ) From 2cb20f7b7556306d08306e6615a93bf5d4f25a7a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 02:43:50 +0500 Subject: [PATCH 116/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/274bd297f9af9cc251447dafc97de26019f0ed20 --- dlls/python.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/python.cpp b/dlls/python.cpp index b7e48386..90606c50 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -169,7 +169,7 @@ void CPython::PrimaryAttack() Reload(); else { - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM ); + PlayEmptySound(); m_flNextPrimaryAttack = 0.15; } From c4820ad0df7bda569275452ad8f25c60d00301f9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:12:53 +0500 Subject: [PATCH 117/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/89efd616d6aed0304db5bf63bfecd311c1cedbdd --- dlls/subs.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/subs.cpp b/dlls/subs.cpp index 5ebe757b..4654363a 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -107,6 +107,13 @@ void CBaseEntity::UpdateOnRemove( void ) if( pev->globalname ) gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); + + // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. + //Killtarget didn't do this before, so the counter broke. - Solokiller + if( CBaseEntity* pOwner = pev->owner ? Instance( pev->owner ) : 0 ) + { + pOwner->DeathNotice( this ); + } } // Convenient way to delay removing oneself From f22f1331afc052a70921e3bb0421c7c205a14bb2 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:25:39 +0500 Subject: [PATCH 118/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/2219190a09711ecbb441ec7160315eccac194dea --- dlls/controller.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dlls/controller.cpp b/dlls/controller.cpp index bfa119d3..b042949e 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -47,6 +47,7 @@ public: void Spawn( void ); void Precache( void ); + void UpdateOnRemove(); void SetYawSpeed( void ); int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); @@ -384,6 +385,23 @@ void CController::Precache() UTIL_PrecacheOther( "controller_head_ball" ); } +void CController::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + if( m_pBall[0] ) + { + UTIL_Remove( m_pBall[0] ); + m_pBall[0] = nullptr; + } + + if( m_pBall[1] ) + { + UTIL_Remove( m_pBall[1] ); + m_pBall[1] = nullptr; + } +} + //========================================================= // AI Schedules Specific to this monster //========================================================= From 6379954153e2c0c0001139b7f7dce9835b17da15 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:32:53 +0500 Subject: [PATCH 119/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/e41b164fdffef1b89aa5286ae15c9617dfcf2188 https://github.com/SamVanheer/HLEnhanced/commit/2da0a12d353f2078f1e2f6d931deb9c0f04e5b43 --- dlls/gargantua.cpp | 14 ++++++++++++++ dlls/islave.cpp | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index 7f60b401..6aa6a738 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -200,6 +200,7 @@ class CGargantua : public CBaseMonster public: void Spawn( void ); void Precache( void ); + void UpdateOnRemove(); void SetYawSpeed( void ); int Classify( void ); int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); @@ -802,6 +803,19 @@ void CGargantua::Precache() PRECACHE_SOUND( (char *)pBreatheSounds[i] ); } +void CGargantua::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + if( m_pEyeGlow ) + { + UTIL_Remove( m_pEyeGlow ); + m_pEyeGlow = 0; + } + + FlameDestroy(); +} + void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { ALERT( at_aiconsole, "CGargantua::TraceAttack\n" ); diff --git a/dlls/islave.cpp b/dlls/islave.cpp index 3b4343d3..51def5d3 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -44,6 +44,7 @@ class CISlave : public CSquadMonster public: void Spawn( void ); void Precache( void ); + void UpdateOnRemove(); void SetYawSpeed( void ); int ISoundMask( void ); int Classify( void ); @@ -557,6 +558,13 @@ void CISlave::Precache() UTIL_PrecacheOther( "test_effect" ); } +void CISlave::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + ClearBeams(); +} + //========================================================= // TakeDamage - get provoked when injured //========================================================= From 95d81733fcc5cb152d9b71224fe4a60de52263bc Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:41:48 +0500 Subject: [PATCH 120/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/29947a0558967e43ead0c4558251c6f77924b3ea --- dlls/tripmine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 520206dd..60190604 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -43,6 +43,7 @@ class CTripmineGrenade : public CGrenade { void Spawn( void ); void Precache( void ); + void UpdateOnRemove(); virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); @@ -148,6 +149,13 @@ void CTripmineGrenade::Precache( void ) PRECACHE_SOUND( "weapons/mine_charge.wav" ); } +void CTripmineGrenade::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + KillBeam(); +} + void CTripmineGrenade::WarningThink( void ) { // play warning sound From 9c85e5eb77e81b642836bad53ddeaa72a6284c02 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:46:20 +0500 Subject: [PATCH 121/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/b3cf83bbf11e0f098382f27f63d0364043306a03 --- dlls/turret.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/turret.cpp b/dlls/turret.cpp index 5b9e1b77..ae95db14 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -56,6 +56,7 @@ class CBaseTurret : public CBaseMonster public: void Spawn( void ); virtual void Precache( void ); + void UpdateOnRemove(); void KeyValue( KeyValueData *pkvd ); void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); @@ -279,6 +280,17 @@ void CBaseTurret::Precache() PRECACHE_SOUND( "turret/tu_alert.wav" ); } +void CBaseTurret::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + if( m_pEyeGlow ) + { + UTIL_Remove( m_pEyeGlow ); + m_pEyeGlow = 0; + } +} + #define TURRET_GLOW_SPRITE "sprites/flare3.spr" void CTurret::Spawn() From 9bb5cb2f05391097453a27b51b671044189f320e Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 03:56:48 +0500 Subject: [PATCH 122/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/46ea4af5f8dc168d048b2cada03308e9c4c3069d --- dlls/nihilanth.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 479a2b34..82b31e13 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -34,6 +34,7 @@ public: void Spawn( void ); void Precache( void ); + void UpdateOnRemove(); int Classify( void ) { return CLASS_ALIEN_MILITARY; }; int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } void Killed( entvars_t *pevAttacker, int iGib ); @@ -345,6 +346,26 @@ void CNihilanth::Precache( void ) PRECACHE_SOUND( "debris/beamstart7.wav" ); } +void CNihilanth::UpdateOnRemove() +{ + CBaseEntity::UpdateOnRemove(); + + if( m_pBall ) + { + UTIL_Remove( m_pBall ); + m_pBall = 0; + } + + for( int i = 0; i < N_SPHERES, i++ ) + { + if( CBaseEntity* pSphere = (CBaseEntity *)m_hSphere[i] ) + { + UTIL_Remove( pSphere ); + m_hSphere[i] = 0; + } + } +} + void CNihilanth::PainSound( void ) { if( m_flNextPainSound > gpGlobals->time ) From 3ad3004dd900f5bfaecf2d57bead3e34d2fc5785 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 04:03:22 +0500 Subject: [PATCH 123/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/3e2f7e1e81af06d092f6350e58b26dfeb699ebc6 --- dlls/controller.cpp | 4 ++-- dlls/crowbar.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/controller.cpp b/dlls/controller.cpp index b042949e..e1d57517 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -392,13 +392,13 @@ void CController::UpdateOnRemove() if( m_pBall[0] ) { UTIL_Remove( m_pBall[0] ); - m_pBall[0] = nullptr; + m_pBall[0] = 0; } if( m_pBall[1] ) { UTIL_Remove( m_pBall[1] ); - m_pBall[1] = nullptr; + m_pBall[1] = 0; } } diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index b00a0ad3..65e21162 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -139,8 +139,10 @@ void CCrowbar::PrimaryAttack() { if( !Swing( 1 ) ) { +#ifndef CLIENT_DLL SetThink( &CCrowbar::SwingAgain ); pev->nextthink = gpGlobals->time + 0.1; +#endif } } @@ -301,11 +303,11 @@ int CCrowbar::Swing( int fFirst ) } m_pPlayer->m_iWeaponVolume = (int)( flVol * CROWBAR_WALLHIT_VOLUME ); -#endif - m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; +#endif + m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); } return fDidHit; } From 740a5a2c31b799dd3f8bd4e5312451489e3cafbe Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 16:42:08 +0500 Subject: [PATCH 124/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/2baa8fe118db844968b2868d378d93b9f7f4f742 --- dlls/weapons.cpp | 7 +++++++ dlls/weapons.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 989c32a8..854425ad 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1557,6 +1557,13 @@ TYPEDESCRIPTION CEgon::m_SaveData[] = IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ) +TYPEDESCRIPTION CHgun::m_SaveData[] = +{ + DEFINE_FIELD( CHgun, m_flRechargeTime, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CHgun, CBasePlayerWeapon ) + TYPEDESCRIPTION CSatchel::m_SaveData[] = { DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), diff --git a/dlls/weapons.h b/dlls/weapons.h index 7bb1b486..6f5de37a 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -841,6 +841,11 @@ private: class CHgun : public CBasePlayerWeapon { public: +#ifndef CLIENT_DLL + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +#endif void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 4; } From 4024c29caf23984191d601bce7e17c5276b83632 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 16:45:48 +0500 Subject: [PATCH 125/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/7002f8fb477c03b44ec2251b1308f4e5432cb50e --- cl_dll/ammo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 860cde42..3d214280 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -542,7 +542,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) } else { - if ( m_pWeapon ) + if( m_pWeapon ) SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); } @@ -574,6 +574,8 @@ int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) if( iId < 1 ) { SetCrosshair( 0, nullrc, 0, 0, 0 ); + // Clear out the weapon so we don't keep drawing the last active weapon's ammo. - Solokiller + m_pWeapon = 0; return 0; } From ca7464b158c5ad69c504168cd249dce4135d1a5d Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 16:51:43 +0500 Subject: [PATCH 126/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/60a45fb6cd027168e2c546d64f1176ed830070d8 --- dlls/weapons.cpp | 2 ++ dlls/weapons.h | 1 + 2 files changed, 3 insertions(+) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 854425ad..ff083ee7 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -598,6 +598,8 @@ BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) void CBasePlayerWeapon::ItemPostFrame( void ) { + WeaponTick(); + if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. diff --git a/dlls/weapons.h b/dlls/weapons.h index 6f5de37a..a7c40678 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -318,6 +318,7 @@ public: virtual void PrimaryAttack( void ) { return; } // do "+ATTACK" virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2" virtual void Reload( void ) { return; } // do "+RELOAD" + virtual void WeaponTick() {} // Always called at beginning of ItemPostFrame. - Solokiller virtual void WeaponIdle( void ) { return; } // called when no buttons pressed virtual int UpdateClientData( CBasePlayer *pPlayer ); // sends hud info to client dll, if things have changed virtual void RetireWeapon( void ); From e5f6f7d9acbc35795cb20cbd7e09bd6e45afd6b9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 16:58:26 +0500 Subject: [PATCH 127/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/0cbbe099f3170170d41683c2a4288d1f06aad048 --- dlls/shotgun.cpp | 17 ++++++++++------- dlls/weapons.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index d6be007a..12e73ede 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -169,7 +169,7 @@ void CShotgun::PrimaryAttack() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - if( m_iClip != 0 ) + //if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.5; m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); @@ -240,7 +240,7 @@ void CShotgun::SecondaryAttack( void ) // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - if( m_iClip != 0 ) + //if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.95; m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); @@ -299,18 +299,21 @@ void CShotgun::Reload( void ) } } -void CShotgun::WeaponIdle( void ) +void CShotgun::WeaponTick() { - 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; } +} + +void CShotgun::WeaponIdle( void ) +{ + ResetEmptySound(); + + m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { diff --git a/dlls/weapons.h b/dlls/weapons.h index a7c40678..7d99e8a6 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -632,6 +632,7 @@ public: void SecondaryAttack( void ); BOOL Deploy( ); void Reload( void ); + void WeaponTick(); void WeaponIdle( void ); int m_fInReload; float m_flNextReload; From 689316912ac98dbd928caacaf73436130e391a28 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 17:06:23 +0500 Subject: [PATCH 128/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/19396936af13e417e7f9eaf48c48c49699da03fb --- cl_dll/ev_hldm.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 787e1be8..381c9179 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1430,6 +1430,12 @@ void EV_EgonFire( event_args_t *args ) } else { + // If there is any sound playing already, kill it. - Solokiller + // This is necessary because multiple sounds can play on the same channel at the same time. + // In some cases, more than 1 run sound plays when the egon stops firing, in which case only the earliest entry in the list is stopped. + // This ensures no more than 1 of those is ever active at the same time. + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); + if( iFireMode == FIRE_WIDE ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); else @@ -1438,7 +1444,7 @@ void EV_EgonFire( event_args_t *args ) //Only play the weapon anims if I shot it. if( EV_IsLocal( idx ) ) - gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[gEngfuncs.pfnRandomLong( 0, 3 )], 1 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( g_fireAnims1[gEngfuncs.pfnRandomLong( 0, 3 )], 1 ); if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. { From 55c3eb674c83cd511a34ea769885cbd6e43f09ad Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 17:39:50 +0500 Subject: [PATCH 129/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/35fd286ccaf7426a95baf30e682410510fe77083 --- dlls/monsters.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index 5f112a62..a9796a80 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -3357,6 +3357,9 @@ CBaseEntity *CBaseMonster::DropItem( const char *pszItemName, const Vector &vecP // do we want this behavior to be default?! (sjb) pItem->pev->velocity = pev->velocity; pItem->pev->avelocity = Vector( 0, RANDOM_FLOAT( 0, 100 ), 0 ); + + // Dropped items should never respawn (unless this rule changes in the future). - Solokiller + pItem->pev->spawnflags |= SF_NORESPAWN; return pItem; } else From 33ba064b88d9b0e818009049aef13f53bd16ae20 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 17:53:04 +0500 Subject: [PATCH 130/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/4dfa6b8710a0a30761b298a02bee21c65f056327 --- cl_dll/ev_hldm.cpp | 2 -- dlls/crowbar.cpp | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 381c9179..7d2464e8 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1159,8 +1159,6 @@ void EV_Crowbar( event_args_t *args ) if( EV_IsLocal( idx ) ) { - gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 ); - switch( (g_iSwing++) % 3 ) { case 0: diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 65e21162..98808e14 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -183,9 +183,12 @@ int CCrowbar::Swing( int fFirst ) } } #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( fFirst ) + { + 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 ) { From 033bbbcd80bce28b4a5b25f5362e28d43b909474 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 18:04:09 +0500 Subject: [PATCH 131/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/3680342c619bf2efef9a8e2e99c72f4469a89bbd --- cl_dll/ammo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 3d214280..f439520e 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -536,7 +536,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) if( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) { - static wrect_t nullrc; + wrect_t nullrc = {}; gpActiveSel = NULL; SetCrosshair( 0, nullrc, 0, 0, 0 ); } @@ -556,7 +556,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) // int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) { - static wrect_t nullrc; + wrect_t nullrc = {}; int fOnTarget = FALSE; BEGIN_READ( pbuf, iSize ); From 6f44185a645266d2fb7ea8bc5136b6b57f650a61 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 18:31:35 +0500 Subject: [PATCH 132/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/0398781544bce0766545fbbb8ac8367e3db6c86b --- cl_dll/ev_hldm.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 7d2464e8..7bb3a797 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -521,16 +521,17 @@ void EV_FireGlock2( event_args_t *args ) VectorCopy( args->origin, origin ); VectorCopy( args->angles, angles ); VectorCopy( args->velocity, velocity ); + int empty = args->bparam1; AngleVectors( angles, forward, right, up ); - shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/shell.mdl" );// brass shell if( EV_IsLocal( idx ) ) { // Add muzzle flash to current weapon model EV_MuzzleFlash(); - gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); V_PunchAxis( 0, -2.0 ); } From e7b324da5ebd26b0eae9c080911fd40c6ca478fb Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 19:17:59 +0500 Subject: [PATCH 133/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/19c8e45d8f92d0e09171f9f1b5b3fd0f25d109b6 --- dlls/mp5.cpp | 6 ++++++ dlls/weapons.h | 1 + 2 files changed, 7 insertions(+) diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 7131f888..a13257a1 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -270,6 +270,12 @@ void CMP5::WeaponIdle( void ) m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. } +BOOL CMP5::IsUseable() +{ + //Can be used if the player has AR grenades. - Solokiller + return CBasePlayerWeapon::IsUseable() || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] > 0; +} + class CMP5AmmoClip : public CBasePlayerAmmo { void Spawn( void ) diff --git a/dlls/weapons.h b/dlls/weapons.h index 7d99e8a6..86e9c7f6 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -563,6 +563,7 @@ public: BOOL Deploy( void ); void Reload( void ); void WeaponIdle( void ); + BOOL IsUseable(); float m_flNextAnimTime; int m_iShell; From 19bdc1d01b7287cd61b58fb7b7bdb6953caa50a8 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 19:48:01 +0500 Subject: [PATCH 134/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/33413807d0ca23f3d9121e45f5584cb5be98751b --- dlls/gauss.cpp | 36 ++++++++++++++++++++++++++---------- dlls/weapons.h | 2 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 93352b57..0ebb876c 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -123,6 +123,12 @@ int CGauss::GetItemInfo( ItemInfo *p ) return 1; } +BOOL CGauss::IsUseable() +{ + // Currently charging, allow the player to fire it first. - Solokiller + return CBasePlayerWeapon::IsUseable() || m_InAttack != 0; +} + BOOL CGauss::Deploy() { m_pPlayer->m_flPlayAftershock = 0.0; @@ -224,6 +230,22 @@ void CGauss::SecondaryAttack() } else { + // Moved to before the ammo burn. + // Because we drained 1 when m_InAttack == 0, then 1 again now before checking if we're out of ammo, + // this resuled in the player having -1 ammo, which in turn caused CanDeploy to think it could be deployed. + // This will need to be fixed further down the line by preventing negative ammo unless explicitly required (infinite ammo?), + // But this check will prevent the problem for now. - Solokiller + // TODO: investigate further. + 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; + } + // 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 ) { @@ -243,16 +265,6 @@ void CGauss::SecondaryAttack() } } - 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. @@ -558,6 +570,10 @@ void CGauss::WeaponIdle( void ) StartFire(); m_fInAttack = 0; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; + + // Need to set m_flNextPrimaryAttack so the weapon gets a chance to complete its secondary fire animation. - Solokiller + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; } else { diff --git a/dlls/weapons.h b/dlls/weapons.h index 86e9c7f6..736dadd4 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -741,7 +741,7 @@ public: int iItemSlot( void ) { return 4; } int GetItemInfo(ItemInfo *p); int AddToPlayer( CBasePlayer *pPlayer ); - + BOOL IsUseable(); BOOL Deploy( void ); void Holster( int skiplocal = 0 ); From 9ef79aee9ef6924dfdfe2ec1538dc0d26fe8a0f8 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 21:44:06 +0500 Subject: [PATCH 135/227] Merge https://github.com/ValveSoftware/halflife/pull/1720/commits/6f020090bd75706174012bb080fce8f4b6a2d187 --- dlls/rpg.cpp | 8 ++++---- dlls/weapons.cpp | 2 +- dlls/weapons.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 021ad534..5fb8cc70 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -109,8 +109,8 @@ CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBa 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->m_hLauncher = pLauncher;// remember what RPG fired me. + pLauncher->m_cActiveRockets++;// register this missile as active for the launcher pRocket->pev->owner = pOwner->edict(); return pRocket; @@ -150,10 +150,10 @@ void CRpgRocket::Spawn( void ) //========================================================= void CRpgRocket::RocketTouch( CBaseEntity *pOther ) { - if( m_pLauncher ) + if( CRpg* pLauncher = (CRpg*)( (CBaseEntity*)( m_hLauncher ) ) ) { // my launcher is still around, tell it I'm dead. - m_pLauncher->m_cActiveRockets--; + pLauncher->m_cActiveRockets--; } STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ff083ee7..bc508c6a 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1518,7 +1518,7 @@ IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ) TYPEDESCRIPTION CRpgRocket::m_SaveData[] = { DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), + DEFINE_FIELD( CRpgRocket, m_hLauncher, FIELD_EHANDLE ), }; IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ) diff --git a/dlls/weapons.h b/dlls/weapons.h index 736dadd4..3d8dd6ad 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -725,7 +725,7 @@ public: int m_iTrail; float m_flIgniteTime; - CRpg *m_pLauncher;// pointer back to the launcher that fired me. + EHANDLE m_hLauncher; // handle back to the launcher that fired me. }; class CGauss : public CBasePlayerWeapon From e98f45b2796670989b9ac219cbe99f4df9845e51 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 21:53:57 +0500 Subject: [PATCH 136/227] Merge https://github.com/ValveSoftware/halflife/pull/1599 --- dlls/weapons.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index bc508c6a..61b038c0 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -578,6 +578,13 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? + + // If the item is falling and its Think remains FallItem after the player picks it up, + // then after the item touches the ground its Touch will be set back to DefaultTouch, + // so the player will pick it up again, this time Kill-ing the item (since we already have it in the inventory), + // which will make the pointer bad and crash the game. + if( m_pfnThink == &CBasePlayerItem::FallThink ) + SetThink( NULL ); } BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) From cf5b2f9e14fdc87f3c58b8780834fffd9cec8fd7 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 5 Jul 2017 23:50:55 +0500 Subject: [PATCH 137/227] Merge https://github.com/ValveSoftware/halflife/pull/1601 --- cl_dll/cdll_int.cpp | 14 ++++++++++++++ dlls/client.cpp | 14 +++++++++++++- dlls/game.cpp | 2 ++ dlls/player.cpp | 13 +++++++++++++ dlls/player.h | 10 ++++++---- pm_shared/pm_shared.c | 13 ++++++++----- 6 files changed, 56 insertions(+), 10 deletions(-) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index ffd342d2..d71659e9 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -21,6 +21,7 @@ #include "hud.h" #include "cl_util.h" #include "netadr.h" +#include "parsemsg.h" extern "C" { @@ -32,10 +33,21 @@ extern "C" cl_enginefunc_t gEngfuncs; CHud gHUD; mobile_engfuncs_t *gMobileEngfuncs = NULL; + +extern "C" int g_bhopcap; void InitInput( void ); void EV_HookEvents( void ); void IN_Commands( void ); +int __MsgFunc_Bhopcap( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + g_bhopcap = READ_BYTE(); + + return 1; +} + /* ========================== Initialize @@ -196,6 +208,8 @@ void DLLEXPORT HUD_Init( void ) { InitInput(); gHUD.Init(); + + gEngfuncs.pfnHookUserMsg( "Bhopcap", __MsgFunc_Bhopcap ); } /* diff --git a/dlls/client.cpp b/dlls/client.cpp index 7354f68f..1fead362 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -48,11 +48,15 @@ extern DLL_GLOBAL ULONG g_ulFrameCount; extern void CopyToBodyQue( entvars_t* pev ); extern int giPrecacheGrunt; extern int gmsgSayText; +extern int gmsgBhopcap; extern cvar_t allow_spectators; extern int g_teamplay; +extern cvar_t bhopcap; +extern "C" int g_bhopcap; + void LinkUserMessages( void ); /* @@ -799,8 +803,16 @@ void StartFrame( void ) gpGlobals->teamplay = teamplay.value; g_ulFrameCount++; -} + int oldBhopcap = g_bhopcap; + g_bhopcap = ( g_pGameRules->IsMultiplayer() && bhopcap.value != 0.0f ) ? 1 : 0; + if( g_bhopcap != oldBhopcap ) + { + MESSAGE_BEGIN( MSG_ALL, gmsgBhopcap, NULL ); + WRITE_BYTE( g_bhopcap ); + MESSAGE_END(); + } +} void ClientPrecache( void ) { diff --git a/dlls/game.cpp b/dlls/game.cpp index fb247903..7905075a 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -38,6 +38,7 @@ 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 bhopcap = { "mp_bhopcap", "1", FCVAR_SERVER }; cvar_t allow_spectators = { "allow_spectators", "0", FCVAR_SERVER }; // 0 prevents players from being spectators @@ -473,6 +474,7 @@ void GameDLLInit( void ) CVAR_REGISTER( &teamoverride ); CVAR_REGISTER( &defaultteam ); CVAR_REGISTER( &allowmonsters ); + CVAR_REGISTER( &bhopcap ); CVAR_REGISTER( &mp_chattime ); diff --git a/dlls/player.cpp b/dlls/player.cpp index 51995acf..b838f35f 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -45,6 +45,8 @@ extern DLL_GLOBAL BOOL g_fDrawLines; int gEvilImpulse101; extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; +extern "C" int g_bhopcap; + BOOL gInitHUD = TRUE; extern void CopyToBodyQue( entvars_t *pev); @@ -181,6 +183,7 @@ int gmsgSetFOV = 0; int gmsgShowMenu = 0; int gmsgGeigerRange = 0; int gmsgTeamNames = 0; +int gmsgBhopcap = 0; int gmsgStatusText = 0; int gmsgStatusValue = 0; @@ -227,6 +230,7 @@ void LinkUserMessages( void ) gmsgFade = REG_USER_MSG( "ScreenFade", sizeof(ScreenFade) ); gmsgAmmoX = REG_USER_MSG( "AmmoX", 2 ); gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 ); + gmsgBhopcap = REG_USER_MSG( "Bhopcap", 1 ); gmsgStatusText = REG_USER_MSG( "StatusText", -1 ); gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 ); @@ -4072,6 +4076,15 @@ void CBasePlayer::UpdateClientData( void ) UpdateStatusBar(); m_flNextSBarUpdateTime = gpGlobals->time + 0.2; } + + // Send the current bhopcap state. + if( !m_bSentBhopcap ) + { + m_bSentBhopcap = true; + MESSAGE_BEGIN( MSG_ONE, gmsgBhopcap, NULL, pev ); + WRITE_BYTE( g_bhopcap ); + MESSAGE_END(); + } } //========================================================= diff --git a/dlls/player.h b/dlls/player.h index b2dce868..8ff312ea 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -313,13 +313,15 @@ public: //Player ID void InitStatusBar( void ); void UpdateStatusBar( void ); - int m_izSBarState[ SBAR_END ]; + int m_izSBarState[SBAR_END]; float m_flNextSBarUpdateTime; float m_flStatusBarDisappearDelay; - char m_SbarString0[ SBAR_STRING_SIZE ]; - char m_SbarString1[ SBAR_STRING_SIZE ]; + char m_SbarString0[SBAR_STRING_SIZE]; + char m_SbarString1[SBAR_STRING_SIZE]; float m_flNextChatTime; + + bool m_bSentBhopcap; // If false, the player just joined and needs a bhopcap message. }; #define AUTOAIM_2DEGREES 0.0348994967025 @@ -327,7 +329,7 @@ public: #define AUTOAIM_8DEGREES 0.1391731009601 #define AUTOAIM_10DEGREES 0.1736481776669 -extern int gmsgHudText; +extern int gmsgHudText; extern BOOL gInitHUD; #endif // PLAYER_H diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index c709ba14..9aed8093 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -27,11 +27,13 @@ #include // atoi #include // isspace +int g_bhopcap = 1; + #ifdef CLIENT_DLL - // Spectator Mode - int iJumpSpectator; -extern float vJumpOrigin[3]; -extern float vJumpAngles[3]; +// Spectator Mode +int iJumpSpectator; +extern float vJumpOrigin[3]; +extern float vJumpAngles[3]; #endif static int pm_shared_initialized = 0; @@ -2556,7 +2558,8 @@ void PM_Jump( void ) // In the air now. pmove->onground = -1; - PM_PreventMegaBunnyJumping(); + if( g_bhopcap ) + PM_PreventMegaBunnyJumping(); if( tfc ) { From 85edea072b35d0dce99f60ad5fb11a1cd82e3e67 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 00:10:06 +0500 Subject: [PATCH 138/227] Merge https://github.com/ValveSoftware/halflife/pull/1590/commits/136de25b61689ee30ca0206e6737c7d06be77567 --- cl_dll/menu.cpp | 10 ++++++---- cl_dll/text_message.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index 5f710a33..fc24b917 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -83,7 +83,7 @@ int CHudMenu::Draw( float flTime ) int nlc = 0; for( i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) { - if ( g_szMenuString[i] == '\n' ) + if( g_szMenuString[i] == '\n' ) nlc++; } @@ -153,19 +153,21 @@ int CHudMenu::MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) else { // append to the current menu string - strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen( g_szPrelocalisedMenuString ) ); + strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen( g_szPrelocalisedMenuString ) - 1 ); } g_szPrelocalisedMenuString[MAX_MENU_STRING - 1] = 0; // ensure null termination (strncat/strncpy does not) if( !NeedMore ) { // we have the whole string, so we can localise it now - strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + strncpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ), MAX_MENU_STRING ); + g_szMenuString[MAX_MENU_STRING - 1] = '\0'; // Swap in characters if( KB_ConvertString( g_szMenuString, &temp ) ) { - strcpy( g_szMenuString, temp ); + strncpy( g_szMenuString, temp, MAX_MENU_STRING ); + g_szMenuString[MAX_MENU_STRING - 1] = '\0'; free( temp ); } } diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index 58dae6f7..9452cebb 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -45,14 +45,15 @@ int CHudTextMessage::Init( void ) char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ) { char *dst = dst_buffer; - for( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- ) + for( char *src = (char*)msg; *src != 0 && ( buffer_size - 1 ) > 0; buffer_size-- ) { if( *src == '#' ) { // cut msg name out of string static char word_buf[255]; char *wdst = word_buf, *word_start = src; - for( ++src; ( *src >= 'A' && *src <= 'z' ) || ( *src >= '0' && *src <= '9' ); wdst++, src++ ) + int wordbuf_size = (int)sizeof(word_buf); + for( ++src; ( ( *src >= 'A' && *src <= 'z' ) || ( *src >= '0' && *src <= '9' ) ) && ( wordbuf_size - 1 ) > 0; wdst++, src++, wordbuf_size-- ) { *wdst = *src; } @@ -69,21 +70,20 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in } // copy string into message over the msg name - for( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ ) + for( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0 && ( buffer_size - 1 ) > 0; wsrc++, dst++, buffer_size-- ) { *dst = *wsrc; } - *dst = 0; + buffer_size++; } else { *dst = *src; dst++, src++; - *dst = 0; } } - dst_buffer[buffer_size - 1] = 0; // ensure null termination + *dst = 0; // ensure null termination return dst_buffer; } From 495c7717242f0315fced701c57dee242b48f66af Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 00:20:29 +0500 Subject: [PATCH 139/227] Update mp5.cpp. --- dlls/mp5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index a13257a1..403efa04 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -238,7 +238,7 @@ void CMP5::SecondaryAttack( void ) void CMP5::Reload( void ) { - if( m_pPlayer->ammo_9mm <= 0 ) + if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == MP5_MAX_CLIP ) return; DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); From b66f1cb39400e586d7a2ef8eca44c2f14c226e69 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 00:25:22 +0500 Subject: [PATCH 140/227] Update glock.cpp. --- dlls/glock.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/glock.cpp b/dlls/glock.cpp index 4e679750..3eb08d6c 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -109,7 +109,7 @@ void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ) if( m_fFireOnEmpty ) { PlayEmptySound(); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.2 ); } return; @@ -158,7 +158,7 @@ void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ) 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 = UTIL_WeaponTimeBase() + flCycleTime; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = GetNextAttackDelay( flCycleTime ); if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) // HEV suit - indicate out of ammo condition From 6e1059026faa90c5bfe5e3b3f4f58fde398d4524 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 00:41:13 +0500 Subject: [PATCH 141/227] Do not detonate hand grenade after weapon switch. --- dlls/handgrenade.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 96119b6b..2a31fc84 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -103,6 +103,12 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) pev->nextthink = gpGlobals->time + 0.1; } + if( m_flStartThrow ) + { + m_flStartThrow = 0; + m_flReleaseThrow = 0; + } + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); } From b7d1bd3235790026cf0d3e66053ba155f2b0a07a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 00:44:14 +0500 Subject: [PATCH 142/227] Merge fix for blocked door sound from bubblemod. --- dlls/doors.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/doors.cpp b/dlls/doors.cpp index dcb04e00..231a3753 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -750,6 +750,11 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) // so let it just squash the object to death real fast if( m_flWait >= 0 ) { + // BMod Start - Door sound fix. + if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) + STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ) ); + // BMod End + if( m_toggle_state == TS_GOING_DOWN ) { DoorGoUp(); From bdd3e74ebd3fbf7f7d4d20cdf2e85c8f981309a3 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 02:30:10 +0500 Subject: [PATCH 143/227] Detonate satchels under blocked door. --- dlls/doors.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 231a3753..3a8613ab 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -22,6 +22,7 @@ #include "util.h" #include "cbase.h" #include "doors.h" +#include "weapons.h" extern void SetMovedir( entvars_t *ev ); @@ -746,6 +747,10 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) if( pev->dmg ) pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); + // Detonate satchels + if( !strcmp( "monster_satchel", STRING( pOther->pev->classname ) ) ) + ( (CSatchel*)pOther )->Use( this, this, USE_ON, 0 ); + // 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 ) From c6b353e09287048fb42cd4811b5854ded5ce93bc Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 02:35:32 +0500 Subject: [PATCH 144/227] Fix build. --- dlls/gauss.cpp | 2 +- dlls/nihilanth.cpp | 2 +- dlls/subs.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 0ebb876c..d3e005c2 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -126,7 +126,7 @@ int CGauss::GetItemInfo( ItemInfo *p ) BOOL CGauss::IsUseable() { // Currently charging, allow the player to fire it first. - Solokiller - return CBasePlayerWeapon::IsUseable() || m_InAttack != 0; + return CBasePlayerWeapon::IsUseable() || m_fInAttack != 0; } BOOL CGauss::Deploy() diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 82b31e13..1f9b0f88 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -356,7 +356,7 @@ void CNihilanth::UpdateOnRemove() m_pBall = 0; } - for( int i = 0; i < N_SPHERES, i++ ) + for( int i = 0; i < N_SPHERES; i++ ) { if( CBaseEntity* pSphere = (CBaseEntity *)m_hSphere[i] ) { diff --git a/dlls/subs.cpp b/dlls/subs.cpp index 4654363a..2a299ce4 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -112,7 +112,7 @@ void CBaseEntity::UpdateOnRemove( void ) //Killtarget didn't do this before, so the counter broke. - Solokiller if( CBaseEntity* pOwner = pev->owner ? Instance( pev->owner ) : 0 ) { - pOwner->DeathNotice( this ); + pOwner->DeathNotice( pev ); } } From f575e78a9b7320db15025e94c1d1bb2cd1922a60 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 6 Jul 2017 03:47:59 +0500 Subject: [PATCH 145/227] Register allow_spectators cvar. --- dlls/game.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/game.cpp b/dlls/game.cpp index 7905075a..9b69cac9 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -455,6 +455,7 @@ void GameDLLInit( void ) g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); CVAR_REGISTER( &displaysoundlist ); + CVAR_REGISTER( &allow_spectators ); CVAR_REGISTER( &teamplay ); CVAR_REGISTER( &fraglimit ); From 4d1dc131b924dedbb03bf40eb4bb64bd1c624f1a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 8 Jul 2017 20:06:00 +0500 Subject: [PATCH 146/227] Fix mistakes with saverestore after merge. --- dlls/util.cpp | 2 +- engine/eiface.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index d79c9f5a..f4b09cb1 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1890,7 +1890,7 @@ void CSave::WriteFunction( const char *pname, void **data, int count ) { const char *functionName; - functionName = NAME_FOR_FUNCTION( (unsigned int)(size_t)*data ); + functionName = NAME_FOR_FUNCTION( (size_t)*data ); if( functionName ) BufferField( pname, strlen( functionName ) + 1, functionName ); else diff --git a/engine/eiface.h b/engine/eiface.h index 30f8a82a..23cb17f8 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -172,8 +172,8 @@ typedef struct enginefuncs_s int (*pfnRegUserMsg)( const char *pszName, int iSize ); void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); - unsigned int (*pfnFunctionFromName)( const char *pName ); - const char *(*pfnNameForFunction)( unsigned int function ); + size_t (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( size_t function ); void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients void (*pfnServerPrint)( const char *szMsg ); const char *(*pfnCmd_Args)( void ); // these 3 added From c16e1ecfef45f5a6b67ff470051c328cc7e760b6 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 8 Jul 2017 20:13:41 +0500 Subject: [PATCH 147/227] A little fix for nodes on 64bit arches. --- dlls/nodes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/nodes.h b/dlls/nodes.h index 2b582a6f..f5ebcd84 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -104,7 +104,11 @@ typedef struct //========================================================= // CGraph //========================================================= +#if defined(__amd64__) || defined(__aarch64__) +#define GRAPH_VERSION (int)17// Was incremented for 64bit arches, because .nod-files have incombatibilities on different arches. +#else #define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. +#endif class CGraph { From 3bce17e3a04f8af10a927a07ceb8ab0f09152ec4 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sat, 8 Jul 2017 20:26:21 +0000 Subject: [PATCH 148/227] Fix saverestore on LP64 --- dlls/saverestore.h | 2 +- dlls/util.cpp | 6 +++--- engine/eiface.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/saverestore.h b/dlls/saverestore.h index f76613e8..a9ad2c54 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -59,7 +59,7 @@ public: 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, const int *value, int count ); // Save a function pointer + 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 ); diff --git a/dlls/util.cpp b/dlls/util.cpp index d1fceb0a..1c229edd 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1886,7 +1886,7 @@ void CSave::WritePositionVector( const char *pname, const float *value, int coun } } -void CSave::WriteFunction( const char *pname, const int *data, int count ) +void CSave::WriteFunction( const char *pname, void **data, int count ) { const char *functionName; @@ -1894,7 +1894,7 @@ void CSave::WriteFunction( const char *pname, const int *data, int count ) if( functionName ) BufferField( pname, strlen( functionName ) + 1, functionName ); else - ALERT( at_error, "Invalid function pointer in entity!" ); + ALERT( at_error, "Invalid function pointer in entity!\n" ); } void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) @@ -2042,7 +2042,7 @@ int CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFi WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); break; case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + WriteFunction( pTest->fieldName, (void **)pOutputData, pTest->fieldSize ); break; default: ALERT( at_error, "Bad field type\n" ); diff --git a/engine/eiface.h b/engine/eiface.h index 903451f5..b3b9d415 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -171,8 +171,8 @@ typedef struct enginefuncs_s int (*pfnRegUserMsg)( const char *pszName, int iSize ); void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); - unsigned long (*pfnFunctionFromName)( const char *pName ); - const char *(*pfnNameForFunction)( unsigned long function ); + void* (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( void *function ); void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients void (*pfnServerPrint)( const char *szMsg ); const char *(*pfnCmd_Args)( void ); // these 3 added From 9ebfc981773ec4c7a89ffe52d9c249e1fbef9634 Mon Sep 17 00:00:00 2001 From: mittorn Date: Sat, 8 Jul 2017 21:28:31 +0000 Subject: [PATCH 149/227] Fix field sizes --- dlls/util.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index 1c229edd..0298487b 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1584,6 +1584,33 @@ void UTIL_StripToken( const char *pKey, char *pDest ) // // -------------------------------------------------------------- static int gSizes[FIELD_TYPECOUNT] = +{ + sizeof(float), // FIELD_FLOAT + sizeof(int), // FIELD_STRING + sizeof(void*), // FIELD_ENTITY + sizeof(void*), // FIELD_CLASSPTR + sizeof(void*), // FIELD_EHANDLE + sizeof(void*), // FIELD_entvars_t + sizeof(void*), // FIELD_EDICT + sizeof(float) * 3, // FIELD_VECTOR + sizeof(float) * 3, // FIELD_POSITION_VECTOR + sizeof(void *), // FIELD_POINTER + sizeof(int), // FIELD_INTEGER +#ifdef GNUC + sizeof(void *) * 2, // FIELD_FUNCTION +#else + sizeof(void *), // 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 +}; + +// entities has different store size +static int gInputSizes[FIELD_TYPECOUNT] = { sizeof(float), // FIELD_FLOAT sizeof(int), // FIELD_STRING @@ -1594,12 +1621,12 @@ static int gSizes[FIELD_TYPECOUNT] = sizeof(int), // FIELD_EDICT sizeof(float) * 3, // FIELD_VECTOR sizeof(float) * 3, // FIELD_POSITION_VECTOR - sizeof(int *), // FIELD_POINTER + sizeof(void *), // FIELD_POINTER sizeof(int), // FIELD_INTEGER #ifdef GNUC - sizeof(int *) * 2, // FIELD_FUNCTION + sizeof(void *) * 2, // FIELD_FUNCTION #else - sizeof(int *), // FIELD_FUNCTION + sizeof(void *), // FIELD_FUNCTION #endif sizeof(int), // FIELD_BOOLEAN sizeof(short), // FIELD_SHORT @@ -2137,7 +2164,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou 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]; + void *pInputData = (char *)pData + j * gInputSizes[pTest->fieldType]; switch( pTest->fieldType ) { From 4d7d6f2c378f0b79fe9dd4eeb931cdb6daadd48f Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 10 Jul 2017 19:28:56 +0500 Subject: [PATCH 150/227] Turn off flashlight when player dead. --- dlls/player.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/player.cpp b/dlls/player.cpp index b838f35f..5029ce97 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -820,6 +820,9 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) else pev->weapons &= ~WEAPON_ALLWEAPONS; + // Turn off flashlight + ClearBits( pev->effects, EF_DIMLIGHT ); + for( i = 0; i < MAX_AMMO_SLOTS; i++ ) m_rgAmmo[i] = 0; From 2324270cc27d818923391f6d34319fb4cd258795 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 10 Jul 2017 22:18:45 +0500 Subject: [PATCH 151/227] Do not reduce armor value when godmode is active. --- dlls/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 5029ce97..852abca3 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -466,7 +466,7 @@ int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl m_lastDamageAmount = (int)flDamage; // Armor. - if( pev->armorvalue && !( bitsDamageType & ( DMG_FALL | DMG_DROWN ) ) )// armor doesn't protect against fall or drown damage! + if( !( pev->flags & FL_GODMODE ) && pev->armorvalue && !( bitsDamageType & ( DMG_FALL | DMG_DROWN ) ) )// armor doesn't protect against fall or drown damage! { float flNew = flDamage * flRatio; From 77d077c83dc3384ee6c6134a04657ea1259847f3 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 11 Jul 2017 01:32:53 +0500 Subject: [PATCH 152/227] Partially merge https://github.com/SamVanheer/HLEnhanced/commit/3563a1846fc8905bb7357c103212a6e10b5f048b --- dlls/plats.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 203f5d9b..a60e6706 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -248,7 +248,7 @@ 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; + EHANDLE m_pPlatform; }; /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER @@ -340,24 +340,24 @@ static void PlatSpawnInsideTrigger( entvars_t *pevPlatform ) // void CPlatTrigger::SpawnInsideTrigger( CFuncPlat *pPlatform ) { - m_pPlatform = pPlatform; + m_hPlatform = 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 ) + Vector vecTMin = pPlatform->pev->mins + Vector( 25, 25, 0 ); + Vector vecTMax = pPlatform->pev->maxs + Vector( 25, 25, 8 ); + vecTMin.z = vecTMax.z - ( pPlatform->m_vecPosition1.z - pPlatform->m_vecPosition2.z + 8 ); + if( pPlatform->pev->size.x <= 50 ) { - vecTMin.x = ( m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x ) / 2; + vecTMin.x = ( pPlatform->pev->mins.x + pPlatform->pev->maxs.x ) / 2; vecTMax.x = vecTMin.x + 1; } - if( m_pPlatform->pev->size.y <= 50 ) + if( pPlatform->pev->size.y <= 50 ) { - vecTMin.y = ( m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y ) / 2; + vecTMin.y = ( pPlatform->pev->mins.y + pPlatform->pev->maxs.y ) / 2; vecTMax.y = vecTMin.y + 1; } UTIL_SetSize( pev, vecTMin, vecTMax ); @@ -373,15 +373,17 @@ void CPlatTrigger::Touch( CBaseEntity *pOther ) if( !FClassnameIs( pevToucher, "player" ) ) return; + CFuncPlat *pPlatform = (CFuncPlat*)(CBaseEntity*)m_hPlatform; + // Ignore touches by corpses if( !pOther->IsAlive() ) 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 + if( pPlatform->m_toggle_state == TS_AT_BOTTOM ) + pPlatform->GoUp(); + else if( pPlatform->m_toggle_state == TS_AT_TOP ) + pPlatform->pev->nextthink = pPlatform->pev->ltime + 1;// delay going down } // From 2df762e705d4726d5017b670138660bc8079053a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 11 Jul 2017 01:40:26 +0500 Subject: [PATCH 153/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/f8db63a45bcc62d6110051109daca77031699df8 --- dlls/plats.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/dlls/plats.cpp b/dlls/plats.cpp index a60e6706..5d5d1f07 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -375,6 +375,13 @@ void CPlatTrigger::Touch( CBaseEntity *pOther ) CFuncPlat *pPlatform = (CFuncPlat*)(CBaseEntity*)m_hPlatform; + if( FNullEnt( pPlatform ) ) + { + // The target platform has been removed, remove myself as well. - Solokiller + UTIL_Remove( this ); + return; + } + // Ignore touches by corpses if( !pOther->IsAlive() ) return; @@ -429,7 +436,7 @@ void CFuncPlat::GoDown( void ) } // -// Platform has hit bottom. Stops and waits forever. +// Platform has hit bottom. Stops and waits forever. // void CFuncPlat::HitBottom( void ) { @@ -458,7 +465,7 @@ void CFuncPlat::GoUp( void ) } // -// Platform has hit top. Pauses, then starts back down again. +// Platform has hit top. Pauses, then starts back down again. // void CFuncPlat::HitTop( void ) { @@ -556,7 +563,7 @@ void CFuncPlatRot::GoDown( void ) } // -// Platform has hit bottom. Stops and waits forever. +// Platform has hit bottom. Stops and waits forever. // void CFuncPlatRot::HitBottom( void ) { @@ -575,7 +582,7 @@ void CFuncPlatRot::GoUp( void ) } // -// Platform has hit top. Pauses, then starts back down again. +// Platform has hit top. Pauses, then starts back down again. // void CFuncPlatRot::HitTop( void ) { @@ -857,8 +864,8 @@ void CFuncTrain::Precache( void ) 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" ); + pev->noise = MAKE_STRING( "plats/train2.wav" ); + pev->noise1 = MAKE_STRING( "plats/train1.wav" ); break; case 2: PRECACHE_SOUND( "plats/platmove1.wav" ); From 8455d693609863c48108aeaff11d9b8e3f59fb49 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 11 Jul 2017 01:58:22 +0500 Subject: [PATCH 154/227] Merge https://github.com/SamVanheer/HLEnhanced/commit/d6732ca0795e1be23bea808782eb4dfd13cbd1aa --- dlls/player.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 852abca3..9680aaf6 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -3661,7 +3661,9 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) pev->viewmodel = 0; pev->weaponmodel = 0; } - else if( m_pLastItem == pItem ) + + // In some cases an item can be both the active and last item, like for instance dropping all weapons and only having an exhaustible weapon left. - Solokiller + if( m_pLastItem == pItem ) m_pLastItem = NULL; CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()]; From 1c1d9ae18385f1a152c93f115289defbd64394ab Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 11 Jul 2017 02:24:19 +0500 Subject: [PATCH 155/227] Remove unneeded strcpy usage. --- cl_dll/com_weapons.cpp | 2 +- cl_dll/com_weapons.h | 2 +- cl_dll/ev_hldm.cpp | 19 +++++++++---------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index 774df091..5621149b 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -283,7 +283,7 @@ unsigned short stub_PrecacheEvent( int type, const char *s ) return 0; } -const char *stub_NameForFunction( unsigned int function ) +const char *stub_NameForFunction( void *function ) { return "func"; } diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index 8559e20b..0a538f0f 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -34,7 +34,7 @@ void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); int stub_PrecacheModel( const char* s ); int stub_PrecacheSound( const char* s ); unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction( unsigned int function ); +const char *stub_NameForFunction( void *function ); void stub_SetModel( struct edict_s *e, const char *m ); extern cvar_t *cl_lw; diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 7bb3a797..d94f9fea 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1695,7 +1695,7 @@ void EV_TrainPitchAdjust( event_args_t *args ) int pitch; int stop; - char sz[256]; + const char *pszSound; idx = args->entindex; @@ -1711,36 +1711,35 @@ void EV_TrainPitchAdjust( event_args_t *args ) switch( noise ) { case 1: - strcpy( sz, "plats/ttrain1.wav" ); + pszSound = "plats/ttrain1.wav"; break; case 2: - strcpy( sz, "plats/ttrain2.wav" ); + pszSound = "plats/ttrain2.wav"; break; case 3: - strcpy( sz, "plats/ttrain3.wav" ); + pszSound = "plats/ttrain3.wav"; break; case 4: - strcpy( sz, "plats/ttrain4.wav"); + pszSound = "plats/ttrain4.wav"; break; case 5: - strcpy( sz, "plats/ttrain6.wav"); + pszSound = "plats/ttrain6.wav"; break; case 6: - strcpy( sz, "plats/ttrain7.wav"); + pszSound = "plats/ttrain7.wav"; break; default: // no sound - strcpy( sz, "" ); return; } if( stop ) { - gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, pszSound ); } else { - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, pszSound, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); } } From a383a57a09351365b5b3beb78d26ec0c035df4ef Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 11 Jul 2017 02:43:24 +0500 Subject: [PATCH 156/227] Fix build. --- dlls/plats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 5d5d1f07..00b05bec 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -248,7 +248,7 @@ public: virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } void SpawnInsideTrigger( CFuncPlat *pPlatform ); void Touch( CBaseEntity *pOther ); - EHANDLE m_pPlatform; + EHANDLE m_hPlatform; }; /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER @@ -375,7 +375,7 @@ void CPlatTrigger::Touch( CBaseEntity *pOther ) CFuncPlat *pPlatform = (CFuncPlat*)(CBaseEntity*)m_hPlatform; - if( FNullEnt( pPlatform ) ) + if( !pPlatform ) { // The target platform has been removed, remove myself as well. - Solokiller UTIL_Remove( this ); From 4661b5c1a5245b27a5532745c11e44b5540e4172 Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 14 Jul 2017 13:11:58 +0000 Subject: [PATCH 157/227] Increase graph version --- dlls/nodes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/nodes.h b/dlls/nodes.h index 27b890ed..cbf1e2a6 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -103,7 +103,11 @@ typedef struct //========================================================= // CGraph //========================================================= +#ifdef __amd64 +#define GRAPH_VERSION (int)16 * 10 +#else #define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. +#endif class CGraph { From a08bd614fe524d8c827ac34810a130b6f2dc90ba Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 14 Jul 2017 13:15:17 +0000 Subject: [PATCH 158/227] Fix client build --- cl_dll/com_weapons.cpp | 2 +- cl_dll/com_weapons.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp index 4f539df9..d359a3f1 100644 --- a/cl_dll/com_weapons.cpp +++ b/cl_dll/com_weapons.cpp @@ -283,7 +283,7 @@ unsigned short stub_PrecacheEvent( int type, const char *s ) return 0; } -const char *stub_NameForFunction( unsigned long function ) +const char *stub_NameForFunction( void *function ) { return "func"; } diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index 7e1fdd77..4ce861f4 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ============ // // Purpose: // @@ -34,7 +34,7 @@ void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); int stub_PrecacheModel( char* s ); int stub_PrecacheSound( char* s ); unsigned short stub_PrecacheEvent( int type, const char *s ); -const char *stub_NameForFunction( unsigned long function ); +const char *stub_NameForFunction( void *function ); void stub_SetModel( struct edict_s *e, const char *m ); extern cvar_t *cl_lw; From 00833188dab87ef5746286479ba5aeb9d83b4a0c Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 14 Jul 2017 13:42:47 +0000 Subject: [PATCH 159/227] Use real MAKE_STRING when possible --- dlls/util.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/util.h b/dlls/util.h index e8aee878..5b00fe94 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -39,7 +39,14 @@ extern globalvars_t *gpGlobals; #if !defined __amd64__ || defined(CLIENT_DLL) #define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) #else -#define MAKE_STRING ALLOC_STRING +static inline int MAKE_STRING(const char *szValue) +{ + long long ptrdiff = szValue - STRING(0); + if( ptrdiff > INT_MAX || ptrdiff < INT_MIN ) + return ALLOC_STRING(szValue); + else + return (int)ptrdiff; +} #endif inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) From 1674a4b6d496b03da7efd689b739d721b83a9c8a Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 14 Jul 2017 15:34:44 +0000 Subject: [PATCH 160/227] Use XASH_64BIT macro --- cl_dll/cl_dll.h | 4 ++++ dlls/extdll.h | 4 ++++ dlls/nodes.h | 2 +- dlls/util.h | 2 +- engine/studio.h | 2 +- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index fda4b812..24d1874b 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -41,6 +41,10 @@ typedef int ( *pfnUserMsgHook )( const char *pszName, int iSize, void *pbuf ); #include "exportdef.h" #include +#if defined(__LP64__) || defined(__LLP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define XASH_64BIT +#endif + extern cl_enginefunc_t gEngfuncs; #include "../engine/mobility_int.h" extern mobile_engfuncs_t *gMobileEngfuncs; diff --git a/dlls/extdll.h b/dlls/extdll.h index cbc7ebb9..dda1cec5 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -57,6 +57,10 @@ typedef int BOOL; #include "stdlib.h" #include "math.h" +#if defined(__LP64__) || defined(__LLP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define XASH_64BIT +#endif + // 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; diff --git a/dlls/nodes.h b/dlls/nodes.h index cbf1e2a6..c959dd2e 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -103,7 +103,7 @@ typedef struct //========================================================= // CGraph //========================================================= -#ifdef __amd64 +#ifdef XASH_64BIT #define GRAPH_VERSION (int)16 * 10 #else #define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. diff --git a/dlls/util.h b/dlls/util.h index 5b00fe94..a61240fd 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -36,7 +36,7 @@ extern globalvars_t *gpGlobals; // Use this instead of ALLOC_STRING on constant strings #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) -#if !defined __amd64__ || defined(CLIENT_DLL) +#if !defined XASH_64BIT || defined(CLIENT_DLL) #define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) #else static inline int MAKE_STRING(const char *szValue) diff --git a/engine/studio.h b/engine/studio.h index b5b709bb..5e5ec26c 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -215,7 +215,7 @@ typedef struct char label[32]; // textual name char name[64]; // file name cache_user_t cache; // cache index pointer -#ifndef __amd64 +#ifndef XASH_64BIT int data; // hack for group 0 #endif } mstudioseqgroup_t; From cbdf9b5d042bf695f85918ca8bee074ecec0d368 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 09:48:08 +0500 Subject: [PATCH 161/227] Fix knowledge bugs with satchels again. --- dlls/client.cpp | 6 ------ dlls/multiplay_gamerules.cpp | 6 ------ dlls/player.cpp | 1 + 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/client.cpp b/dlls/client.cpp index 1fead362..480a9506 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -127,12 +127,6 @@ void ClientDisconnect( edict_t *pEntity ) pEntity->v.solid = SOLID_NOT;// nonsolid UTIL_SetOrigin( &pEntity->v, pEntity->v.origin ); - CBasePlayer *pl = (CBasePlayer *)CBaseEntity::Instance( pEntity ); - if( pl->HasNamedPlayerItem( "weapon_satchel" ) ) - { - DeactivateSatchels( pl ); - } - g_pGameRules->ClientDisconnected( pEntity ); } diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 9da8d0b4..494ac4f6 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -675,12 +675,6 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, // 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 } //========================================================= diff --git a/dlls/player.cpp b/dlls/player.cpp index 9680aaf6..1d198e84 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -826,6 +826,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) for( i = 0; i < MAX_AMMO_SLOTS; i++ ) m_rgAmmo[i] = 0; + DeactivateSatchels( this ); UpdateClientData(); // send Selected Weapon Message to our client From 004054586b0cc48863638a9505c3e139c3423148 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 10:01:32 +0500 Subject: [PATCH 162/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/52209adc339fa21ee1c9564e5d82ad97d9a09374 --- dlls/func_tank.cpp | 4 +++- dlls/player.cpp | 11 ----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index ab295e0c..cace610d 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -351,6 +351,7 @@ BOOL CFuncTank::StartControl( CBasePlayer *pController ) ALERT( at_console, "using TANK!\n"); m_pController = pController; + m_pController->m_pTank = this; if( m_pController->m_pActiveItem ) { m_pController->m_pActiveItem->Holster(); @@ -380,6 +381,8 @@ void CFuncTank::StopControl() m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; pev->nextthink = 0; + + m_pController->m_pTank = NULL; m_pController = NULL; if( IsActive() ) @@ -426,7 +429,6 @@ void CFuncTank::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use } else if( !m_pController && useType != USE_OFF ) { - ( (CBasePlayer*)pActivator )->m_pTank = this; StartControl( (CBasePlayer*)pActivator ); } else diff --git a/dlls/player.cpp b/dlls/player.cpp index 1d198e84..10216734 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -792,10 +792,7 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) m_pLastItem = NULL; if( m_pTank != 0 ) - { m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } int i; CBasePlayerItem *pPendingItem; @@ -856,10 +853,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) 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() ) ); @@ -1402,10 +1396,7 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) 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 ); @@ -1481,7 +1472,6 @@ void CBasePlayer::PlayerUse( void ) // Stop controlling the tank // TODO: Send HUD Update m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; return; } else @@ -2520,7 +2510,6 @@ void CBasePlayer::PostThink() { // they've moved off the platform m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; } } From 2b2fdac7d056587cc8105f47ea67cec457c913fa Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 10:04:33 +0500 Subject: [PATCH 163/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/336bc05c82c171f895656f913e9fbedfd8c8df54 --- dlls/rpg.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 5fb8cc70..c87d345f 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -265,6 +265,11 @@ void CRpgRocket::FollowThink( void ) pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; if( pev->waterlevel == 0 && pev->velocity.Length() < 1500 ) { + if( m_pLauncher ) + { + // my launcher is still around, tell it I'm dead. + m_pLauncher->m_cActiveRockets--; + } Detonate(); } } From 6f8cd70328a9ec1ef1dc74ec07aed72e098f8fc9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 10:11:39 +0500 Subject: [PATCH 164/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/7a627bf8e3e13929afd7b23ae8435ea8784b4654 --- dlls/satchel.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 458ac532..8ddc41a3 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -42,6 +42,9 @@ enum satchel_radio_e class CSatchelCharge : public CGrenade { + Vector m_lastBounceOrigin; // Used to fix a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set + void Spawn( void ); + void Precache( void ); void Spawn( void ); void Precache( void ); void BounceSound( void ); @@ -114,14 +117,19 @@ void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) } if( !( pev->flags & FL_ONGROUND ) && pev->velocity.Length2D() > 10 ) { + // Fix for a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set + if( pev->origin != m_lastBounceOrigin ) BounceSound(); } - StudioFrameAdvance(); + m_lastBounceOrigin = pev->origin; + // There is no model animation so commented this out to prevent net traffic + // StudioFrameAdvance(); } void CSatchelCharge::SatchelThink( void ) { - StudioFrameAdvance(); + // There is no model animation so commented this out to prevent net traffic + // StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; if( !IsInWorld() ) @@ -149,7 +157,7 @@ void CSatchelCharge::SatchelThink( void ) void CSatchelCharge::Precache( void ) { - PRECACHE_MODEL( "models/grenade.mdl" ); + PRECACHE_MODEL( "models/w_satchel.mdl" ); PRECACHE_SOUND( "weapons/g_bounce1.wav" ); PRECACHE_SOUND( "weapons/g_bounce2.wav" ); PRECACHE_SOUND( "weapons/g_bounce3.wav" ); From 73a99df89420b7bf2939bdd0ddf53ad755ce8a3e Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 10:15:17 +0500 Subject: [PATCH 165/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/c66ee97ade72db0f63d1357d7a0760702a1c92e8 --- dlls/cbase.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index cdf9a00f..6009bfd5 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -441,9 +441,16 @@ edict_t *EHANDLE::Get( void ) edict_t *EHANDLE::Set( edict_t *pent ) { - m_pent = pent; - if( pent ) - m_serialnumber = m_pent->serialnumber; + if( pent ) + { + m_pent = pent; + m_serialnumber = m_pent->serialnumber; + } + else + { + m_pent = NULL; + m_serialnumber = 0; + } return pent; } From 38b223651533fd0ab984147f906e2fe174683eb9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 12:01:53 +0500 Subject: [PATCH 166/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/ee1ec9d64f96ecce0ab144cd86b246f5e7b00555 --- dlls/player.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 10216734..e94f5588 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2583,11 +2583,10 @@ void CBasePlayer::PostThink() CheckPowerups( pev ); UpdatePlayerSound(); - +pt_end: // Track button info so we can detect 'pressed' and 'released' buttons next frame m_afButtonLast = pev->button; -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 @@ -4061,6 +4060,52 @@ void CBasePlayer::UpdateClientData( void ) m_rgpPlayerItems[i]->UpdateClientData( this ); } + if( m_pClientActiveItem != pPlayer->m_pActiveItem ) + { + if( pPlayer->m_pActiveItem == NULL ) + { + // If no weapon, we have to send update here + CBasePlayer *plr; + for( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); + if( !plr || !plr->IsObserver() || plr->m_hObserverTarget != pPlayer ) + continue; + + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, plr->pev ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + } + + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + } + else if( this != pPlayer ) + { + // Special case for spectator + CBasePlayerWeapon *gun = (CBasePlayerWeapon *)pPlayer->m_pActiveItem->GetWeaponPtr(); + if( gun ) + { + int state; + if( pPlayer->m_fOnTarget ) + state = WEAPON_IS_ONTARGET; + else + state = 1; + + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); + WRITE_BYTE( state ); + WRITE_BYTE( gun->m_iId ); + WRITE_BYTE( gun->m_iClip ); + MESSAGE_END(); + } + } + } + // Cache and client weapon change m_pClientActiveItem = m_pActiveItem; m_iClientFOV = m_iFOV; From f318cab1c23d0060c36786763bc6d8c955745616 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 12:06:26 +0500 Subject: [PATCH 167/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/d8daa2f16c30f31f2839fae03580dd213e4501c4 --- dlls/shotgun.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 12e73ede..a08770b3 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -144,6 +144,9 @@ void CShotgun::PrimaryAttack() #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 ); From 0570769d35c39a8c4d6a249ac7b46bd5fb0a5b8f Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 12:17:26 +0500 Subject: [PATCH 168/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/fd29683101f725c5aa41d6fb62d5217db45e8582 --- dlls/func_tank.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index cace610d..4ee4e6d6 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -369,6 +369,9 @@ BOOL CFuncTank::StartControl( CBasePlayer *pController ) void CFuncTank::StopControl() { + if( m_pLaser ) + m_pLaser->TurnOff(); + // TODO: bring back the controllers current weapon if( !m_pController ) return; From 075fd2903075aaa28b0d4930d7d1ba0d1b73f492 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 12:56:33 +0500 Subject: [PATCH 169/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/29c4d46ad02492a33ddd9bb4ace0c873855eebe7 --- dlls/items.cpp | 1 + dlls/weapons.cpp | 12 +++--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/dlls/items.cpp b/dlls/items.cpp index d9cc7871..b0b2aa38 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -166,6 +166,7 @@ void CItem::Materialize( void ) } SetTouch( &CItem::ItemTouch ); + SetThink( NULL ); } #define SF_SUIT_SHORTLOGON 0x0001 diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 61b038c0..22b4a456 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -485,7 +485,7 @@ void CBasePlayerItem::Materialize( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch( &CBasePlayerItem::DefaultTouch); + SetTouch( &CBasePlayerItem::DefaultTouch ); SetThink( NULL ); } @@ -578,13 +578,6 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? - - // If the item is falling and its Think remains FallItem after the player picks it up, - // then after the item touches the ground its Touch will be set back to DefaultTouch, - // so the player will pick it up again, this time Kill-ing the item (since we already have it in the inventory), - // which will make the pointer bad and crash the game. - if( m_pfnThink == &CBasePlayerItem::FallThink ) - SetThink( NULL ); } BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) @@ -734,7 +727,7 @@ void CBasePlayerItem::AttachToPlayer( CBasePlayer *pPlayer ) 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; + pev->nextthink = 0;// Remove think - prevents futher attempts to materialize SetTouch( NULL ); SetThink( NULL ); } @@ -1054,6 +1047,7 @@ void CBasePlayerAmmo::Materialize( void ) } SetTouch( &CBasePlayerAmmo::DefaultTouch ); + SetThink( NULL ); } void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) From 5a2dccb978a7484db890c91f1ebd6fcfb9780194 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 12:58:28 +0500 Subject: [PATCH 170/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/09a90f4a0095d6702f43c66ff27e9f4444866f3c --- dlls/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index e94f5588..e9ad5645 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -799,13 +799,13 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) for( i = 0; i < MAX_ITEM_TYPES; i++ ) { m_pActiveItem = m_rgpPlayerItems[i]; + m_rgpPlayerItems[i] = NULL; while( m_pActiveItem ) { pPendingItem = m_pActiveItem->m_pNext; m_pActiveItem->Drop(); m_pActiveItem = pPendingItem; } - m_rgpPlayerItems[i] = NULL; } m_pActiveItem = NULL; From 7e5145aaff6dbb0d734acb66a97c9e7247e21402 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 13:03:38 +0500 Subject: [PATCH 171/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/b15a0f9d564d6f8e793617ebc88b41cd6940d90c --- dlls/crowbar.cpp | 12 ++++++++++++ dlls/glock.cpp | 12 ++++++++++++ dlls/weapons.h | 6 ++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 98808e14..f9a91978 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -80,6 +80,18 @@ int CCrowbar::GetItemInfo( ItemInfo *p ) return 1; } +int CCrowbar::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 CCrowbar::Deploy() { return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); diff --git a/dlls/glock.cpp b/dlls/glock.cpp index 3eb08d6c..1150d8b9 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -86,6 +86,18 @@ int CGlock::GetItemInfo( ItemInfo *p ) return 1; } +int CGlock::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 CGlock::Deploy() { // pev->body = 1; diff --git a/dlls/weapons.h b/dlls/weapons.h index 3d8dd6ad..f48767c8 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -463,7 +463,8 @@ public: void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 2; } - int GetItemInfo(ItemInfo *p); + int GetItemInfo( ItemInfo *p ); + int AddToPlayer( CBasePlayer *pPlayer ); void PrimaryAttack( void ); void SecondaryAttack( void ); @@ -496,7 +497,8 @@ public: int iItemSlot( void ) { return 1; } void EXPORT SwingAgain( void ); void EXPORT Smack( void ); - int GetItemInfo(ItemInfo *p); + int GetItemInfo( ItemInfo *p ); + int AddToPlayer( CBasePlayer *pPlayer ); void PrimaryAttack( void ); int Swing( int fFirst ); From 0af3a37151614429c13035c5dce0de3cf54f63c4 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 17 Jul 2017 13:45:39 +0500 Subject: [PATCH 172/227] Fix build. Remove unneeded changes. --- dlls/func_tank.cpp | 4 ++-- dlls/player.cpp | 4 ++-- dlls/rpg.cpp | 5 ----- dlls/satchel.cpp | 2 -- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 4ee4e6d6..54f4755a 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -369,8 +369,8 @@ BOOL CFuncTank::StartControl( CBasePlayer *pController ) void CFuncTank::StopControl() { - if( m_pLaser ) - m_pLaser->TurnOff(); + //if( m_pLaser ) + //m_pLaser->TurnOff(); // TODO: bring back the controllers current weapon if( !m_pController ) diff --git a/dlls/player.cpp b/dlls/player.cpp index e9ad5645..d8ed7010 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -4060,7 +4060,7 @@ void CBasePlayer::UpdateClientData( void ) m_rgpPlayerItems[i]->UpdateClientData( this ); } - if( m_pClientActiveItem != pPlayer->m_pActiveItem ) + /*if( m_pClientActiveItem != pPlayer->m_pActiveItem ) { if( pPlayer->m_pActiveItem == NULL ) { @@ -4104,7 +4104,7 @@ void CBasePlayer::UpdateClientData( void ) MESSAGE_END(); } } - } + }*/ // Cache and client weapon change m_pClientActiveItem = m_pActiveItem; diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index c87d345f..5fb8cc70 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -265,11 +265,6 @@ void CRpgRocket::FollowThink( void ) pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; if( pev->waterlevel == 0 && pev->velocity.Length() < 1500 ) { - if( m_pLauncher ) - { - // my launcher is still around, tell it I'm dead. - m_pLauncher->m_cActiveRockets--; - } Detonate(); } } diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 8ddc41a3..015b3483 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -43,8 +43,6 @@ enum satchel_radio_e class CSatchelCharge : public CGrenade { Vector m_lastBounceOrigin; // Used to fix a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set - void Spawn( void ); - void Precache( void ); void Spawn( void ); void Precache( void ); void BounceSound( void ); From 8bae5a5450e7f0c1040fb7c2329a92723a9fc584 Mon Sep 17 00:00:00 2001 From: mittorn Date: Tue, 18 Jul 2017 12:59:46 +0000 Subject: [PATCH 173/227] Fix infinite loop on mingw --- cl_dll/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 94489844..ecbae657 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -91,7 +91,7 @@ SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w +DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ $(LOCAL_PATH)/../common \ From 5dab1c1f1db1556a6648f3c66e1066888257ae51 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 18 Jul 2017 22:54:03 +0500 Subject: [PATCH 174/227] Revert "Merge https://github.com/LevShisterov/BugfixedHL/commit/29c4d46ad02492a33ddd9bb4ace0c873855eebe7" This reverts commit 075fd2903075aaa28b0d4930d7d1ba0d1b73f492. --- dlls/items.cpp | 1 - dlls/weapons.cpp | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dlls/items.cpp b/dlls/items.cpp index b0b2aa38..d9cc7871 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -166,7 +166,6 @@ void CItem::Materialize( void ) } SetTouch( &CItem::ItemTouch ); - SetThink( NULL ); } #define SF_SUIT_SHORTLOGON 0x0001 diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 22b4a456..61b038c0 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -485,7 +485,7 @@ void CBasePlayerItem::Materialize( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch( &CBasePlayerItem::DefaultTouch ); + SetTouch( &CBasePlayerItem::DefaultTouch); SetThink( NULL ); } @@ -578,6 +578,13 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? + + // If the item is falling and its Think remains FallItem after the player picks it up, + // then after the item touches the ground its Touch will be set back to DefaultTouch, + // so the player will pick it up again, this time Kill-ing the item (since we already have it in the inventory), + // which will make the pointer bad and crash the game. + if( m_pfnThink == &CBasePlayerItem::FallThink ) + SetThink( NULL ); } BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) @@ -727,7 +734,7 @@ void CBasePlayerItem::AttachToPlayer( CBasePlayer *pPlayer ) pev->modelindex = 0;// server won't send down to clients if modelindex == 0 pev->model = iStringNull; pev->owner = pPlayer->edict(); - pev->nextthink = 0;// Remove think - prevents futher attempts to materialize + pev->nextthink = gpGlobals->time + .1; SetTouch( NULL ); SetThink( NULL ); } @@ -1047,7 +1054,6 @@ void CBasePlayerAmmo::Materialize( void ) } SetTouch( &CBasePlayerAmmo::DefaultTouch ); - SetThink( NULL ); } void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) From 6d2a869ecdd0bc10b17733b78651c5528a099ec7 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 18 Jul 2017 22:56:45 +0500 Subject: [PATCH 175/227] Revert unneeded changes. --- dlls/satchel.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 015b3483..aeb9c5e6 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -117,17 +117,15 @@ void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) { // Fix for a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set if( pev->origin != m_lastBounceOrigin ) - BounceSound(); + BounceSound(); } m_lastBounceOrigin = pev->origin; - // There is no model animation so commented this out to prevent net traffic - // StudioFrameAdvance(); + StudioFrameAdvance(); } void CSatchelCharge::SatchelThink( void ) { - // There is no model animation so commented this out to prevent net traffic - // StudioFrameAdvance(); + StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; if( !IsInWorld() ) From c8ebe744c3311f1306f88fd88a467abd57029de5 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 02:00:03 +0500 Subject: [PATCH 176/227] Fix my mistakes. Apply fixes for rpg and tank laser again. --- dlls/func_tank.cpp | 11 +++++++++-- dlls/player.cpp | 46 ---------------------------------------------- dlls/rpg.cpp | 5 +++++ 3 files changed, 14 insertions(+), 48 deletions(-) diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 54f4755a..c4e3cb42 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -93,6 +93,7 @@ public: BOOL StartControl( CBasePlayer* pController ); void StopControl( void ); void ControllerPostFrame( void ); + virtual void StopFire( void ){} protected: CBasePlayer* m_pController; @@ -369,8 +370,7 @@ BOOL CFuncTank::StartControl( CBasePlayer *pController ) void CFuncTank::StopControl() { - //if( m_pLaser ) - //m_pLaser->TurnOff(); + StopFire(); // TODO: bring back the controllers current weapon if( !m_pController ) @@ -755,6 +755,7 @@ public: virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; + virtual void StopFire( void ); private: CLaser *m_pLaser; @@ -859,6 +860,12 @@ void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entva } } +void CFuncTankLaser::StopFire( void ) +{ + if( m_pLaser ) + m_pLaser->TurnOff(); +} + class CFuncTankRocket : public CFuncTank { public: diff --git a/dlls/player.cpp b/dlls/player.cpp index d8ed7010..04da24c4 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -4060,52 +4060,6 @@ void CBasePlayer::UpdateClientData( void ) m_rgpPlayerItems[i]->UpdateClientData( this ); } - /*if( m_pClientActiveItem != pPlayer->m_pActiveItem ) - { - if( pPlayer->m_pActiveItem == NULL ) - { - // If no weapon, we have to send update here - CBasePlayer *plr; - for( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); - if( !plr || !plr->IsObserver() || plr->m_hObserverTarget != pPlayer ) - continue; - - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, plr->pev ); - WRITE_BYTE( 0 ); - WRITE_BYTE( 0 ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - } - - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); - WRITE_BYTE( 0 ); - WRITE_BYTE( 0 ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - } - else if( this != pPlayer ) - { - // Special case for spectator - CBasePlayerWeapon *gun = (CBasePlayerWeapon *)pPlayer->m_pActiveItem->GetWeaponPtr(); - if( gun ) - { - int state; - if( pPlayer->m_fOnTarget ) - state = WEAPON_IS_ONTARGET; - else - state = 1; - - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE( state ); - WRITE_BYTE( gun->m_iId ); - WRITE_BYTE( gun->m_iClip ); - MESSAGE_END(); - } - } - }*/ - // Cache and client weapon change m_pClientActiveItem = m_pActiveItem; m_iClientFOV = m_iFOV; diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 5fb8cc70..fe1fd8a9 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -265,6 +265,11 @@ void CRpgRocket::FollowThink( void ) pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; if( pev->waterlevel == 0 && pev->velocity.Length() < 1500 ) { + if( CRpg *pLauncher = (CRpg*)( (CBaseEntity*)( m_hLauncher ) ) ) + { + // my launcher is still around, tell it I'm dead. + pLauncher->m_cActiveRockets--; + } Detonate(); } } From c2a1b013c2d7c9a9c3cb4268de52aa67e3cc2368 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 02:47:31 +0500 Subject: [PATCH 177/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/001e6a09fa9e016995d76aa9092a7656efb63b9e --- dlls/weapons.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 61b038c0..8a7898bf 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -295,6 +295,7 @@ void W_Precache( void ) // common world objects UTIL_PrecacheOther( "item_suit" ); + UTIL_PrecacheOther( "item_healthkit" ); UTIL_PrecacheOther( "item_battery" ); UTIL_PrecacheOther( "item_antidote" ); UTIL_PrecacheOther( "item_security" ); @@ -316,6 +317,9 @@ void W_Precache( void ) UTIL_PrecacheOther( "ammo_9mmAR" ); UTIL_PrecacheOther( "ammo_ARgrenades" ); + // 9mm ammo box + UTIL_PrecacheOther( "ammo_9mmbox" ); + #if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) // python UTIL_PrecacheOtherWeapon( "weapon_357" ); From 9dff875d32bd076a34ce379f3e785fa7636bf228 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 02:51:17 +0500 Subject: [PATCH 178/227] Revert "Revert unneeded changes." This reverts commit 6d2a869ecdd0bc10b17733b78651c5528a099ec7. --- dlls/satchel.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index aeb9c5e6..015b3483 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -117,15 +117,17 @@ void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) { // Fix for a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set if( pev->origin != m_lastBounceOrigin ) - BounceSound(); + BounceSound(); } m_lastBounceOrigin = pev->origin; - StudioFrameAdvance(); + // There is no model animation so commented this out to prevent net traffic + // StudioFrameAdvance(); } void CSatchelCharge::SatchelThink( void ) { - StudioFrameAdvance(); + // There is no model animation so commented this out to prevent net traffic + // StudioFrameAdvance(); pev->nextthink = gpGlobals->time + 0.1; if( !IsInWorld() ) From 426a0e7ab31ece52abe20436a64f4a5ce838bfe9 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 02:52:11 +0500 Subject: [PATCH 179/227] Revert "Revert "Merge https://github.com/LevShisterov/BugfixedHL/commit/29c4d46ad02492a33ddd9bb4ace0c873855eebe7"" This reverts commit 5dab1c1f1db1556a6648f3c66e1066888257ae51. --- dlls/items.cpp | 1 + dlls/weapons.cpp | 12 +++--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/dlls/items.cpp b/dlls/items.cpp index d9cc7871..b0b2aa38 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -166,6 +166,7 @@ void CItem::Materialize( void ) } SetTouch( &CItem::ItemTouch ); + SetThink( NULL ); } #define SF_SUIT_SHORTLOGON 0x0001 diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 8a7898bf..05db43da 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -489,7 +489,7 @@ void CBasePlayerItem::Materialize( void ) pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch( &CBasePlayerItem::DefaultTouch); + SetTouch( &CBasePlayerItem::DefaultTouch ); SetThink( NULL ); } @@ -582,13 +582,6 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) } SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? - - // If the item is falling and its Think remains FallItem after the player picks it up, - // then after the item touches the ground its Touch will be set back to DefaultTouch, - // so the player will pick it up again, this time Kill-ing the item (since we already have it in the inventory), - // which will make the pointer bad and crash the game. - if( m_pfnThink == &CBasePlayerItem::FallThink ) - SetThink( NULL ); } BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) @@ -738,7 +731,7 @@ void CBasePlayerItem::AttachToPlayer( CBasePlayer *pPlayer ) 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; + pev->nextthink = 0;// Remove think - prevents futher attempts to materialize SetTouch( NULL ); SetThink( NULL ); } @@ -1058,6 +1051,7 @@ void CBasePlayerAmmo::Materialize( void ) } SetTouch( &CBasePlayerAmmo::DefaultTouch ); + SetThink( NULL ); } void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) From 51c682c15e7d6e2abdf403ef096b9cecbd545211 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 03:22:08 +0500 Subject: [PATCH 180/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/adb616153729102975800edbbdcc8ed8a50ed8ad --- dlls/game.cpp | 4 +++- dlls/game.h | 1 + dlls/gauss.cpp | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/game.cpp b/dlls/game.cpp index 9b69cac9..b109f376 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -25,11 +25,12 @@ 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 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 selfgauss = { "mp_selfgauss", "1", 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 }; @@ -467,6 +468,7 @@ void GameDLLInit( void ) CVAR_REGISTER( &friendlyfire ); CVAR_REGISTER( &falldamage ); CVAR_REGISTER( &weaponstay ); + CVAR_REGISTER( &selfgauss ); CVAR_REGISTER( &forcerespawn ); CVAR_REGISTER( &flashlight ); CVAR_REGISTER( &aimcrosshair ); diff --git a/dlls/game.h b/dlls/game.h index 925010f3..e29b2563 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -27,6 +27,7 @@ extern cvar_t timelimit; extern cvar_t friendlyfire; extern cvar_t falldamage; extern cvar_t weaponstay; +extern cvar_t selfgauss; extern cvar_t forcerespawn; extern cvar_t flashlight; extern cvar_t aimcrosshair; diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index d3e005c2..62af08e1 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -24,6 +24,7 @@ #include "soundent.h" #include "shake.h" #include "gamerules.h" +#include "game.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 @@ -512,6 +513,10 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) vecSrc = beam_tr.vecEndPos + vecDir; } + else if( !selfgauss.value ) + { + flDamage = 0; + } } else { From 946e962f3c8e1429ab39a0e5e851ff5d1e13a211 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 04:06:19 +0500 Subject: [PATCH 181/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/1c71f33cb0978cfdcfc5167d9c8860654778f762 --- cl_dll/flashlight.cpp | 2 ++ dlls/player.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index 8b8a8d0e..c3514c7d 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -49,6 +49,8 @@ void CHudFlashlight::Reset( void ) { m_fFade = 0; m_fOn = 0; + m_iBat = 100; + m_flBat = 1.0; } int CHudFlashlight::VidInit( void ) diff --git a/dlls/player.cpp b/dlls/player.cpp index 04da24c4..0d86caf8 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -3868,6 +3868,12 @@ void CBasePlayer::UpdateClientData( void ) FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); + // Send flashlight status + MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); + WRITE_BYTE( FlashlightIsOn() ? 1 : 0 ); + WRITE_BYTE( m_iFlashBattery ); + MESSAGE_END(); + InitStatusBar(); } From a2e4a7ec03d987c0645742fde30a591452689245 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 04:11:08 +0500 Subject: [PATCH 182/227] Fix crosshair. --- cl_dll/ammo.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index f439520e..edc21652 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -305,6 +305,9 @@ void CHudAmmo::Reset( void ) gHR.Reset(); //VidInit(); + wrect_t nullrc = {}; + SetCrosshair( 0, nullrc, 0, 0, 0 ); // reset crosshair + m_pWeapon = NULL; // reset last weapon } int CHudAmmo::VidInit( void ) @@ -606,22 +609,24 @@ int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) m_pWeapon = pWeapon; - if( gHUD.m_iFOV >= 90 ) + if( !( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) ) { - // normal crosshairs - if( fOnTarget && m_pWeapon->hAutoaim ) - SetCrosshair( m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255 ); + if( gHUD.m_iFOV >= 90 ) + { + // normal crosshairs + if( fOnTarget && m_pWeapon->hAutoaim ) + SetCrosshair( m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255 ); + else + SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); + } else - SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - else - { - // zoomed crosshairs - if( fOnTarget && m_pWeapon->hZoomedAutoaim ) - SetCrosshair( m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255 ); - else - SetCrosshair( m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255 ); - + { + // zoomed crosshairs + if( fOnTarget && m_pWeapon->hZoomedAutoaim ) + SetCrosshair( m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255 ); + else + SetCrosshair( m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255 ); + } } m_fFade = 200.0f; //!!! From d062757f5273e0ecdbf05f6a1ea599690ba8816a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Wed, 19 Jul 2017 23:25:47 +0500 Subject: [PATCH 183/227] Use MAKE_STRING for literals. Remove duplicated code. --- dlls/bmodels.cpp | 40 ++++------ dlls/buttons.cpp | 10 +-- dlls/doors.cpp | 192 +++++++++++++++++++++------------------------- dlls/maprules.cpp | 160 +++++++++++++++++++------------------- dlls/plats.cpp | 119 ++++++++++++++-------------- dlls/triggers.cpp | 2 +- 6 files changed, 244 insertions(+), 279 deletions(-) diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index 6e8526f9..c48abbf9 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -430,15 +430,13 @@ void CFuncRotating::Spawn() void CFuncRotating::Precache( void ) { - char* szSoundFile = (char*)STRING( pev->message ); + const char* szSoundFile = STRING( pev->message ); + BOOL NullSound = FALSE; // 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 { @@ -446,42 +444,32 @@ void CFuncRotating::Precache( void ) switch( m_sounds ) { case 1: - PRECACHE_SOUND( "fans/fan1.wav" ); - pev->noiseRunning = ALLOC_STRING( "fans/fan1.wav" ); + szSoundFile = "fans/fan1.wav"; break; case 2: - PRECACHE_SOUND( "fans/fan2.wav" ); - pev->noiseRunning = ALLOC_STRING( "fans/fan2.wav" ); + szSoundFile = "fans/fan2.wav"; break; case 3: - PRECACHE_SOUND( "fans/fan3.wav" ); - pev->noiseRunning = ALLOC_STRING( "fans/fan3.wav" ); + szSoundFile = "fans/fan3.wav"; break; case 4: - PRECACHE_SOUND( "fans/fan4.wav" ); - pev->noiseRunning = ALLOC_STRING( "fans/fan4.wav" ); + szSoundFile = "fans/fan4.wav"; break; case 5: - PRECACHE_SOUND( "fans/fan5.wav" ); - pev->noiseRunning = ALLOC_STRING( "fans/fan5.wav" ); + szSoundFile = "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; - } + szSoundFile = "common/null.wav"; + NullSound = TRUE; + break; } } + if( !NullSound ) + PRECACHE_SOUND( szSoundFile ); + pev->noiseRunning = MAKE_STRING( szSoundFile ); + if( pev->avelocity != g_vecZero ) { // if fan was spinning, and we went through transition or save/restore, diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index df7c51f3..7ea9082a 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -292,14 +292,14 @@ void CBaseButton::Precache( void ) { pszSound = ButtonSound( (int)m_bLockedSound ); PRECACHE_SOUND( pszSound ); - m_ls.sLockedSound = ALLOC_STRING( pszSound ); + m_ls.sLockedSound = MAKE_STRING( pszSound ); } if( m_bUnlockedSound ) { pszSound = ButtonSound( (int)m_bUnlockedSound ); PRECACHE_SOUND( pszSound ); - m_ls.sUnlockedSound = ALLOC_STRING( pszSound ); + m_ls.sUnlockedSound = MAKE_STRING( pszSound ); } // get sentence group names, for doors which are directly 'touched' to open @@ -469,7 +469,7 @@ void CBaseButton::Spawn() //---------------------------------------------------- pszSound = ButtonSound( m_sounds ); PRECACHE_SOUND( pszSound ); - pev->noise = ALLOC_STRING( pszSound ); + pev->noise = MAKE_STRING( pszSound ); Precache(); @@ -876,7 +876,7 @@ void CRotButton::Spawn( void ) //---------------------------------------------------- pszSound = ButtonSound( m_sounds ); PRECACHE_SOUND( pszSound ); - pev->noise = ALLOC_STRING( pszSound ); + pev->noise = MAKE_STRING( pszSound ); // set the axis of rotation CBaseToggle::AxisDir( pev ); @@ -1012,7 +1012,7 @@ void CMomentaryRotButton::Spawn( void ) const char *pszSound = ButtonSound( m_sounds ); PRECACHE_SOUND( pszSound ); - pev->noise = ALLOC_STRING( pszSound ); + pev->noise = MAKE_STRING( pszSound ); m_lastUsed = 0; } diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 3a8613ab..ce901ee8 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -330,114 +330,104 @@ void CBaseDoor::SetToggleState( int state ) void CBaseDoor::Precache( void ) { const char *pszSound; + BOOL NullSound = FALSE; // 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" ); + pszSound = "doors/doormove1.wav"; break; case 2: - PRECACHE_SOUND( "doors/doormove2.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove2.wav" ); + pszSound = "doors/doormove2.wav"; break; case 3: - PRECACHE_SOUND( "doors/doormove3.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove3.wav" ); + pszSound = "doors/doormove3.wav"; break; case 4: - PRECACHE_SOUND( "doors/doormove4.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove4.wav" ); + pszSound = "doors/doormove4.wav"; break; case 5: - PRECACHE_SOUND( "doors/doormove5.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove5.wav" ); + pszSound = "doors/doormove5.wav"; break; case 6: - PRECACHE_SOUND( "doors/doormove6.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove6.wav" ); + pszSound = "doors/doormove6.wav"; break; case 7: - PRECACHE_SOUND( "doors/doormove7.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove7.wav" ); + pszSound = "doors/doormove7.wav"; break; case 8: - PRECACHE_SOUND( "doors/doormove8.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove8.wav" ); + pszSound = "doors/doormove8.wav"; break; case 9: - PRECACHE_SOUND( "doors/doormove9.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove9.wav" ); + pszSound = "doors/doormove9.wav"; break; case 10: - PRECACHE_SOUND( "doors/doormove10.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove10.wav" ); + pszSound = "doors/doormove10.wav"; break; + case 0: default: - pev->noiseMoving = ALLOC_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseMoving = MAKE_STRING( pszSound ); + NullSound = FALSE; + // 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" ); + pszSound = "doors/doorstop1.wav"; break; case 2: - PRECACHE_SOUND( "doors/doorstop2.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop2.wav" ); + pszSound = "doors/doorstop2.wav"; break; case 3: - PRECACHE_SOUND( "doors/doorstop3.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop3.wav" ); + pszSound = "doors/doorstop3.wav"; break; case 4: - PRECACHE_SOUND( "doors/doorstop4.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop4.wav" ); + pszSound = "doors/doorstop4.wav"; break; case 5: - PRECACHE_SOUND( "doors/doorstop5.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop5.wav" ); + pszSound = "doors/doorstop5.wav"; break; case 6: - PRECACHE_SOUND( "doors/doorstop6.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop6.wav"); + pszSound = "doors/doorstop6.wav" break; case 7: - PRECACHE_SOUND( "doors/doorstop7.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop7.wav" ); + pszSound = "doors/doorstop7.wav"; break; case 8: - PRECACHE_SOUND( "doors/doorstop8.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop8.wav" ); + pszSound = "doors/doorstop8.wav"; break; + case 0: default: - pev->noiseArrived = ALLOC_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseArrived = MAKE_STRING( pszSound ); + // 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 ); + m_ls.sLockedSound = MAKE_STRING( pszSound ); } if( m_bUnlockedSound ) { pszSound = ButtonSound( (int)m_bUnlockedSound ); PRECACHE_SOUND( pszSound ); - m_ls.sUnlockedSound = ALLOC_STRING( pszSound ); + m_ls.sUnlockedSound = MAKE_STRING( pszSound ); } // get sentence group names, for doors which are directly 'touched' to open @@ -445,39 +435,39 @@ void CBaseDoor::Precache( void ) { case 1: // access denied - m_ls.sLockedSentence = ALLOC_STRING( "NA" ); + m_ls.sLockedSentence = MAKE_STRING( "NA" ); break; case 2: // security lockout - m_ls.sLockedSentence = ALLOC_STRING( "ND" ); + m_ls.sLockedSentence = MAKE_STRING( "ND" ); break; case 3: // blast door - m_ls.sLockedSentence = ALLOC_STRING( "NF" ); + m_ls.sLockedSentence = MAKE_STRING( "NF" ); break; case 4: // fire door - m_ls.sLockedSentence = ALLOC_STRING( "NFIRE" ); + m_ls.sLockedSentence = MAKE_STRING( "NFIRE" ); break; case 5: // chemical door - m_ls.sLockedSentence = ALLOC_STRING( "NCHEM" ); + m_ls.sLockedSentence = MAKE_STRING( "NCHEM" ); break; case 6: // radiation door - m_ls.sLockedSentence = ALLOC_STRING( "NRAD" ); + m_ls.sLockedSentence = MAKE_STRING( "NRAD" ); break; case 7: // gen containment - m_ls.sLockedSentence = ALLOC_STRING( "NCON" ); + m_ls.sLockedSentence = MAKE_STRING( "NCON" ); break; case 8: // maintenance door - m_ls.sLockedSentence = ALLOC_STRING( "NH" ); + m_ls.sLockedSentence = MAKE_STRING( "NH" ); break; case 9: // broken door - m_ls.sLockedSentence = ALLOC_STRING( "NG" ); + m_ls.sLockedSentence = MAKE_STRING( "NG" ); break; default: m_ls.sLockedSentence = 0; @@ -488,35 +478,35 @@ void CBaseDoor::Precache( void ) { case 1: // access granted - m_ls.sUnlockedSentence = ALLOC_STRING( "EA" ); + m_ls.sUnlockedSentence = MAKE_STRING( "EA" ); break; case 2: // security door - m_ls.sUnlockedSentence = ALLOC_STRING( "ED" ); + m_ls.sUnlockedSentence = MAKE_STRING( "ED" ); break; case 3: // blast door - m_ls.sUnlockedSentence = ALLOC_STRING( "EF" ); + m_ls.sUnlockedSentence = MAKE_STRING( "EF" ); break; case 4: // fire door - m_ls.sUnlockedSentence = ALLOC_STRING( "EFIRE" ); + m_ls.sUnlockedSentence = MAKE_STRING( "EFIRE" ); break; case 5: // chemical door - m_ls.sUnlockedSentence = ALLOC_STRING( "ECHEM" ); + m_ls.sUnlockedSentence = MAKE_STRING( "ECHEM" ); break; case 6: // radiation door - m_ls.sUnlockedSentence = ALLOC_STRING( "ERAD" ); + m_ls.sUnlockedSentence = MAKE_STRING( "ERAD" ); break; case 7: // gen containment - m_ls.sUnlockedSentence = ALLOC_STRING( "ECON" ); + m_ls.sUnlockedSentence = MAKE_STRING( "ECON" ); break; case 8: // maintenance door - m_ls.sUnlockedSentence = ALLOC_STRING( "EH" ); + m_ls.sUnlockedSentence = MAKE_STRING( "EH" ); break; default: m_ls.sUnlockedSentence = 0; @@ -985,94 +975,88 @@ void CMomentaryDoor::Spawn( void ) Precache(); } - + void CMomentaryDoor::Precache( void ) { + const char *pszSound; + BOOL NullSound = FALSE; + // 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" ); + pszSound = "doors/doormove1.wav"; break; case 2: - PRECACHE_SOUND( "doors/doormove2.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove2.wav" ); + pszSound = "doors/doormove2.wav"; break; case 3: - PRECACHE_SOUND( "doors/doormove3.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove3.wav" ); + pszSound = "doors/doormove3.wav"; break; case 4: - PRECACHE_SOUND( "doors/doormove4.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove4.wav" ); + pszSound = "doors/doormove4.wav"; break; case 5: - PRECACHE_SOUND( "doors/doormove5.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove5.wav" ); + pszSound = "doors/doormove5.wav"; break; case 6: - PRECACHE_SOUND( "doors/doormove6.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove6.wav" ); + pszSound = "doors/doormove6.wav"; break; case 7: - PRECACHE_SOUND( "doors/doormove7.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove7.wav" ); + pszSound = "doors/doormove7.wav"; break; case 8: - PRECACHE_SOUND( "doors/doormove8.wav" ); - pev->noiseMoving = ALLOC_STRING( "doors/doormove8.wav" ); + pszSound = "doors/doormove8.wav"; break; + case 0: default: - pev->noiseMoving = ALLOC_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseMoving = MAKE_STRING( pszSound ); + NullSound = FALSE; + // 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" ); + pszSound = "doors/doorstop1.wav"; break; case 2: - PRECACHE_SOUND( "doors/doorstop2.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop2.wav" ); + pszSound = "doors/doorstop2.wav"; break; case 3: - PRECACHE_SOUND( "doors/doorstop3.wav" ); - pev->noiseArrived = ALLOC_STRING("doors/doorstop3.wav"); + pszSound = "doors/doorstop3.wav"; break; case 4: - PRECACHE_SOUND( "doors/doorstop4.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop4.wav" ); + pszSound = "doors/doorstop4.wav"; break; case 5: - PRECACHE_SOUND( "doors/doorstop5.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop5.wav" ); + pszSound = "doors/doorstop5.wav"; break; case 6: - PRECACHE_SOUND( "doors/doorstop6.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop6.wav" ); + pszSound = "doors/doorstop6.wav"; break; case 7: - PRECACHE_SOUND( "doors/doorstop7.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop7.wav" ); + pszSound = "doors/doorstop7.wav"; break; case 8: - PRECACHE_SOUND( "doors/doorstop8.wav" ); - pev->noiseArrived = ALLOC_STRING( "doors/doorstop8.wav" ); + pszSound = "doors/doorstop8.wav"; break; + case 0: default: - pev->noiseArrived = ALLOC_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseArrived = MAKE_STRING( pszSound ); } void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index 2230acac..bfec93e2 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -153,9 +153,9 @@ void CGameScore::Spawn( void ) void CGameScore::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "points")) + if( FStrEq( pkvd->szKeyName, "points" ) ) { - SetPoints( atoi(pkvd->szValue) ); + SetPoints( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else @@ -164,13 +164,13 @@ void CGameScore::KeyValue( KeyValueData *pkvd ) void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; // Only players can use this - if ( pActivator->IsPlayer() ) + if( pActivator->IsPlayer() ) { - if ( AwardToTeam() ) + if( AwardToTeam() ) { pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); } @@ -194,7 +194,7 @@ LINK_ENTITY_TO_CLASS( game_end, CGameEnd ) void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; g_pGameRules->EndMultiplayerGame(); @@ -239,27 +239,27 @@ IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ) void CGameText::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "channel")) + if( FStrEq( pkvd->szKeyName, "channel" ) ) { m_textParms.channel = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "x")) + else if( FStrEq( pkvd->szKeyName, "x" ) ) { m_textParms.x = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "y")) + else if( FStrEq(pkvd->szKeyName, "y" ) ) { m_textParms.y = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "effect")) + else if( FStrEq( pkvd->szKeyName, "effect" ) ) { m_textParms.effect = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "color")) + else if( FStrEq( pkvd->szKeyName, "color" ) ) { int color[4]; UTIL_StringToIntArray( color, 4, pkvd->szValue ); @@ -269,7 +269,7 @@ void CGameText::KeyValue( KeyValueData *pkvd ) m_textParms.a1 = color[3]; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "color2")) + else if( FStrEq( pkvd->szKeyName, "color2" ) ) { int color[4]; UTIL_StringToIntArray( color, 4, pkvd->szValue ); @@ -279,22 +279,22 @@ void CGameText::KeyValue( KeyValueData *pkvd ) m_textParms.a2 = color[3]; pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "fadein")) + else if( FStrEq( pkvd->szKeyName, "fadein" ) ) { m_textParms.fadeinTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "fadeout")) + else if( FStrEq( pkvd->szKeyName, "fadeout" ) ) { m_textParms.fadeoutTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "holdtime")) + else if( FStrEq( pkvd->szKeyName, "holdtime" ) ) { m_textParms.holdTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "fxtime")) + else if( FStrEq(pkvd->szKeyName, "fxtime" ) ) { m_textParms.fxTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -305,16 +305,16 @@ void CGameText::KeyValue( KeyValueData *pkvd ) void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; - if ( MessageToAll() ) + if( MessageToAll() ) { UTIL_HudMessageAll( m_textParms, MessageGet() ); } else { - if ( pActivator->IsNetClient() ) + if( pActivator->IsNetClient() ) { UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); } @@ -356,12 +356,12 @@ LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ) void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "teamindex")) + if( FStrEq( pkvd->szKeyName, "teamindex" ) ) { m_teamIndex = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) + else if( FStrEq( pkvd->szKeyName, "triggerstate" ) ) { int type = atoi( pkvd->szValue ); switch( type ) @@ -384,12 +384,12 @@ void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; - if ( useType == USE_SET ) + if( useType == USE_SET ) { - if ( value < 0 ) + if( value < 0 ) { m_teamIndex = -1; } @@ -400,10 +400,10 @@ void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY return; } - if ( TeamMatch( pActivator ) ) + if( TeamMatch( pActivator ) ) { SUB_UseTargets( pActivator, triggerType, value ); - if ( RemoveOnFire() ) + if( RemoveOnFire() ) UTIL_Remove( this ); } } @@ -415,7 +415,7 @@ BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) const char *CGameTeamMaster::TeamID( void ) { - if ( m_teamIndex < 0 ) // Currently set to "no team" + 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" @@ -423,10 +423,10 @@ const char *CGameTeamMaster::TeamID( void ) BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) { - if ( m_teamIndex < 0 && AnyTeam() ) + if( m_teamIndex < 0 && AnyTeam() ) return TRUE; - if ( !pActivator ) + if( !pActivator ) return FALSE; return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); @@ -443,7 +443,7 @@ BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) class CGameTeamSet : public CRulePointEntity { public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + 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; } @@ -454,10 +454,10 @@ LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ) void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; - if ( ShouldClearTeam() ) + if( ShouldClearTeam() ) { SUB_UseTargets( pActivator, USE_SET, -1 ); } @@ -466,7 +466,7 @@ void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE SUB_UseTargets( pActivator, USE_SET, 0 ); } - if ( RemoveOnFire() ) + if( RemoveOnFire() ) { UTIL_Remove( this ); } @@ -506,22 +506,22 @@ IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ) void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "intarget")) + if( FStrEq(pkvd->szKeyName, "intarget" ) ) { m_iszInTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "outtarget")) + else if( FStrEq( pkvd->szKeyName, "outtarget" ) ) { m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "incount")) + else if( FStrEq( pkvd->szKeyName, "incount" ) ) { m_iszInCount = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "outcount")) + else if( FStrEq( pkvd->szKeyName, "outcount" ) ) { m_iszOutCount = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -535,12 +535,12 @@ void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY int playersInCount = 0; int playersOutCount = 0; - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; CBaseEntity *pPlayer = NULL; - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for( int i = 1; i <= gpGlobals->maxClients; i++ ) { pPlayer = UTIL_PlayerByIndex( i ); if ( pPlayer ) @@ -549,40 +549,40 @@ void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY int hullNumber; hullNumber = human_hull; - if ( pPlayer->pev->flags & FL_DUCKING ) + if( pPlayer->pev->flags & FL_DUCKING ) { hullNumber = head_hull; } UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - if ( trace.fStartSolid ) + if( trace.fStartSolid ) { playersInCount++; - if ( m_iszInTarget ) + if( m_iszInTarget ) { - FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value ); + FireTargets( STRING( m_iszInTarget ), pPlayer, pActivator, useType, value ); } } else { playersOutCount++; - if ( m_iszOutTarget ) + if( m_iszOutTarget ) { - FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value ); + FireTargets( STRING( m_iszOutTarget ), pPlayer, pActivator, useType, value ); } } } } - if ( m_iszInCount ) + if( m_iszInCount ) { - FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount ); + FireTargets( STRING( m_iszInCount ), pActivator, this, USE_SET, playersInCount ); } - if ( m_iszOutCount ) + if( m_iszOutCount ) { - FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount ); + FireTargets( STRING( m_iszOutCount ), pActivator, this, USE_SET, playersOutCount ); } } @@ -605,12 +605,12 @@ LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ) void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; - if ( pActivator->IsPlayer() ) + if( pActivator->IsPlayer() ) { - if ( pev->dmg < 0 ) + if( pev->dmg < 0 ) pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); else pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); @@ -618,7 +618,7 @@ void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY SUB_UseTargets( pActivator, useType, value ); - if ( RemoveOnFire() ) + if( RemoveOnFire() ) { UTIL_Remove( this ); } @@ -665,7 +665,7 @@ void CGameCounter::Spawn( void ) void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; switch( useType ) @@ -681,16 +681,16 @@ void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE SetCountValue( (int)value ); break; } - - if ( HitLimit() ) + + if( HitLimit() ) { SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - if ( RemoveOnFire() ) + if( RemoveOnFire() ) { UTIL_Remove( this ); } - - if ( ResetOnFire() ) + + if( ResetOnFire() ) { ResetCount(); } @@ -716,12 +716,12 @@ LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ) void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; SUB_UseTargets( pActivator, USE_SET, pev->frags ); - if ( RemoveOnFire() ) + if( RemoveOnFire() ) { UTIL_Remove( this ); } @@ -756,19 +756,19 @@ void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) { CRulePointEntity::KeyValue( pkvd ); - if ( !pkvd->fHandled ) + if( !pkvd->fHandled ) { - for ( int i = 0; i < MAX_EQUIP; i++ ) + for( int i = 0; i < MAX_EQUIP; i++ ) { - if ( !m_weaponNames[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]); + m_weaponNames[i] = ALLOC_STRING( tmp ); + m_weaponCount[i] = atoi( pkvd->szValue ); + m_weaponCount[i] = max( 1, m_weaponCount[i] ); pkvd->fHandled = TRUE; break; } @@ -778,10 +778,10 @@ void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) void CGamePlayerEquip::Touch( CBaseEntity *pOther ) { - if ( !CanFireForActivator( pOther ) ) + if( !CanFireForActivator( pOther ) ) return; - if ( UseOnly() ) + if( UseOnly() ) return; EquipPlayer( pOther ); @@ -791,21 +791,21 @@ void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) { CBasePlayer *pPlayer = NULL; - if ( pEntity->IsPlayer() ) + if( pEntity->IsPlayer() ) { pPlayer = (CBasePlayer *)pEntity; } - if ( !pPlayer ) + if( !pPlayer ) return; - for ( int i = 0; i < MAX_EQUIP; i++ ) + for( int i = 0; i < MAX_EQUIP; i++ ) { - if ( !m_weaponNames[i] ) + if( !m_weaponNames[i] ) break; - for ( int j = 0; j < m_weaponCount[i]; j++ ) + for( int j = 0; j < m_weaponCount[i]; j++ ) { - pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); + pPlayer->GiveNamedItem( STRING( m_weaponNames[i] ) ); } } } @@ -844,9 +844,9 @@ const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) { CBaseEntity *pTeamEntity = NULL; - while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) + while( ( pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName ) ) != NULL ) { - if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) + if( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) return pTeamEntity->TeamID(); } @@ -855,10 +855,10 @@ const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - if ( !CanFireForActivator( pActivator ) ) + if( !CanFireForActivator( pActivator ) ) return; - if ( pActivator->IsPlayer() ) + if( pActivator->IsPlayer() ) { const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); if ( pszTargetTeam ) @@ -868,7 +868,7 @@ void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY } } - if ( RemoveOnFire() ) + if( RemoveOnFire() ) { UTIL_Remove( this ); } diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 00b05bec..3034fd93 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -104,111 +104,100 @@ void CBasePlatTrain::KeyValue( KeyValueData *pkvd ) void CBasePlatTrain::Precache( void ) { + const char *pszSound; + BOOL NullSound = FALSE; + // 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" ); + pszSound = "plats/bigmove1.wav"; break; case 2: - PRECACHE_SOUND( "plats/bigmove2.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/bigmove2.wav" ); + pszSound = "plats/bigmove2.wav"; break; case 3: - PRECACHE_SOUND( "plats/elevmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/elevmove1.wav" ); + pszSound = "plats/elevmove1.wav"; break; case 4: - PRECACHE_SOUND( "plats/elevmove2.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/elevmove2.wav" ); + pszSound = "plats/elevmove2.wav"; break; case 5: - PRECACHE_SOUND( "plats/elevmove3.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/elevmove3.wav" ); + pszSound = "plats/elevmove3.wav"; break; case 6: - PRECACHE_SOUND( "plats/freightmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/freightmove1.wav" ); + pszSound = "plats/freightmove1.wav"; break; case 7: - PRECACHE_SOUND( "plats/freightmove2.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/freightmove2.wav" ); + pszSound = "plats/freightmove2.wav"; break; case 8: - PRECACHE_SOUND( "plats/heavymove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/heavymove1.wav" ); + pszSound = "plats/heavymove1.wav"; break; case 9: - PRECACHE_SOUND( "plats/rackmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/rackmove1.wav" ); + pszSound = "plats/rackmove1.wav"; break; case 10: - PRECACHE_SOUND( "plats/railmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/railmove1.wav" ); + pszSound = "plats/railmove1.wav"; break; case 11: - PRECACHE_SOUND( "plats/squeekmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/squeekmove1.wav" ); + pszSound = "plats/squeekmove1.wav"; break; case 12: - PRECACHE_SOUND( "plats/talkmove1.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/talkmove1.wav" ); + pszSound = "plats/talkmove1.wav"; break; case 13: - PRECACHE_SOUND( "plats/talkmove2.wav" ); - pev->noiseMoving = MAKE_STRING( "plats/talkmove2.wav" ); + pszSound = "plats/talkmove2.wav"; break; + case 0: default: - pev->noiseMoving = MAKE_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseMoving = MAKE_STRING( pszSound ); + NullSound = FALSE; + // 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" ); + pszSound = "plats/bigstop1.wav"; break; case 2: - PRECACHE_SOUND( "plats/bigstop2.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/bigstop2.wav" ); + pszSound = "plats/bigstop2.wav"; break; case 3: - PRECACHE_SOUND( "plats/freightstop1.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/freightstop1.wav" ); + pszSound = "plats/freightstop1.wav"; break; case 4: - PRECACHE_SOUND( "plats/heavystop2.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/heavystop2.wav" ); + pszSound = "plats/heavystop2.wav"; break; case 5: - PRECACHE_SOUND( "plats/rackstop1.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/rackstop1.wav" ); + pszSound = "plats/rackstop1.wav"; break; case 6: - PRECACHE_SOUND( "plats/railstop1.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/railstop1.wav" ); + pszSound = "plats/railstop1.wav"; break; case 7: - PRECACHE_SOUND( "plats/squeekstop1.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/squeekstop1.wav" ); + pszSound = "plats/squeekstop1.wav"; break; case 8: - PRECACHE_SOUND( "plats/talkstop1.wav" ); - pev->noiseArrived = MAKE_STRING( "plats/talkstop1.wav" ); + pszSound = "plats/talkstop1.wav"; break; + case 0: default: - pev->noiseArrived = MAKE_STRING( "common/null.wav" ); + pszSound = "common/null.wav"; + NullSound = TRUE; break; } + + if( !NullSound ) + PRECACHE_SOUND( pszSound ); + pev->noiseArrived = MAKE_STRING( pszSound ); } // @@ -1482,6 +1471,8 @@ void CFuncTrackTrain::Spawn( void ) void CFuncTrackTrain::Precache( void ) { + const char *pszSound; + if( m_flVolume == 0.0 ) m_flVolume = 1.0; @@ -1489,34 +1480,36 @@ void CFuncTrackTrain::Precache( void ) { default: // no sound - pev->noise = 0; + pszSound = NULL; break; case 1: - PRECACHE_SOUND( "plats/ttrain1.wav" ); - pev->noise = MAKE_STRING("plats/ttrain1.wav" ); + pszSound = "plats/ttrain1.wav"; break; case 2: - PRECACHE_SOUND( "plats/ttrain2.wav" ); - pev->noise = MAKE_STRING( "plats/ttrain2.wav" ); + pszSound = "plats/ttrain2.wav"; break; case 3: - PRECACHE_SOUND( "plats/ttrain3.wav" ); - pev->noise = MAKE_STRING( "plats/ttrain3.wav" ); + pszSound = "plats/ttrain3.wav"; break; case 4: - PRECACHE_SOUND( "plats/ttrain4.wav" ); - pev->noise = MAKE_STRING( "plats/ttrain4.wav" ); + pszSound = "plats/ttrain4.wav"; break; case 5: - PRECACHE_SOUND( "plats/ttrain6.wav" ); - pev->noise = MAKE_STRING( "plats/ttrain6.wav" ); + pszSound = "plats/ttrain6.wav"; break; case 6: - PRECACHE_SOUND( "plats/ttrain7.wav" ); - pev->noise = MAKE_STRING( "plats/ttrain7.wav" ); + pszSound = "plats/ttrain7.wav"; break; } + if( !pszSound ) + { + PRECACHE_SOUND( pszSound ); + pev->noise = MAKE_STRING( pszSound ); + } + else + pev->noise = 0; + PRECACHE_SOUND( "plats/ttrain_brake1.wav" ); PRECACHE_SOUND( "plats/ttrain_start1.wav" ); diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 2959d96d..57d8d031 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1689,7 +1689,7 @@ void NextLevel( void ) // go back to start if no trigger_changelevel if( FNullEnt( pent ) ) { - gpGlobals->mapname = ALLOC_STRING( "start" ); + gpGlobals->mapname = MAKE_STRING( "start" ); pChange = GetClassPtr( (CChangeLevel *)NULL ); strcpy( pChange->m_szMapName, "start" ); } From 14e75025bb64f730fa42081fa594c397ca064b2d Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 10:33:39 +0500 Subject: [PATCH 184/227] Show long nicknames in scoreboard. Show fulli nicknames in scoreboard. --- cl_dll/scoreboard.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp index b20e316c..3adbaab6 100644 --- a/cl_dll/scoreboard.cpp +++ b/cl_dll/scoreboard.cpp @@ -92,7 +92,7 @@ We have a minimum width of 1-320 - we could have the field widths scale with it? // X positions // relative to the side of the scoreboard -#define NAME_RANGE_MIN 20 +#define NAME_RANGE_MIN -100 #define NAME_RANGE_MAX 145 #define KILLS_RANGE_MIN 130 #define KILLS_RANGE_MAX 170 @@ -145,7 +145,7 @@ int CHudScoreboard::Draw( float fTime ) int xpos = NAME_RANGE_MIN + xpos_rel; FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; - FAR_RIGHT += 5; + FAR_RIGHT += 125; if( cl_scoreboard_bg && cl_scoreboard_bg->value ) gHUD.DrawDarkRectangle( xpos - 5, ypos - 5, FAR_RIGHT, ROW_RANGE_MAX ); if( !gHUD.m_Teamplay ) @@ -340,7 +340,7 @@ int CHudScoreboard::DrawPlayers( int xpos_rel, float list_slot, int nameoffset, } FAR_RIGHT = can_show_packetloss ? PL_RANGE_MAX : PING_RANGE_MAX; - FAR_RIGHT += 5; + FAR_RIGHT += 125; // draw the players, in order, and restricted to team if set while( 1 ) From 7a5c29cbc9f68bf1fbfe1a454ae351721155b640 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 10:51:34 +0500 Subject: [PATCH 185/227] Clear any effects on disconnect. --- dlls/client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/client.cpp b/dlls/client.cpp index 480a9506..3e23821f 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -125,6 +125,7 @@ void ClientDisconnect( edict_t *pEntity ) // 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 + pEntity->v.effects = 0;// clear any effects UTIL_SetOrigin( &pEntity->v, pEntity->v.origin ); g_pGameRules->ClientDisconnected( pEntity ); From ea8f2bed7715b48bdf012b1c6bcbcf8881e5400a Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 12:13:04 +0500 Subject: [PATCH 186/227] Implement cl_viewbob cvar for viewmodel bobbing. Same as in http://am.half-lifecreations.com/forums/index.php?topic=288.0 --- cl_dll/hud.cpp | 2 ++ cl_dll/view.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 0f3b45bc..05bda284 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -35,6 +35,7 @@ extern client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, extern cvar_t *sensitivity; cvar_t *cl_lw = NULL; +cvar_t *cl_viewbob = NULL; void ShutdownInput( void ); @@ -194,6 +195,7 @@ void CHud::Init( void ) m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); + cl_viewbob = CVAR_CREATE( "cl_viewbob", "0", FCVAR_ARCHIVE ); m_pSpriteList = NULL; diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index dcd2b1af..efa4b104 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -78,6 +78,7 @@ extern cvar_t *cl_forwardspeed; extern cvar_t *chase_active; extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; extern cvar_t *cl_vsmoothing; +extern cvar_t *cl_viewbob; extern Vector dead_viewangles; #define CAM_MODE_RELAX 1 @@ -527,7 +528,7 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) V_AddIdle( pparams ); // offsets - if ( pparams->health <= 0 ) + if( pparams->health <= 0 ) { VectorCopy( dead_viewangles, angles ); } @@ -598,6 +599,9 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) view->angles[ROLL] -= bob * 1; view->angles[PITCH] -= bob * 0.3; + if( cl_viewbob && cl_viewbob->value ) + VectorCopy( view->angles, view->curstate.angles ); + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem // with view model distortion, this may be a cause. (SJB). From c9ac2c6dabf511a5b68526876d47a8579c2bf02c Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 12:22:02 +0500 Subject: [PATCH 187/227] Implement mp_satchelfix cvar. --- dlls/doors.cpp | 10 +++++++--- dlls/game.cpp | 2 ++ dlls/game.h | 1 + dlls/player.cpp | 4 +++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/dlls/doors.cpp b/dlls/doors.cpp index ce901ee8..61a04ed2 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -22,6 +22,7 @@ #include "util.h" #include "cbase.h" #include "doors.h" +#include "game.h" #include "weapons.h" extern void SetMovedir( entvars_t *ev ); @@ -737,9 +738,12 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) if( pev->dmg ) pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - // Detonate satchels - if( !strcmp( "monster_satchel", STRING( pOther->pev->classname ) ) ) - ( (CSatchel*)pOther )->Use( this, this, USE_ON, 0 ); + if( satchelfix.value ) + { + // Detonate satchels + if( !strcmp( "monster_satchel", STRING( pOther->pev->classname ) ) ) + ( (CSatchel*)pOther )->Use( this, this, USE_ON, 0 ); + } // 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 diff --git a/dlls/game.cpp b/dlls/game.cpp index b109f376..4354a63d 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -31,6 +31,7 @@ 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 selfgauss = { "mp_selfgauss", "1", FCVAR_SERVER }; +cvar_t satchelfix = { "mp_satchelfix", "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 }; @@ -469,6 +470,7 @@ void GameDLLInit( void ) CVAR_REGISTER( &falldamage ); CVAR_REGISTER( &weaponstay ); CVAR_REGISTER( &selfgauss ); + CVAR_REGISTER( &satchelfix ); CVAR_REGISTER( &forcerespawn ); CVAR_REGISTER( &flashlight ); CVAR_REGISTER( &aimcrosshair ); diff --git a/dlls/game.h b/dlls/game.h index e29b2563..a6d0cd1c 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -28,6 +28,7 @@ extern cvar_t friendlyfire; extern cvar_t falldamage; extern cvar_t weaponstay; extern cvar_t selfgauss; +extern cvar_t satchelfix; extern cvar_t forcerespawn; extern cvar_t flashlight; extern cvar_t aimcrosshair; diff --git a/dlls/player.cpp b/dlls/player.cpp index 0d86caf8..1a7bc206 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -823,7 +823,9 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) for( i = 0; i < MAX_AMMO_SLOTS; i++ ) m_rgAmmo[i] = 0; - DeactivateSatchels( this ); + if( satchelfix.value ) + DeactivateSatchels( this ); + UpdateClientData(); // send Selected Weapon Message to our client From d1fbb99574d66c35de21a3b3b45a7c137b33f6e0 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 23:32:06 +0500 Subject: [PATCH 188/227] Fix some warnings yet. --- cl_dll/cl_util.h | 2 +- cl_dll/hud_spectator.cpp | 10 +++---- cl_dll/hud_spectator.h | 4 +-- dlls/client.cpp | 4 +-- dlls/doors.cpp | 2 +- dlls/multiplay_gamerules.cpp | 2 +- dlls/nihilanth.cpp | 20 +++++++------- engine/cdll_int.h | 52 ++++++++++++++++++------------------ 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 22555caa..1996543d 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -144,7 +144,7 @@ inline void CenterPrint( const char *string ) #define GetPlayerInfo ( *gEngfuncs.pfnGetPlayerInfo ) // sound functions -inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } +inline void PlaySound( const char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } #define max(a, b) (((a) > (b)) ? (a) : (b)) diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index ff6eb8ff..5ffce74a 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -175,13 +175,13 @@ void UTIL_StringToVector( float * pVector, const char *pString ) } } -int UTIL_FindEntityInMap( char * name, float * origin, float * angle ) +int UTIL_FindEntityInMap( const char *name, float *origin, float *angle ) { int n, found = 0; char keyname[256]; char token[2048]; - cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + cl_entity_t *pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model if( !pEnt ) return 0; @@ -189,7 +189,7 @@ int UTIL_FindEntityInMap( char * name, float * origin, float * angle ) if( !pEnt->model ) return 0; - char * data = pEnt->model->entities; + char *data = pEnt->model->entities; while( data ) { @@ -1374,12 +1374,12 @@ void CHudSpectator::DeathMessage( int victim ) AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); } -bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) +bool CHudSpectator::AddOverviewEntityToList( HSPRITE sprite, cl_entity_t *ent, double killTime ) { for( int i = 0; i < MAX_OVERVIEW_ENTITIES; i++ ) { // find empty entity slot - if( m_OverviewEntities[i].entity == NULL) + if( m_OverviewEntities[i].entity == NULL ) { m_OverviewEntities[i].entity = ent; m_OverviewEntities[i].hSprite = sprite; diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index f60353db..58026668 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -64,11 +64,11 @@ public: void CheckOverviewEntities(); void DrawOverview(); void DrawOverviewEntities(); - void GetMapPosition( float * returnvec ); + void GetMapPosition( float *returnvec ); void DrawOverviewLayer(); void LoadMapSprites(); bool ParseOverviewFile(); - bool IsActivePlayer( cl_entity_t * ent ); + bool IsActivePlayer( cl_entity_t *ent ); void SetModes( int iMainMode, int iInsetMode ); void HandleButtonsDown( int ButtonPressed ); void HandleButtonsUp( int ButtonPressed ); diff --git a/dlls/client.cpp b/dlls/client.cpp index 3e23821f..569b1a53 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -566,7 +566,7 @@ void ClientCommand( edict_t *pEntity ) // 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" ) ); + ( pev->netname && ( STRING( pev->netname ) )[0] != 0 ) ? STRING( pev->netname ) : "unconnected" ) ); } else ClientPrint( pev, HUD_PRINTCONSOLE, "Spectator mode is disabled.\n" ); @@ -629,7 +629,7 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) 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" ) ) ) + 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" ); diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 61a04ed2..90678df6 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -397,7 +397,7 @@ void CBaseDoor::Precache( void ) pszSound = "doors/doorstop5.wav"; break; case 6: - pszSound = "doors/doorstop6.wav" + pszSound = "doors/doorstop6.wav"; break; case 7: pszSound = "doors/doorstop7.wav"; diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 494ac4f6..a898158f 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -423,7 +423,7 @@ 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" ) ); + ( pl->pev->netname && ( STRING( pl->pev->netname ) )[0] != 0 ) ? STRING( pl->pev->netname ) : "unconnected" ) ); // team match? if( g_teamplay ) diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 1f9b0f88..34375a58 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -642,14 +642,14 @@ void CNihilanth::MakeFriend( Vector vecStart ) for( i = 0; i < 3; i++ ) { - if( m_hFriend[i] != NULL && !m_hFriend[i]->IsAlive() ) + 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] == NULL ) + if( m_hFriend[i] == 0 ) { if( RANDOM_LONG( 0, 1 ) == 0 ) { @@ -675,7 +675,7 @@ void CNihilanth::MakeFriend( Vector vecStart ) m_hFriend[i] = Create( "monster_alien_slave", node.m_vecOrigin, pev->angles ); } } - if( m_hFriend[i] != NULL ) + if( m_hFriend[i] != 0 ) { EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); } @@ -722,7 +722,7 @@ void CNihilanth::NextActivity() } } - if( ( pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2 ) && m_hRecharger == NULL && m_iLevel <= 9 ) + if( ( pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2 ) && m_hRecharger == 0 && m_iLevel <= 9 ) { char szName[64]; @@ -881,7 +881,7 @@ void CNihilanth::HuntThink( void ) } // look for current enemy - if( m_hEnemy != 0 && m_hRecharger == NULL ) + if( m_hEnemy != 0 && m_hRecharger == 0 ) { if( FVisible( m_hEnemy ) ) { @@ -1057,7 +1057,7 @@ void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) break; case 2: // zen - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { if( RANDOM_LONG( 0, 4 ) == 0 ) EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); @@ -1098,7 +1098,7 @@ void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) break; case 3: // prayer - if (m_hEnemy != NULL) + if( m_hEnemy != 0 ) { char szText[32]; @@ -1178,7 +1178,7 @@ void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) } break; case 6: - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { Vector vecSrc, vecAngles; GetAttachment( 2, vecSrc, vecAngles ); @@ -1208,7 +1208,7 @@ void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); if( pTouch ) { - if( m_hEnemy != NULL ) + if( m_hEnemy != 0 ) { pTouch->Touch( m_hEnemy ); } @@ -1597,7 +1597,7 @@ void CNihilanthHVR::TeleportThink( void ) if( m_hTargetEnt != 0 ) m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - if( m_hTouch != 0 && m_hEnemy != NULL ) + if( m_hTouch != 0 && m_hEnemy != 0 ) m_hTouch->Touch( m_hEnemy ); } else diff --git a/engine/cdll_int.h b/engine/cdll_int.h index 056146b4..d45bb9d5 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -128,7 +128,7 @@ typedef struct cl_enginefuncs_s void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc ); void (*pfnSPR_EnableScissor)( int x, int y, int width, int height ); void (*pfnSPR_DisableScissor)( void ); - client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount ); + client_sprite_t *(*pfnSPR_GetList)( const char *psz, int *piCount ); // screen handlers void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a ); @@ -136,20 +136,20 @@ typedef struct cl_enginefuncs_s void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b ); // cvar handlers - struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags ); - float (*pfnGetCvarFloat)( char *szName ); - char* (*pfnGetCvarString)( char *szName ); + struct cvar_s *(*pfnRegisterVariable)( const char *szName, const char *szValue, int flags ); + float (*pfnGetCvarFloat)( const char *szName ); + char* (*pfnGetCvarString)( const char *szName ); // command handlers - int (*pfnAddCommand)( char *cmd_name, void (*function)(void) ); - int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn ); - int (*pfnServerCmd)( char *szCmdString ); - int (*pfnClientCmd)( char *szCmdString ); + int (*pfnAddCommand)( const char *cmd_name, void (*function)(void) ); + int (*pfnHookUserMsg)( const char *szMsgName, pfnUserMsgHook pfn ); + int (*pfnServerCmd)( const char *szCmdString ); + int (*pfnClientCmd)( const char *szCmdString ); void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo ); // sound handlers - void (*pfnPlaySoundByName)( char *szSound, float volume ); + void (*pfnPlaySoundByName)( const char *szSound, float volume ); void (*pfnPlaySoundByIndex)( int iSound, float volume ); // vector helpers @@ -158,7 +158,7 @@ typedef struct cl_enginefuncs_s // text message system client_textmessage_t *(*pfnTextMessageGet)( const char *pName ); int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b ); - int (*pfnDrawConsoleString)( int x, int y, char *string ); + int (*pfnDrawConsoleString)( int x, int y, const char *string ); void (*pfnDrawSetTextColor)( float r, float g, float b ); void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height ); @@ -171,19 +171,19 @@ typedef struct cl_enginefuncs_s void (*GetViewAngles)( float * ); void (*SetViewAngles)( float * ); int (*GetMaxClients)( void ); - void (*Cvar_SetValue)( char *cvar, float value ); + void (*Cvar_SetValue)( const char *cvar, float value ); int (*Cmd_Argc)( void ); char *(*Cmd_Argv)( int arg ); - void (*Con_Printf)( char *fmt, ... ); - void (*Con_DPrintf)( char *fmt, ... ); - void (*Con_NPrintf)( int pos, char *fmt, ... ); - void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... ); + void (*Con_Printf)( const char *fmt, ... ); + void (*Con_DPrintf)( const char *fmt, ... ); + void (*Con_NPrintf)( int pos, const char *fmt, ... ); + void (*Con_NXPrintf)( struct con_nprint_s *info, const char *fmt, ... ); const char* (*PhysInfo_ValueForKey)( const char *key ); const char* (*ServerInfo_ValueForKey)( const char *key ); float (*GetClientMaxspeed)( void ); - int (*CheckParm)( char *parm, char **ppnext ); + int (*CheckParm)( const char *parm, const char **ppnext ); void (*Key_Event)( int key, int down ); void (*GetMousePosition)( int *mx, int *my ); @@ -212,7 +212,7 @@ typedef struct cl_enginefuncs_s void (*pfnWeaponAnim)( int iAnim, int body ); float (*pfnRandomFloat)( float flLow, float flHigh ); int (*pfnRandomLong)( int lLow, int lHigh ); - void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args )); + void (*pfnHookEvent)( const char *name, void ( *pfnEvent )( struct event_args_s *args )); int (*Con_IsVisible) (); const char *(*pfnGetGameDirectory)( void ); struct cvar_s *(*pfnGetCvarPointer)( const char *szName ); @@ -223,8 +223,8 @@ typedef struct cl_enginefuncs_s void* (*VGui_GetPanel)( ); void (*VGui_ViewportPaintBackground)( int extents[4] ); - byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength ); - char* (*COM_ParseFile)( char *data, char *token ); + byte* (*COM_LoadFile)( const char *path, int usehunk, int *pLength ); + char* (*COM_ParseFile)( const char *data, const char *token ); void (*COM_FreeFile)( void *buffer ); struct triangleapi_s *pTriAPI; @@ -252,7 +252,7 @@ typedef struct cl_enginefuncs_s // Gets a unique ID for the specified player. This is the same even if you see the player on a different server. // iPlayer is an entity index, so client 0 would use iPlayer=1. // Returns false if there is no player on the server in the specified slot. - qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]); + qboolean (*GetPlayerUniqueID)(int iPlayer, const char playerID[16]); // TrackerID access int (*GetTrackerIDForPlayer)(int playerSlot); @@ -260,7 +260,7 @@ typedef struct cl_enginefuncs_s // Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream // (but it might not get there). - int ( *pfnServerCmdUnreliable )( char *szCmdString ); + int ( *pfnServerCmdUnreliable )( const char *szCmdString ); void (*pfnGetMousePos)( struct tagPOINT *ppt ); void (*pfnSetMousePos)( int x, int y ); @@ -285,12 +285,12 @@ typedef struct cl_enginefuncs_s const char *(*LocalPlayerInfo_ValueForKey)( const char* key ); int (*pfnVGUI2DrawCharacter)( int x, int y, int ch, unsigned int font ); int (*pfnVGUI2DrawCharacterAdditive)( int x, int y, int ch, int r, int g, int b, unsigned int font ); - unsigned int (*pfnGetApproxWavePlayLen)( char *filename ); + unsigned int (*pfnGetApproxWavePlayLen)( const char *filename ); void* (*GetCareerGameUI)( void ); // g-cont. !!!! potential crash-point! - void (*Cvar_Set)( char *name, char *value ); + void (*Cvar_Set)( const char *name, const char *value ); int (*pfnIsPlayingCareerMatch)( void ); - void (*pfnPlaySoundVoiceByName)( char *szSound, float volume, int pitch ); - void (*pfnPrimeMusicStream)( char *filename, int looping ); + void (*pfnPlaySoundVoiceByName)( const char *szSound, float volume, int pitch ); + void (*pfnPrimeMusicStream)( const char *filename, int looping ); double (*pfnSys_FloatTime)( void ); // decay funcs @@ -298,7 +298,7 @@ typedef struct cl_enginefuncs_s void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen ); void (*pfnResetTutorMessageDecayData)( void ); - void (*pfnPlaySoundByNameAtPitch)( char *szSound, float volume, int pitch ); + void (*pfnPlaySoundByNameAtPitch)( const char *szSound, float volume, int pitch ); void (*pfnFillRGBABlend)( int x, int y, int width, int height, int r, int g, int b, int a ); int (*pfnGetAppID)( void ); cmdalias_t *(*pfnGetAliases)( void ); From 58a5ca48be81a8d12995d4bd71f4ad9fee274ba7 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Thu, 20 Jul 2017 23:42:00 +0500 Subject: [PATCH 189/227] Add protection for vec3_t definition. --- common/mathlib.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/mathlib.h b/common/mathlib.h index fadb97fb..12fb972f 100644 --- a/common/mathlib.h +++ b/common/mathlib.h @@ -18,7 +18,12 @@ typedef float vec_t; typedef vec_t vec2_t[2]; + +#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 #ifndef M_PI From 3dc0939b40960f1a3e0c7ff9d68849e2dff0ccd7 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Fri, 21 Jul 2017 00:00:38 +0500 Subject: [PATCH 190/227] Prevent buffer overflow. --- cl_dll/text_message.cpp | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index 9452cebb..b959fc87 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -162,42 +162,39 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf int msg_dest = READ_BYTE(); - static char szBuf[6][128]; - const char *msg_text = LookupString( READ_STRING(), &msg_dest ); - msg_text = strcpy( szBuf[0], msg_text ); +#define MSG_BUF_SIZE 128 + char szBuf[6][MSG_BUF_SIZE]; + + strncpy( szBuf[0], LookupString( READ_STRING(), &msg_dest ), MSG_BUF_SIZE - 1 ); + szBuf[0][MSG_BUF_SIZE - 1] = '\0'; + + for( int i = 1; i <= 4; i++ ) + { + // keep reading strings and using C format strings for subsituting the strings into the localised text string + strncpy( szBuf[i], LookupString( READ_STRING() ), MSG_BUF_SIZE - 1 ); + szBuf[i][MSG_BUF_SIZE - 1] = '\0'; + StripEndNewlineFromString( szBuf[i] ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines + } - // keep reading strings and using C format strings for subsituting the strings into the localised text string - const char *sstr1 = LookupString( READ_STRING() ); - sstr1 = strcpy( szBuf[1], sstr1 ); - StripEndNewlineFromString( (char*)sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines - const char *sstr2 = LookupString( READ_STRING() ); - sstr2 = strcpy( szBuf[2], sstr2 ); - StripEndNewlineFromString( (char*)sstr2 ); - const char *sstr3 = LookupString( READ_STRING() ); - sstr3 = strcpy( szBuf[3], sstr3 ); - StripEndNewlineFromString( (char*)sstr3 ); - const char *sstr4 = LookupString( READ_STRING() ); - sstr4 = strcpy( szBuf[4], sstr4 ); - StripEndNewlineFromString( (char*)sstr4 ); char *psz = szBuf[5]; switch( msg_dest ) { case HUD_PRINTCENTER: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + snprintf( psz, MSG_BUF_SIZE, szBuf[0], szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); CenterPrint( ConvertCRtoNL( psz ) ); break; case HUD_PRINTNOTIFY: psz[0] = 1; // mark this message to go into the notify buffer - sprintf( psz + 1, msg_text, sstr1, sstr2, sstr3, sstr4 ); + snprintf( psz + 1, MSG_BUF_SIZE - 1, szBuf[0], szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); ConsolePrint( ConvertCRtoNL( psz ) ); break; case HUD_PRINTTALK: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); - gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); + snprintf( psz, MSG_BUF_SIZE, szBuf[0], szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); + gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), MSG_BUF_SIZE ); break; case HUD_PRINTCONSOLE: - sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); + snprintf( psz, MSG_BUF_SIZE, szBuf[0], szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); ConsolePrint( ConvertCRtoNL( psz ) ); break; } From cf9ba716862eb50da691a4daff272a61f0a0b674 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Fri, 21 Jul 2017 00:52:09 +0500 Subject: [PATCH 191/227] Make UpdateOnRemove() virtual. --- cl_dll/hl/hl_baseentity.cpp | 1 + dlls/cbase.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index d24c0ef4..acd537e0 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -55,6 +55,7 @@ BOOL CBaseEntity::IsInWorld( void ) { return TRUE; } int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } int CBaseEntity::DamageDecal( int bitsDamageType ) { return -1; } CBaseEntity *CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::UpdateOnRemove( void ) { } void CBaseEntity::SUB_Remove( void ) { } // CBaseDelay Stubs diff --git a/dlls/cbase.h b/dlls/cbase.h index 6c738bf5..b78de883 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -12,6 +12,8 @@ * without written permission from Valve LLC. * ****/ +#ifndef CBASE_H +#define CBASE_H /* Class Hierachy @@ -229,7 +231,7 @@ public: }; #endif - void UpdateOnRemove( void ); + virtual void UpdateOnRemove( void ); // common member functions void EXPORT SUB_Remove( void ); @@ -780,3 +782,4 @@ public: void Precache( void ); void KeyValue( KeyValueData *pkvd ); }; +#endif From 70c6e429076e746b1be4492b0c6f468ef7ea2174 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 23 Jul 2017 21:41:05 +0500 Subject: [PATCH 192/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/68c9b7cf6bdcacdf267c2e2dab2415dbbebdfcd2 --- cl_dll/hl/hl_baseentity.cpp | 2 +- dlls/handgrenade.cpp | 3 +- dlls/player.cpp | 20 +++++---- dlls/player.h | 2 +- dlls/satchel.cpp | 83 +++++++++++++++++-------------------- dlls/squeakgrenade.cpp | 3 +- dlls/tripmine.cpp | 3 +- dlls/weapons.cpp | 18 ++++++-- 8 files changed, 68 insertions(+), 66 deletions(-) diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index acd537e0..38978f6a 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -277,7 +277,7 @@ void CBasePlayer::ForceClientDllUpdate( void ) { } void CBasePlayer::ImpulseCommands() { } void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHoster ) { return FALSE; } void CBasePlayer::ItemPreFrame() { } void CBasePlayer::ItemPostFrame() { } int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 2a31fc84..c2bbd7f9 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -99,8 +99,7 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { // no more grenades! m_pPlayer->pev->weapons &= ~( 1 << WEAPON_HANDGRENADE ); - SetThink( &CBasePlayerItem::DestroyItem ); - pev->nextthink = gpGlobals->time + 0.1; + DestroyItem(); } if( m_flStartThrow ) diff --git a/dlls/player.cpp b/dlls/player.cpp index 1a7bc206..38038b36 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -666,8 +666,8 @@ void CBasePlayer::PackDeadPlayerItems( void ) int iWeaponRules; int iAmmoRules; int i; - CBasePlayerWeapon *rgpPackWeapons[20] = {0};// 20 hardcoded for now. How to determine exactly how many weapons we have? - int iPackAmmo[MAX_AMMO_SLOTS + 1]; + CBasePlayerWeapon *rgpPackWeapons[MAX_WEAPONS] = {}; + int iPackAmmo[MAX_AMMO_SLOTS]; int iPW = 0;// index into packweapons array int iPA = 0;// index into packammo array @@ -675,7 +675,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) // get the game rules iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); - iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); + iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); if( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) { @@ -685,14 +685,14 @@ void CBasePlayer::PackDeadPlayerItems( void ) } // go through all of the weapons and make a list of the ones to pack - for( i = 0; i < MAX_ITEM_TYPES; i++ ) + for( i = 0; i < MAX_ITEM_TYPES && iPW < MAX_WEAPONS; i++ ) { if( m_rgpPlayerItems[i] ) { // there's a weapon here. Should I pack it? CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[i]; - while( pPlayerItem ) + while( pPlayerItem && iPW < MAX_WEAPONS ) { switch( iWeaponRules ) { @@ -3640,14 +3640,16 @@ int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) return FALSE; } -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHolster ) { + pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. + pItem->SetThink( NULL ); + if( m_pActiveItem == pItem ) { ResetAutoaim(); - pItem->Holster(); - pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. - pItem->SetThink( NULL ); + if( bCallHolster ) + pItem->Holster(); m_pActiveItem = NULL; pev->viewmodel = 0; pev->weaponmodel = 0; diff --git a/dlls/player.h b/dlls/player.h index 8ff312ea..1c17556c 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -259,7 +259,7 @@ public: void AddPoints( int score, BOOL bAllowNegativeScore ); void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); BOOL AddPlayerItem( CBasePlayerItem *pItem ); - BOOL RemovePlayerItem( CBasePlayerItem *pItem ); + BOOL RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHoster ); void DropPlayerItem ( char *pszItemName ); BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); BOOL HasNamedPlayerItem( const char *pszItemName ); diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 015b3483..dc8724bd 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -23,6 +23,13 @@ #include "player.h" #include "gamerules.h" +enum satchel_state +{ + SATCHEL_IDLE = 0, + SATCHEL_READY, + SATCHEL_RELOAD +}; + enum satchel_e { SATCHEL_IDLE1 = 0, @@ -194,7 +201,7 @@ int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) { pSatchel = (CSatchel *)pOriginal; - if( pSatchel->m_chargeReady != 0 ) + if( pSatchel->m_chargeReady != SATCHEL_IDLE ) { // player has some satchels deployed. Refuse to add more. return FALSE; @@ -211,7 +218,7 @@ int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); pPlayer->pev->weapons |= ( 1 << m_iId ); - m_chargeReady = 0;// this satchel charge weapon now forgets that any satchels are deployed by it. + m_chargeReady = SATCHEL_IDLE;// this satchel charge weapon now forgets that any satchels are deployed by it. if( bResult ) { @@ -263,19 +270,7 @@ int CSatchel::GetItemInfo( ItemInfo *p ) //========================================================= 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; + return CanDeploy(); } BOOL CSatchel::CanDeploy( void ) @@ -286,7 +281,7 @@ BOOL CSatchel::CanDeploy( void ) return TRUE; } - if( m_chargeReady != 0 ) + if( m_chargeReady ) { // player isn't carrying any satchels, but has some out return TRUE; @@ -322,11 +317,10 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) } EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); - if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) + if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && m_chargeReady != SATCHEL_READY ) { m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SATCHEL ); - SetThink( &CBasePlayerItem::DestroyItem ); - pev->nextthink = gpGlobals->time + 0.1; + DestroyItem(); } } @@ -334,38 +328,37 @@ void CSatchel::PrimaryAttack() { switch( m_chargeReady ) { - case 0: + case SATCHEL_IDLE: { - Throw(); + Throw(); } break; - case 1: + case SATCHEL_READY: { - SendWeaponAnim( SATCHEL_RADIO_FIRE ); + SendWeaponAnim( SATCHEL_RADIO_FIRE ); - edict_t *pPlayer = m_pPlayer->edict(); + edict_t *pPlayer = m_pPlayer->edict(); - CBaseEntity *pSatchel = NULL; + CBaseEntity *pSatchel = NULL; - while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 ) ) != NULL ) - { - if( FClassnameIs( pSatchel->pev, "monster_satchel" ) ) + while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 ) ) != NULL ) { - if( pSatchel->pev->owner == pPlayer ) + if( FClassnameIs( pSatchel->pev, "monster_satchel" ) ) { - pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); - m_chargeReady = 2; + if( pSatchel->pev->owner == pPlayer ) + { + pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); + } } } - } - m_chargeReady = 2; - m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - break; + m_chargeReady = SATCHEL_RELOAD; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; + break; } - case 2: + case SATCHEL_RELOAD: // we're reloading, don't allow fire break; } @@ -373,7 +366,7 @@ void CSatchel::PrimaryAttack() void CSatchel::SecondaryAttack( void ) { - if( m_chargeReady != 2 ) + if( m_chargeReady != SATCHEL_RELOAD ) { Throw(); } @@ -403,8 +396,8 @@ void CSatchel::Throw( void ) // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - m_chargeReady = 1; - + m_chargeReady = SATCHEL_READY; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); @@ -419,17 +412,17 @@ void CSatchel::WeaponIdle( void ) switch( m_chargeReady ) { - case 0: + case SATCHEL_IDLE: SendWeaponAnim( SATCHEL_FIDGET1 ); // use tripmine animations strcpy( m_pPlayer->m_szAnimExtention, "trip" ); break; - case 1: + case SATCHEL_READY: SendWeaponAnim( SATCHEL_RADIO_FIDGET1 ); // use hivehand animations strcpy( m_pPlayer->m_szAnimExtention, "hive" ); break; - case 2: + case SATCHEL_RELOAD: if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { m_chargeReady = 0; @@ -450,7 +443,7 @@ void CSatchel::WeaponIdle( void ) m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_chargeReady = 0; + m_chargeReady = SATCHEL_IDLE; break; } m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 830cfab8..bfe17ed1 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -475,8 +475,7 @@ void CSqueak::Holster( int skiplocal /* = 0 */ ) if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SNARK ); - SetThink( &CBasePlayerItem::DestroyItem ); - pev->nextthink = gpGlobals->time + 0.1; + DestroyItem(); return; } diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 60190604..94907bcd 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -418,8 +418,7 @@ void CTripmine::Holster( int skiplocal /* = 0 */ ) { // out of mines m_pPlayer->pev->weapons &= ~( 1 << WEAPON_TRIPMINE ); - SetThink( &CBasePlayerItem::DestroyItem ); - pev->nextthink = gpGlobals->time + 0.1; + DestroyItem(); } SendWeaponAnim( TRIPMINE_HOLSTER ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 05db43da..06bb1796 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -688,8 +688,8 @@ void CBasePlayerItem::DestroyItem( void ) { if( m_pPlayer ) { - // if attached to a player, remove. - m_pPlayer->RemovePlayerItem( this ); + // if attached to a player, remove. + m_pPlayer->RemovePlayerItem( this, false ); } Kill(); @@ -1140,7 +1140,17 @@ void CBasePlayerWeapon::RetireWeapon( void ) m_pPlayer->pev->weaponmodel = iStringNull; //m_pPlayer->pev->viewmodelindex = NULL; - g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); + if( !g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) + { + // Another weapon wasn't selected. Get rid of current one + if( m_pPlayer->m_pActiveItem == this ) + { + m_pPlayer->ResetAutoaim(); + m_pPlayer->m_pActiveItem->Holster(); + m_pPlayer->m_pLastItem = NULL; + m_pPlayer->m_pActiveItem = NULL; + } + } } //========================================================================= @@ -1340,7 +1350,7 @@ BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) if( pWeapon->m_pPlayer ) { - if( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) + if( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon, true ) ) { // failed to unhook the weapon from the player! return FALSE; From 49e740c6f132969f7881c21ad3bdecb6aad84568 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 24 Jul 2017 02:24:55 +0500 Subject: [PATCH 193/227] Remove unneeded casts. --- dlls/agrunt.cpp | 14 ++++++------- dlls/animation.cpp | 2 +- dlls/bmodels.cpp | 16 +++++++-------- dlls/buttons.cpp | 26 +++++++++++------------ dlls/cbase.cpp | 2 +- dlls/doors.cpp | 28 ++++++++++++------------- dlls/effects.cpp | 25 +++++++++++----------- dlls/func_break.cpp | 8 ++++---- dlls/func_tank.cpp | 10 ++++----- dlls/gargantua.cpp | 22 ++++++++++---------- dlls/genericmonster.cpp | 2 +- dlls/h_cycler.cpp | 10 ++++----- dlls/islave.cpp | 8 ++++---- dlls/leech.cpp | 4 ++-- dlls/multiplay_gamerules.cpp | 28 ++++++++++++------------- dlls/nodes.cpp | 8 ++++---- dlls/nodes.h | 6 +++--- dlls/plats.cpp | 40 ++++++++++++++++++------------------ dlls/prop.cpp | 6 +++--- dlls/scripted.cpp | 4 ++-- dlls/sound.cpp | 8 ++++---- dlls/stats.cpp | 4 ++-- dlls/triggers.cpp | 8 ++++---- dlls/util.cpp | 10 ++++----- dlls/util.h | 2 +- dlls/weapons.cpp | 8 ++++---- dlls/world.cpp | 4 ++-- dlls/xen.cpp | 6 +++--- dlls/zombie.cpp | 14 ++++++------- 29 files changed, 166 insertions(+), 167 deletions(-) diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index c6583fb7..cb47ac65 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -613,25 +613,25 @@ void CAGrunt::Precache() PRECACHE_MODEL( "models/agrunt.mdl" ); for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); + PRECACHE_SOUND( pAttackHitSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); + PRECACHE_SOUND( pAttackMissSounds[i] ); for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( (char *)pIdleSounds[i] ); + PRECACHE_SOUND( pIdleSounds[i] ); for( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) - PRECACHE_SOUND( (char *)pDieSounds[i] ); + PRECACHE_SOUND( pDieSounds[i] ); for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( (char *)pPainSounds[i] ); + PRECACHE_SOUND( pPainSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackSounds[i] ); + PRECACHE_SOUND( pAttackSounds[i] ); for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( (char *)pAlertSounds[i] ); + PRECACHE_SOUND( pAlertSounds[i] ); PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 5454f0e8..f84ec380 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -208,7 +208,7 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) 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 ) ) ); + PRECACHE_SOUND( gpGlobals->pStringBase + ALLOC_STRING( pevent[i].options ) ); } } } diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index c48abbf9..fe56b6ac 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -402,7 +402,7 @@ void CFuncRotating::Spawn() } UTIL_SetOrigin( pev, pev->origin ); - SET_MODEL( ENT(pev), STRING(pev->model) ); + SET_MODEL( ENT( pev ), STRING( pev->model ) ); SetUse( &CFuncRotating::RotatingUse ); // did level designer forget to assign speed? @@ -538,7 +538,7 @@ void CFuncRotating::RampPitchVol( int fUp ) pitch = PITCH_NORM - 1; // change the fan's vol and pitch - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING( pev->noiseRunning ), + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noiseRunning ), fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); } @@ -560,7 +560,7 @@ void CFuncRotating::SpinUp( void ) fabs( vecAVel.z ) >= fabs( 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 ), + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noiseRunning ), m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX ); SetThink( &CFuncRotating::Rotate ); @@ -601,7 +601,7 @@ void CFuncRotating::SpinDown( void ) 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 */ ), + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noiseRunning /* Stop */ ), 0, 0, SND_STOP, (int)m_pitch ); SetThink( &CFuncRotating::Rotate ); @@ -630,7 +630,7 @@ void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, if( pev->avelocity != g_vecZero ) { SetThink( &CFuncRotating::SpinDown ); - //EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, (char *)STRING( pev->noiseStop ), + //EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, STRING( pev->noiseStop ), // m_flVolume, m_flAttenuation, 0, m_pitch ); pev->nextthink = pev->ltime + 0.1; @@ -638,7 +638,7 @@ void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, else// fan is not moving, so start it { SetThink( &CFuncRotating::SpinUp ); - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING( pev->noiseRunning ), + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noiseRunning ), 0.01, m_flAttenuation, 0, FANPITCHMIN ); pev->nextthink = pev->ltime + 0.1; @@ -651,7 +651,7 @@ void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, // play stopping sound here SetThink( &CFuncRotating::SpinDown ); - // EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, (char *)STRING( pev->noiseStop ), + // EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, STRING( pev->noiseStop ), // m_flVolume, m_flAttenuation, 0, m_pitch ); pev->nextthink = pev->ltime + 0.1; @@ -659,7 +659,7 @@ void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, } else { - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, (char *)STRING( pev->noiseRunning ), + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noiseRunning ), m_flVolume, m_flAttenuation, 0, FANPITCHMAX ); pev->avelocity = pev->movedir * pev->speed; diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 7ea9082a..90bc42e5 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -343,25 +343,25 @@ void CBaseButton::Precache( void ) m_ls.sUnlockedSentence = MAKE_STRING( "EA" ); break; case 2: // security door - m_ls.sUnlockedSentence = MAKE_STRING("ED"); + m_ls.sUnlockedSentence = MAKE_STRING( "ED" ); break; case 3: // blast door - m_ls.sUnlockedSentence = MAKE_STRING("EF"); + m_ls.sUnlockedSentence = MAKE_STRING( "EF" ); break; case 4: // fire door - m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); + m_ls.sUnlockedSentence = MAKE_STRING( "EFIRE" ); break; case 5: // chemical door - m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); + m_ls.sUnlockedSentence = MAKE_STRING( "ECHEM" ); break; case 6: // radiation door - m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); + m_ls.sUnlockedSentence = MAKE_STRING( "ERAD" ); break; case 7: // gen containment - m_ls.sUnlockedSentence = MAKE_STRING("ECON"); + m_ls.sUnlockedSentence = MAKE_STRING( "ECON" ); break; case 8: // maintenance door - m_ls.sUnlockedSentence = MAKE_STRING("EH"); + m_ls.sUnlockedSentence = MAKE_STRING( "EH" ); break; default: m_ls.sUnlockedSentence = 0; @@ -426,7 +426,7 @@ int CBaseButton::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, fl if( code == BUTTON_RETURN ) { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); // Toggle buttons fire when they get back to their "home" position if( !( pev->spawnflags & SF_BUTTON_TOGGLE ) ) @@ -657,7 +657,7 @@ void CBaseButton::ButtonUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ { if( !m_fStayPushed && FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); //SUB_UseTargets( m_eoActivator ); ButtonReturn(); @@ -716,7 +716,7 @@ void CBaseButton::ButtonTouch( CBaseEntity *pOther ) if( code == BUTTON_RETURN ) { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); ButtonReturn(); } @@ -729,7 +729,7 @@ void CBaseButton::ButtonTouch( CBaseEntity *pOther ) // void CBaseButton::ButtonActivate() { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); if( !UTIL_IsMasterTriggered( m_sMaster, m_hActivator ) ) { @@ -815,7 +815,7 @@ void CBaseButton::ButtonBackHome( void ) if( FBitSet( pev->spawnflags, SF_BUTTON_TOGGLE ) ) { - //EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + //EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); } @@ -1034,7 +1034,7 @@ void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) void CMomentaryRotButton::PlaySound( void ) { - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); } // BUGBUG: This design causes a latentcy. When the button is retriggered, the first impulse diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 6009bfd5..8750bddf 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -605,7 +605,7 @@ int CBaseEntity::Restore( CRestore &restore ) mins = pev->mins; // Set model is about to destroy these maxs = pev->maxs; - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); UTIL_SetSize( pev, mins, maxs ); // Reset them } diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 90678df6..c12cc3a0 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -127,7 +127,7 @@ void PlayLockSounds( entvars_t *pev, locksound_t *pls, int flocked, int fbutton if( fplaysound ) { // play 'door locked' sound - EMIT_SOUND( ENT( pev ), CHAN_ITEM, (char*)STRING( pls->sLockedSound ), fvol, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, STRING( pls->sLockedSound ), fvol, ATTN_NORM ); pls->flwaitSound = gpGlobals->time + flsoundwait; } @@ -164,7 +164,7 @@ void PlayLockSounds( entvars_t *pev, locksound_t *pls, int flocked, int fbutton // play 'door unlocked' sound if set if( fplaysound ) { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, (char*)STRING( pls->sUnlockedSound ), fvol, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_ITEM, STRING( pls->sUnlockedSound ), fvol, ATTN_NORM ); pls->flwaitSound = gpGlobals->time + flsoundwait; } @@ -606,7 +606,7 @@ void CBaseDoor::DoorGoUp( void ) // 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 ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM ); m_toggle_state = TS_GOING_UP; @@ -646,8 +646,8 @@ 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 ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM ); } ASSERT( m_toggle_state == TS_GOING_UP ); @@ -686,7 +686,7 @@ 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 ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM ); #ifdef DOOR_ASSERT ASSERT( m_toggle_state == TS_AT_TOP ); #endif // DOOR_ASSERT @@ -706,8 +706,8 @@ 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 ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM ); } ASSERT( m_toggle_state == TS_GOING_DOWN ); @@ -751,7 +751,7 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) { // BMod Start - Door sound fix. if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) ); // BMod End if( m_toggle_state == TS_GOING_DOWN ) @@ -767,7 +767,7 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) // Block all door pieces with the same targetname here. if( !FStringNull( pev->targetname ) ) { - for(;;) + for( ; ; ) { pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->targetname ) ); @@ -799,7 +799,7 @@ void CBaseDoor::Blocked( CBaseEntity *pOther ) } } if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) ); if( pDoor->m_toggle_state == TS_GOING_DOWN ) pDoor->DoorGoUp(); @@ -1106,7 +1106,7 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP // 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 ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM ); // If we already moving to designated point, return else if( move == m_vecFinalDest ) return; @@ -1118,6 +1118,6 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP void CMomentaryDoor::MomentaryMoveDone( void ) { - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ) ); - EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseArrived ), 1, ATTN_NORM ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM ); } diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 2977a3ed..c3216835 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -229,7 +229,7 @@ void CBeam::BeamInit( const char *pSpriteName, int width ) SetFrame( 0 ); SetScrollRate( 0 ); pev->model = MAKE_STRING( pSpriteName ); - SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); + SetTexture( PRECACHE_MODEL( pSpriteName ) ); SetWidth( width ); pev->skin = 0; pev->sequence = 0; @@ -486,7 +486,7 @@ void CLightning::Spawn( void ) void CLightning::Precache( void ) { - m_spriteTexture = PRECACHE_MODEL( (char *)STRING( m_iszSpriteName ) ); + m_spriteTexture = PRECACHE_MODEL( STRING( m_iszSpriteName ) ); CBeam::Precache(); } @@ -954,9 +954,9 @@ void CLaser::Spawn( void ) void CLaser::Precache( void ) { - pev->modelindex = PRECACHE_MODEL( (char *)STRING( pev->model ) ); + pev->modelindex = PRECACHE_MODEL( STRING( pev->model ) ); if( m_iszSpriteName ) - PRECACHE_MODEL( (char *)STRING( m_iszSpriteName ) ); + PRECACHE_MODEL( STRING( m_iszSpriteName ) ); } void CLaser::KeyValue( KeyValueData *pkvd ) @@ -1100,7 +1100,7 @@ void CGlow::Spawn( void ) pev->effects = 0; pev->frame = 0; - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; @@ -1160,7 +1160,7 @@ void CSprite::Spawn( void ) void CSprite::Precache( void ) { - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); // Reset attachment after save/restore if( pev->aiment ) @@ -1515,7 +1515,7 @@ void CEnvShooter::KeyValue( KeyValueData *pkvd ) void CEnvShooter::Precache( void ) { - m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING( pev->model ) ); + m_iGibModelIndex = PRECACHE_MODEL( STRING( pev->model ) ); CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); } @@ -2005,7 +2005,7 @@ void CMessage::Spawn( void ) void CMessage::Precache( void ) { if( pev->noise ) - PRECACHE_SOUND( (char *)STRING( pev->noise ) ); + PRECACHE_SOUND( STRING( pev->noise ) ); } void CMessage::KeyValue( KeyValueData *pkvd ) @@ -2040,16 +2040,15 @@ void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useT 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 ); @@ -2071,7 +2070,7 @@ public: void CEnvFunnel::Precache( void ) { - m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); + m_iSprite = PRECACHE_MODEL( "sprites/flare6.spr" ); } LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ) diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 6abf1b44..0cc3675f 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -259,7 +259,7 @@ void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) for( i = 0; i < soundCount; i++ ) { - PRECACHE_SOUND( (char *)pSoundList[i] ); + PRECACHE_SOUND( pSoundList[i] ); } } @@ -340,11 +340,11 @@ void CBreakable::Precache( void ) if( m_iszGibModel ) pGibName = STRING( m_iszGibModel ); - m_idShard = PRECACHE_MODEL( (char *)pGibName ); + m_idShard = PRECACHE_MODEL( pGibName ); // Precache the spawn item's data if( m_iszSpawnObject ) - UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) ); + UTIL_PrecacheOther( STRING( m_iszSpawnObject ) ); } // play shard sound when func_breakable takes damage. @@ -746,7 +746,7 @@ void CBreakable::Die( void ) SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = pev->ltime + 0.1; if( m_iszSpawnObject ) - CBaseEntity::Create( (char *)STRING( m_iszSpawnObject ), VecBModelOrigin( pev ), pev->angles, edict() ); + CBaseEntity::Create( STRING( m_iszSpawnObject ), VecBModelOrigin( pev ), pev->angles, edict() ); if( Explodable() ) { diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index c4e3cb42..6eebc675 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -200,13 +200,13 @@ void CFuncTank::Spawn( void ) void CFuncTank::Precache( void ) { if( m_iszSpriteSmoke ) - PRECACHE_MODEL( (char *)STRING( m_iszSpriteSmoke ) ); + PRECACHE_MODEL( STRING( m_iszSpriteSmoke ) ); if( m_iszSpriteFlash ) - PRECACHE_MODEL( (char *)STRING( m_iszSpriteFlash ) ); + PRECACHE_MODEL( STRING( m_iszSpriteFlash ) ); if( pev->noise ) - PRECACHE_SOUND( (char *)STRING( pev->noise ) ); + PRECACHE_SOUND( STRING( pev->noise ) ); } void CFuncTank::KeyValue( KeyValueData *pkvd ) @@ -688,13 +688,13 @@ 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 ); + EMIT_SOUND( edict(), CHAN_STATIC, 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 ) ); + STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noise ) ); pev->spawnflags &= ~SF_TANK_SOUNDON; } diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index 6aa6a738..f3155d7f 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -770,37 +770,37 @@ void CGargantua::Precache() PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND ); for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); + PRECACHE_SOUND( pAttackHitSounds[i] ); for( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) - PRECACHE_SOUND( (char *)pBeamAttackSounds[i] ); + PRECACHE_SOUND( pBeamAttackSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); + PRECACHE_SOUND( pAttackMissSounds[i] ); for( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) - PRECACHE_SOUND( (char *)pRicSounds[i] ); + PRECACHE_SOUND( pRicSounds[i] ); for( i = 0; i < ARRAYSIZE( pFootSounds ); i++ ) - PRECACHE_SOUND( (char *)pFootSounds[i] ); + PRECACHE_SOUND( pFootSounds[i] ); for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( (char *)pIdleSounds[i] ); + PRECACHE_SOUND( pIdleSounds[i] ); for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); + PRECACHE_SOUND( pAlertSounds[i] ); for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( (char *)pPainSounds[i] ); + PRECACHE_SOUND( pPainSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackSounds[i] ); + PRECACHE_SOUND( pAttackSounds[i] ); for( i = 0; i < ARRAYSIZE( pStompSounds ); i++ ) - PRECACHE_SOUND( (char *)pStompSounds[i] ); + PRECACHE_SOUND( pStompSounds[i] ); for( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) - PRECACHE_SOUND( (char *)pBreatheSounds[i] ); + PRECACHE_SOUND( pBreatheSounds[i] ); } void CGargantua::UpdateOnRemove() diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 23622120..3cc0acc6 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -131,7 +131,7 @@ void CGenericMonster::Spawn() //========================================================= void CGenericMonster::Precache() { - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); } //========================================================= diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index e920abfa..5daad4a2 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -67,7 +67,7 @@ class CGenericCycler : public CCycler public: void Spawn( void ) { - GenericCyclerSpawn( (char *)STRING( pev->model ), Vector( -16, -16, 0 ), Vector( 16, 16, 72 ) ); + GenericCyclerSpawn( STRING( pev->model ), Vector( -16, -16, 0 ), Vector( 16, 16, 72 ) ); } }; @@ -255,7 +255,7 @@ void CCyclerSprite::Spawn( void ) m_animate = 1; m_lastTime = gpGlobals->time; - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; @@ -314,7 +314,7 @@ void CWeaponCycler::Spawn() pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_NONE; - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); m_iszModel = pev->model; m_iModel = pev->modelindex; @@ -401,7 +401,7 @@ void CWreckage::Spawn( void ) if( pev->model ) { - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); } // pev->scale = 5.0; @@ -412,7 +412,7 @@ void CWreckage::Spawn( void ) void CWreckage::Precache() { if( pev->model ) - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); } void CWreckage::Think( void ) diff --git a/dlls/islave.cpp b/dlls/islave.cpp index 51def5d3..b516c09b 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -544,16 +544,16 @@ void CISlave::Precache() PRECACHE_SOUND( "weapons/cbar_miss1.wav" ); for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); + PRECACHE_SOUND( pAttackHitSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); + PRECACHE_SOUND( pAttackMissSounds[i] ); for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i] ); + PRECACHE_SOUND( pPainSounds[i] ); for( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) - PRECACHE_SOUND( (char *)pDeathSounds[i] ); + PRECACHE_SOUND( pDeathSounds[i] ); UTIL_PrecacheOther( "test_effect" ); } diff --git a/dlls/leech.cpp b/dlls/leech.cpp index dccffcf4..1d64eae1 100644 --- a/dlls/leech.cpp +++ b/dlls/leech.cpp @@ -277,9 +277,9 @@ void CLeech::Precache( void ) PRECACHE_MODEL( "models/leech.mdl" ); for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackSounds[i] ); + PRECACHE_SOUND( pAttackSounds[i] ); for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( (char *)pAlertSounds[i] ); + PRECACHE_SOUND( pAlertSounds[i] ); } int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index a898158f..5e06f909 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -92,7 +92,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() if( IS_DEDICATED_SERVER() ) { // dedicated server - /*char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + /*const char *servercfgfile = CVAR_GET_STRING( "servercfgfile" ); if( servercfgfile && servercfgfile[0] ) { @@ -108,7 +108,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() else { // listen server - char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); + const char *lservercfgfile = CVAR_GET_STRING( "lservercfgfile" ); if( lservercfgfile && lservercfgfile[0] ) { @@ -1214,7 +1214,7 @@ COM_Parse Parse a token out of a string ============== */ -char *COM_Parse( char *data ) +const char *COM_Parse( const char *data ) { int c; int len; @@ -1290,9 +1290,9 @@ COM_TokenWaiting Returns 1 if additional data is waiting to be processed on this line ============== */ -int COM_TokenWaiting( char *buffer ) +int COM_TokenWaiting( const char *buffer ) { - char *p; + const char *p; p = buffer; while( *p && *p!='\n') @@ -1313,12 +1313,12 @@ ReloadMapCycleFile Parses mapcycle.txt file into mapcycle_t structure ============== */ -int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) +int ReloadMapCycleFile( const char *filename, mapcycle_t *cycle ) { char szMap[32]; int length; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); + const char *pFileList; + const char *aFileList = pFileList = (const char *)LOAD_FILE_FOR_ME( filename, &length ); int hasbuffer; mapcycle_item_s *item, *newlist = NULL, *next; @@ -1396,7 +1396,7 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) } } - FREE_FILE( aFileList ); + FREE_FILE( (void*)aFileList ); } // Fixup circular list pointer @@ -1532,7 +1532,7 @@ void CHalfLifeMultiplay::ChangeLevel( void ) BOOL do_cycle = TRUE; // find the map to change to - char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + const char *mapcfile = CVAR_GET_STRING( "mapcyclefile" ); ASSERT( mapcfile != NULL ); szCommands[0] = '\0'; @@ -1650,8 +1650,8 @@ 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 ); + const char *pFileList; + const char *aFileList = pFileList = (const char*)LOAD_FILE_FOR_ME( CVAR_GET_STRING( "motdfile" ), &length ); // send the server name MESSAGE_BEGIN( MSG_ONE, gmsgServerName, NULL, client ); @@ -1679,7 +1679,7 @@ void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client ) if( char_count < MAX_MOTD_LENGTH ) pFileList = aFileList + char_count; else - *pFileList = 0; + pFileList = 0; MESSAGE_BEGIN( MSG_ONE, gmsgMOTD, NULL, client ); WRITE_BYTE( *pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come @@ -1687,5 +1687,5 @@ void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client ) MESSAGE_END(); } - FREE_FILE( aFileList ); + FREE_FILE( (void*)aFileList ); } diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index 68a1c267..b94f894b 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -2108,7 +2108,7 @@ void CTestHull::BuildNodeGraph( void ) WorldGraph.ComputeStaticRoutingTables(); // save the node graph for this level - WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); + WorldGraph.FSaveGraph( STRING( gpGlobals->mapname ) ); ALERT( at_console, "Done.\n" ); } @@ -2363,7 +2363,7 @@ void CQueuePriority::Heap_SiftUp( void ) // will be loaded. If file cannot be loaded, the node tree // will be created and saved to disk. //========================================================= -int CGraph::FLoadGraph( char *szMapName ) +int CGraph::FLoadGraph( const char *szMapName ) { char szFilename[MAX_PATH]; int iVersion; @@ -2542,7 +2542,7 @@ NoMemory: // CGraph - FSaveGraph - It's not rocket science. // this WILL overwrite existing files. //========================================================= -int CGraph::FSaveGraph( char *szMapName ) +int CGraph::FSaveGraph( const char *szMapName ) { int iVersion = GRAPH_VERSION; char szFilename[MAX_PATH]; @@ -2674,7 +2674,7 @@ int CGraph::FSetGraphPointers( void ) // 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 CGraph::CheckNODFile( const char *szMapName ) { int retValue; diff --git a/dlls/nodes.h b/dlls/nodes.h index 29440025..49036a39 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -182,9 +182,9 @@ public: void InitGraph( void ); int AllocNodes ( void ); - int CheckNODFile(char *szMapName); - int FLoadGraph(char *szMapName); - int FSaveGraph(char *szMapName); + int CheckNODFile(const char *szMapName); + int FLoadGraph(const char *szMapName); + int FSaveGraph(const char *szMapName); int FSetGraphPointers(void); void CheckNode(Vector vecOrigin, int iNode); diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 3034fd93..1e6de4bf 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -416,7 +416,7 @@ void CFuncPlat::PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE void CFuncPlat::GoDown( void ) { if( pev->noiseMovement ) - EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, 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; @@ -430,10 +430,10 @@ void CFuncPlat::GoDown( void ) void CFuncPlat::HitBottom( void ) { if( pev->noiseMovement ) - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMovement ) ); if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); ASSERT( m_toggle_state == TS_GOING_DOWN ); m_toggle_state = TS_AT_BOTTOM; @@ -445,7 +445,7 @@ void CFuncPlat::HitBottom( void ) void CFuncPlat::GoUp( void ) { if( pev->noiseMovement ) - EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, 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; @@ -459,10 +459,10 @@ void CFuncPlat::GoUp( void ) void CFuncPlat::HitTop( void ) { if( pev->noiseMovement ) - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMovement ) ); if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_WEAPON, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); ASSERT( m_toggle_state == TS_GOING_UP ); m_toggle_state = TS_AT_TOP; @@ -482,7 +482,7 @@ void CFuncPlat::Blocked( CBaseEntity *pOther ) pOther->TakeDamage( pev, pev, 1, DMG_CRUSH ); if( pev->noiseMovement ) - STOP_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMovement ) ); // Send the platform back where it came from ASSERT( m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ); @@ -670,7 +670,7 @@ void CFuncTrain::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE us pev->nextthink = 0; pev->velocity = g_vecZero; if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); } } @@ -691,9 +691,9 @@ void CFuncTrain::Wait( void ) // clear the sound channel. if( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noiseMovement ) ); if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); pev->nextthink = 0; return; } @@ -704,9 +704,9 @@ void CFuncTrain::Wait( void ) // -1 wait will wait forever! pev->nextthink = pev->ltime + m_flWait; if( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noiseMovement ) ); if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); SetThink( &CFuncTrain::Next ); } else @@ -728,10 +728,10 @@ void CFuncTrain::Next( void ) if( !pTarg ) { if( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING( pev->noiseMovement ) ); + STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noiseMovement ) ); // Play stop sound if( pev->noiseStopMoving ) - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noiseStopMoving ), m_volume, ATTN_NORM ); return; } @@ -767,8 +767,8 @@ void CFuncTrain::Next( void ) // 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 ) ); - EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMovement ), m_volume, ATTN_NORM ); + STOP_SOUND( edict(), CHAN_STATIC, STRING( pev->noiseMovement ) ); + EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMovement ), m_volume, ATTN_NORM ); } ClearBits( pev->effects, EF_NOINTERP ); @@ -1061,7 +1061,7 @@ void CFuncTrackTrain::StopSound( void ) 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 ) ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise ) ); */ EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 ); } @@ -1085,14 +1085,14 @@ void CFuncTrackTrain::UpdateSound( void ) { // 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, 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 ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int)flpitch ); */ // volume 0.0 - 1.0 - 6 bits // m_sounds 3 bits @@ -1322,7 +1322,7 @@ BOOL CFuncTrackTrain::OnControls( entvars_t *pevTest ) void CFuncTrackTrain::Find( void ) { - m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ) ); + m_ppath = CPathTrack::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ) ); if( !m_ppath ) return; diff --git a/dlls/prop.cpp b/dlls/prop.cpp index c6c4017e..7f7dba48 100644 --- a/dlls/prop.cpp +++ b/dlls/prop.cpp @@ -248,7 +248,7 @@ void CProp::MaterialSoundPrecache( Materials precacheMaterial ) for( i = 0; i < soundCount; i++ ) { - PRECACHE_SOUND( (char *)pSoundList[i] ); + PRECACHE_SOUND( pSoundList[i] ); } } @@ -327,8 +327,8 @@ void CProp::Precache( void ) if( m_iszGibModel ) pGibName = STRING( m_iszGibModel ); - m_idShard = PRECACHE_MODEL( (char *)pGibName ); - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + m_idShard = PRECACHE_MODEL( pGibName ); + PRECACHE_MODEL( STRING( pev->model ) ); } void CProp::DamageSound( void ) diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index da9708d1..678502f6 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -712,7 +712,7 @@ void CCineMonster::DelayStart( int state ) else { pTarget->m_iDelay--; - if (pTarget->m_iDelay <= 0) + if( pTarget->m_iDelay <= 0 ) pTarget->m_startTime = gpGlobals->time + 0.05; } } @@ -1177,7 +1177,7 @@ void CFurniture::Die( void ) //========================================================= void CFurniture::Spawn() { - PRECACHE_MODEL( (char *)STRING( pev->model ) ); + PRECACHE_MODEL( STRING( pev->model ) ); SET_MODEL( ENT( pev ), STRING( pev->model ) ); pev->movetype = MOVETYPE_NONE; diff --git a/dlls/sound.cpp b/dlls/sound.cpp index f6110a8d..85b9f71d 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -182,7 +182,7 @@ void CAmbientGeneric::Spawn( void ) m_flAttenuation = ATTN_STATIC; } - char* szSoundFile = (char*)STRING( pev->message ); + const char *szSoundFile = STRING( pev->message ); if( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) { @@ -216,7 +216,7 @@ void CAmbientGeneric::Spawn( void ) void CAmbientGeneric::Precache( void ) { - char* szSoundFile = (char*)STRING( pev->message ); + const char *szSoundFile = STRING( pev->message ); if( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) { @@ -248,7 +248,7 @@ void CAmbientGeneric::Precache( void ) // with lfo if active. void CAmbientGeneric::RampThink( void ) { - char* szSoundFile = (char*) STRING(pev->message); + const char *szSoundFile = STRING( pev->message ); int pitch = m_dpv.pitch; int vol = m_dpv.vol; int flags = 0; @@ -533,7 +533,7 @@ void CAmbientGeneric::InitModulationParms( void ) // void CAmbientGeneric::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { - char* szSoundFile = (char*)STRING( pev->message ); + const char *szSoundFile = STRING( pev->message ); float fraction; if( useType != USE_TOGGLE ) diff --git a/dlls/stats.cpp b/dlls/stats.cpp index 9b21f792..1df298b2 100644 --- a/dlls/stats.cpp +++ b/dlls/stats.cpp @@ -48,7 +48,7 @@ float AmmoDamage( const char *pName ) return 0; } -void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, int skillLevel ) +void UpdateStatsFile( float dataTime, const char *pMapname, float health, float ammo, int skillLevel ) { FILE *fp; @@ -136,7 +136,7 @@ void UpdateStats( CBasePlayer *pPlayer ) } else if( ( gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime ) || forceWrite ) { - UpdateStatsFile( gStats.dataTime, (char *)STRING( gpGlobals->mapname ), health, ammo, (int)CVAR_GET_FLOAT( "skill" ) ); + UpdateStatsFile( gStats.dataTime, STRING( gpGlobals->mapname ), health, ammo, (int)CVAR_GET_FLOAT( "skill" ) ); gStats.lastAmmo = ammo; gStats.lastHealth = health; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 57d8d031..8171a195 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -527,7 +527,7 @@ void CBaseTrigger::InitTrigger() SetMovedir( pev ); pev->solid = SOLID_TRIGGER; pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING( pev->model ) ); // set size and link into world + SET_MODEL( ENT( pev ), STRING( pev->model ) ); // set size and link into world if( CVAR_GET_FLOAT( "showtriggers" ) == 0 ) SetBits( pev->effects, EF_NODRAW ); } @@ -1135,7 +1135,7 @@ void CBaseTrigger::ActivateMultiTrigger( CBaseEntity *pActivator ) } if( !FStringNull( pev->noise ) ) - EMIT_SOUND( ENT( pev ), CHAN_VOICE, (char*)STRING( pev->noise ), 1, ATTN_NORM ); + EMIT_SOUND( ENT( pev ), CHAN_VOICE, STRING( pev->noise ), 1, ATTN_NORM ); // don't trigger again until reset // pev->takedamage = DAMAGE_NO; @@ -1264,7 +1264,7 @@ 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 + SET_MODEL( ENT( pev ), STRING( pev->model ) ); // set size and link into world pev->model = 0; pev->modelindex = 0; } @@ -1338,7 +1338,7 @@ TYPEDESCRIPTION CChangeLevel::m_SaveData[] = DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), }; -IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger) +IMPLEMENT_SAVERESTORE( CChangeLevel, CBaseTrigger ) // // Cache user-entity-field values until spawn is called. diff --git a/dlls/util.cpp b/dlls/util.cpp index bca89948..68ba30cd 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1052,7 +1052,7 @@ Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) return tmp; } -int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) +int UTIL_IsMasterTriggered( string_t sMaster, CBaseEntity *pActivator ) { if( sMaster ) { @@ -1340,7 +1340,7 @@ void UTIL_StringToVector( float *pVector, const char *pString ) while( *pstr && *pstr != ' ' ) pstr++; - if( !(*pstr) ) + if( !( *pstr ) ) break; pstr++; pfront = pstr; @@ -1858,7 +1858,7 @@ void CSave::WriteString( const char *pname, const int *stringId, int count ) #if 0 if( count != 1 ) ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING( *stringId ) ); + WriteString( pname, STRING( *stringId ) ); #endif size = 0; for( i = 0; i < count; i++ ) @@ -2209,9 +2209,9 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou if( !FStringNull( string ) && m_precache ) { if( pTest->fieldType == FIELD_MODELNAME ) - PRECACHE_MODEL( (char *)STRING( string ) ); + PRECACHE_MODEL( STRING( string ) ); else if( pTest->fieldType == FIELD_SOUNDNAME ) - PRECACHE_SOUND( (char *)STRING( string ) ); + PRECACHE_SOUND( STRING( string ) ); } } break; diff --git a/dlls/util.h b/dlls/util.h index c13271b0..2ffe536e 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -542,7 +542,7 @@ 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 < (int)ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } + { for (int i = 0; i < (int)ARRAYSIZE( a ); i++ ) PRECACHE_SOUND( 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) ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 06bb1796..a1205f27 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -367,7 +367,7 @@ void W_Precache( void ) 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_sModelIndexLaser = PRECACHE_MODEL( g_pModelNameLaser ); g_sModelIndexLaserDot = PRECACHE_MODEL( "sprites/laserdot.spr" ); // used by explosions @@ -535,7 +535,7 @@ 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 ); + CBaseEntity *pNewWeapon = CBaseEntity::Create( STRING( pev->classname ), g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); if( pNewWeapon ) { @@ -1297,7 +1297,7 @@ void CWeaponBox::Touch( CBaseEntity *pOther ) 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] ) ); + pPlayer->GiveAmmo( m_rgAmmo[i], STRING( m_rgiszAmmo[i] ), MaxAmmoCarry( m_rgiszAmmo[i] ) ); //ALERT( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING( m_rgiszAmmo[i] ) ); @@ -1407,7 +1407,7 @@ BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) if( iMaxCarry != -1 && iCount > 0 ) { //ALERT( at_console, "Packed %d rounds of %s\n", iCount, STRING( iszName ) ); - GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); + GiveAmmo( iCount, STRING( iszName ), iMaxCarry ); return TRUE; } diff --git a/dlls/world.cpp b/dlls/world.cpp index 1cc645c9..3b9a1f1e 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -592,7 +592,7 @@ void CWorld::Precache( void ) WorldGraph.InitGraph(); // make sure the .NOD file is newer than the .BSP file. - if( !WorldGraph.CheckNODFile( ( char * )STRING( gpGlobals->mapname ) ) ) + if( !WorldGraph.CheckNODFile( STRING( gpGlobals->mapname ) ) ) { // NOD file is not present, or is older than the BSP file. WorldGraph.AllocNodes(); @@ -600,7 +600,7 @@ void CWorld::Precache( void ) else { // Load the node graph for this level - if( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) + if( !WorldGraph.FLoadGraph( STRING( gpGlobals->mapname ) ) ) { // couldn't load, so alloc and prepare to build a graph. ALERT( at_console, "*Error opening .NOD file\n" ); diff --git a/dlls/xen.cpp b/dlls/xen.cpp index 4e9e1685..1d86beb3 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -444,9 +444,9 @@ CXenHull *CXenHull::CreateHull( CBaseEntity *source, const Vector &mins, const V CXenHull *pHull = GetClassPtr( (CXenHull *)NULL ); UTIL_SetOrigin( pHull->pev, source->pev->origin + offset ); - SET_MODEL( pHull->edict(), STRING(source->pev->model) ); + SET_MODEL( pHull->edict(), STRING( source->pev->model ) ); pHull->pev->solid = SOLID_BBOX; - pHull->pev->classname = MAKE_STRING("xen_hull"); + pHull->pev->classname = MAKE_STRING( "xen_hull" ); pHull->pev->movetype = MOVETYPE_NONE; pHull->pev->owner = source->edict(); UTIL_SetSize( pHull->pev, mins, maxs ); @@ -527,7 +527,7 @@ const char *CXenSpore::pModelNames[] = void CXenSpore::Precache( void ) { - PRECACHE_MODEL( (char *)pModelNames[pev->skin] ); + PRECACHE_MODEL( pModelNames[pev->skin] ); } void CXenSpore::Touch( CBaseEntity *pOther ) diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 2611f881..96f032e6 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -266,7 +266,7 @@ void CZombie::Spawn() { Precache(); - SET_MODEL( ENT(pev), "models/zombie.mdl" ); + SET_MODEL( ENT( pev ), "models/zombie.mdl" ); UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); pev->solid = SOLID_SLIDEBOX; @@ -291,22 +291,22 @@ void CZombie::Precache() PRECACHE_MODEL( "models/zombie.mdl" ); for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackHitSounds[i] ); + PRECACHE_SOUND( pAttackHitSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackMissSounds[i] ); + PRECACHE_SOUND( pAttackMissSounds[i] ); for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( (char *)pAttackSounds[i] ); + PRECACHE_SOUND( pAttackSounds[i] ); for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( (char *)pIdleSounds[i] ); + PRECACHE_SOUND( pIdleSounds[i] ); for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( (char *)pAlertSounds[i] ); + PRECACHE_SOUND( pAlertSounds[i] ); for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( (char *)pPainSounds[i] ); + PRECACHE_SOUND( pPainSounds[i] ); } //========================================================= From 4150b464a047d87f398c8a9838a6a27fa3646418 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 24 Jul 2017 16:38:38 +0500 Subject: [PATCH 194/227] Improve spectator. --- dlls/client.cpp | 28 +++++++++++++++++++--------- dlls/observer.cpp | 23 +++++++++++++++++++++++ dlls/player.h | 1 + 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/dlls/client.cpp b/dlls/client.cpp index 569b1a53..32b6bebd 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -556,20 +556,30 @@ void ClientCommand( edict_t *pEntity ) } 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 ); + if( !pPlayer->IsObserver() ) { - CBasePlayer *pPlayer = GetClassPtr( (CBasePlayer *)pev ); + // always allow proxies to become a spectator + if( ( pev->flags & FL_PROXY ) || allow_spectators.value ) + { + edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + pPlayer->StartObserver( pev->origin, VARS( pentSpawnSpot )->angles ); - 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", + // 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 - ClientPrint( pev, HUD_PRINTCONSOLE, "Spectator mode is disabled.\n" ); + { + pPlayer->StopObserver(); + + // notify other clients of player left spectators + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has left spectator mode\n", + ( pev->netname && ( STRING( pev->netname ) )[0] != 0 ) ? STRING( pev->netname ) : "unconnected" ) ); + } } else if( FStrEq( pcmd, "specmode" ) ) // new spectator mode { diff --git a/dlls/observer.cpp b/dlls/observer.cpp index f3fc54a0..22fa3818 100644 --- a/dlls/observer.cpp +++ b/dlls/observer.cpp @@ -24,6 +24,10 @@ extern int gmsgCurWeapon; extern int gmsgSetFOV; +extern int gmsgTeamInfo; + +extern int g_teamplay; + // Find the next client in the game for this player to spectate void CBasePlayer::Observer_FindNextPlayer( bool bReverse ) { @@ -266,3 +270,22 @@ void CBasePlayer::Observer_SetMode( int iMode ) m_iObserverLastMode = iMode; } + +void CBasePlayer::StopObserver() +{ + // Turn off spectator + pev->iuser1 = pev->iuser2 = 0; + m_iHideHUD = 0; + + GetClassPtr( (CBasePlayer *)pev )->Spawn(); + pev->nextthink = -1; + + // Update Team Status + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( ENTINDEX( edict() ) ); // index number of primary entity + if( g_teamplay ) + WRITE_STRING( TeamID() ); + else + WRITE_STRING( "Players" ); + MESSAGE_END(); +} diff --git a/dlls/player.h b/dlls/player.h index 1c17556c..54e7fa85 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -255,6 +255,7 @@ public: void StartDeathCam( void ); void StartObserver( Vector vecPosition, Vector vecViewAngle ); + void StopObserver(); void AddPoints( int score, BOOL bAllowNegativeScore ); void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); From aaf81c770994d179c43b39e4233299752dec7f44 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 24 Jul 2017 16:56:43 +0500 Subject: [PATCH 195/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/ef7cecf654ccf7716a5646ff9498928905a266dc --- pm_shared/pm_math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c index 5bbe0068..4bb4b93f 100644 --- a/pm_shared/pm_math.c +++ b/pm_shared/pm_math.c @@ -239,7 +239,7 @@ float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ) if( !l1 || !l2 ) return 0.0f; - angle = acos( DotProduct( v1, v2 ) ) / ( l1 * l2 ); + angle = acos( DotProduct( v1, v2 ) / ( l1 * l2 ) ); angle = ( angle * 180.0f ) / M_PI; return angle; From 96b1f4c58e8d8be9c1f743275b3ab562e50111ea Mon Sep 17 00:00:00 2001 From: mittorn Date: Sun, 30 Jul 2017 12:30:47 +0300 Subject: [PATCH 196/227] Fix wrong -std=c99 --- cl_dll/Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index ecbae657..a79b6363 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -13,7 +13,6 @@ LOCAL_MODULE := client #else APP_PLATFORM := android-8 #endif -LOCAL_CONLYFLAGS += -std=c99 include $(XASH3D_CONFIG) From f14d7cc552dadde3756edddbf72a04251b620c9c Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 24 Jul 2017 23:07:59 +0500 Subject: [PATCH 197/227] A little fix. --- dlls/multiplay_gamerules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 5e06f909..8d089696 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1682,7 +1682,7 @@ void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client ) pFileList = 0; MESSAGE_BEGIN( MSG_ONE, gmsgMOTD, NULL, client ); - WRITE_BYTE( *pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come + WRITE_BYTE( pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come WRITE_STRING( chunk ); MESSAGE_END(); } From e3f953064dfe57f407d5129b432705d5d184af02 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 25 Jul 2017 13:24:06 +0500 Subject: [PATCH 198/227] Remove unneeded macros. --- dlls/enginecallback.h | 4 ---- engine/custom.h | 5 ----- engine/edict.h | 4 ---- engine/progdefs.h | 5 ----- pm_shared/pm_debug.h | 4 ---- pm_shared/pm_defs.h | 5 ----- pm_shared/pm_info.h | 4 ---- pm_shared/pm_shared.h | 4 ---- 8 files changed, 35 deletions(-) diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index 9bef0d48..a9e37c26 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -15,11 +15,7 @@ #ifndef ENGINECALLBACK_H #define ENGINECALLBACK_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #include "event_flags.h" diff --git a/engine/custom.h b/engine/custom.h index 8f644e00..30ee8d53 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -12,15 +12,10 @@ * without written permission from Valve LLC. * ****/ - #ifndef CUSTOM_H #define CUSTOM_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #include "const.h" diff --git a/engine/edict.h b/engine/edict.h index e89b6926..3994c705 100644 --- a/engine/edict.h +++ b/engine/edict.h @@ -16,11 +16,7 @@ #ifndef EDICT_H #define EDICT_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #define MAX_ENT_LEAFS 48 diff --git a/engine/progdefs.h b/engine/progdefs.h index cdbcc006..56d904b1 100644 --- a/engine/progdefs.h +++ b/engine/progdefs.h @@ -12,15 +12,10 @@ * without written permission from Valve LLC. * ****/ - #ifndef PROGDEFS_H #define PROGDEFS_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif typedef struct { diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index cc130598..417c3478 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -15,11 +15,7 @@ #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 ); diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index b4c652ba..eddb17b6 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -12,15 +12,10 @@ * without written permission from Valve LLC. * ****/ - #ifndef PM_DEFS_H #define PM_DEFS_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #define MAX_PHYSENTS 600 // Must have room for all entities in the world. #define MAX_MOVEENTS 64 diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index d9dbc03d..d75b67fc 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -15,11 +15,7 @@ #ifndef PM_INFO_H #define PM_INFO_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #define MAX_PHYSINFO_STRING 256 #endif//PM_INFO_H diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index 1d0e4f38..2fb947a2 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -16,11 +16,7 @@ #ifndef PM_SHARED_H #define PM_SHARED_H -#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 ); From 65dc1997f7685b8cb6adc9ac1cb5594ca5f9c623 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Tue, 25 Jul 2017 23:52:50 +0500 Subject: [PATCH 199/227] Fix typo. --- dlls/plats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 1e6de4bf..c1220f3c 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1502,7 +1502,7 @@ void CFuncTrackTrain::Precache( void ) break; } - if( !pszSound ) + if( pszSound ) { PRECACHE_SOUND( pszSound ); pev->noise = MAKE_STRING( pszSound ); From 46ecb7e8eecc446472504f0112cb80fc0b64d4b4 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 9 Oct 2017 19:51:51 +0500 Subject: [PATCH 200/227] Fix shadowing variables. --- cl_dll/ev_hldm.cpp | 16 ++++++++-------- cl_dll/view.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index d94f9fea..80073b27 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -38,7 +38,7 @@ extern engine_studio_api_t IEngineStudio; -static int tracerCount[32]; +static int g_tracerCount[32]; extern "C" char PM_FindTextureType( char *name ); @@ -546,7 +546,7 @@ void EV_FireGlock2( event_args_t *args ) VectorCopy( forward, vecAiming ); - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &g_tracerCount[idx - 1], args->fparam1, args->fparam2 ); } //====================== // GLOCK END @@ -602,11 +602,11 @@ void EV_FireShotGunDouble( event_args_t *args ) if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.17365, 0.04362 ); + EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &g_tracerCount[idx - 1], 0.17365, 0.04362 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.08716 ); + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &g_tracerCount[idx - 1], 0.08716, 0.08716 ); } } @@ -654,11 +654,11 @@ void EV_FireShotGunSingle( event_args_t *args ) if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.04362 ); + EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &g_tracerCount[idx - 1], 0.08716, 0.04362 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx - 1], 0.08716, 0.08716 ); + EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, 2048, BULLET_PLAYER_BUCKSHOT, 0, &g_tracerCount[idx - 1], 0.08716, 0.08716 ); } } //====================== @@ -719,11 +719,11 @@ void EV_FireMP5( event_args_t *args ) if( gEngfuncs.GetMaxClients() > 1 ) { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &g_tracerCount[idx - 1], args->fparam1, args->fparam2 ); } else { - EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx - 1], args->fparam1, args->fparam2 ); + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_MP5, 2, &g_tracerCount[idx - 1], args->fparam1, args->fparam2 ); } } diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index efa4b104..a4abe91c 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -91,7 +91,7 @@ float v_cameraFocusAngle = 35.0f; int v_cameraMode = CAM_MODE_FOCUS; qboolean v_resetCamera = 1; -vec3_t ev_punchangle; +vec3_t g_ev_punchangle; cvar_t *scr_ofsx; cvar_t *scr_ofsy; @@ -630,9 +630,9 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) VectorAdd( pparams->viewangles, pparams->punchangle, pparams->viewangles ); // Include client side punch, too - VectorAdd( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles ); + VectorAdd( pparams->viewangles, (float *)&g_ev_punchangle, pparams->viewangles ); - V_DropPunchAngle( pparams->frametime, (float *)&ev_punchangle ); + V_DropPunchAngle( pparams->frametime, (float *)&g_ev_punchangle ); // smooth out stair step ups #if 1 @@ -1579,7 +1579,7 @@ Client side punch effect */ void V_PunchAxis( int axis, float punch ) { - ev_punchangle[axis] = punch; + g_ev_punchangle[axis] = punch; } /* From e7989d438a4eea04317fc4dd7b79b34c9c18f3d8 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 15 Oct 2017 00:12:26 +0500 Subject: [PATCH 201/227] Fix compatibility with MSVC 6. --- cl_dll/ammo.cpp | 6 +++--- dlls/player.cpp | 2 +- dlls/scientist.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index edc21652..4104acff 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -305,7 +305,7 @@ void CHudAmmo::Reset( void ) gHR.Reset(); //VidInit(); - wrect_t nullrc = {}; + wrect_t nullrc = {0,}; SetCrosshair( 0, nullrc, 0, 0, 0 ); // reset crosshair m_pWeapon = NULL; // reset last weapon } @@ -539,7 +539,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) if( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) { - wrect_t nullrc = {}; + wrect_t nullrc = {0,}; gpActiveSel = NULL; SetCrosshair( 0, nullrc, 0, 0, 0 ); } @@ -559,7 +559,7 @@ int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) // int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) { - wrect_t nullrc = {}; + wrect_t nullrc = {0,}; int fOnTarget = FALSE; BEGIN_READ( pbuf, iSize ); diff --git a/dlls/player.cpp b/dlls/player.cpp index 38038b36..e5a01bae 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -666,7 +666,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) int iWeaponRules; int iAmmoRules; int i; - CBasePlayerWeapon *rgpPackWeapons[MAX_WEAPONS] = {}; + CBasePlayerWeapon *rgpPackWeapons[MAX_WEAPONS] = {0,}; int iPackAmmo[MAX_AMMO_SLOTS]; int iPW = 0;// index into packweapons array int iPA = 0;// index into packammo array diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 7cf9cc4d..7e94b286 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -467,7 +467,7 @@ void CScientist::StartTask( Task_t *pTask ) //The enemy can be null here. - Solokiller //Discovered while testing the barnacle grapple on headcrabs with scientists in view. - if( m_hEnemy && m_hEnemy->IsPlayer() ) + if( m_hEnemy != 0 && m_hEnemy->IsPlayer() ) PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); else PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); From f78471ad1d562ba0a53a43981fba5a823ca3957f Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 15 Oct 2017 00:57:55 +0500 Subject: [PATCH 202/227] min->Q_min, max->Q_max. --- cl_dll/hl/hl_weapons.cpp | 2 +- dlls/apache.cpp | 8 ++++---- dlls/client.cpp | 8 ++++---- dlls/combat.cpp | 2 +- dlls/effects.cpp | 12 ++++++------ dlls/extdll.h | 8 ++++---- dlls/hassassin.cpp | 4 ++-- dlls/items.cpp | 2 +- dlls/maprules.cpp | 2 +- dlls/monsters.cpp | 2 +- dlls/multiplay_gamerules.cpp | 8 ++++---- dlls/nihilanth.cpp | 4 ++-- dlls/nodes.cpp | 14 +++++++------- dlls/player.cpp | 16 ++++++++-------- dlls/sound.cpp | 2 +- dlls/talkmonster.cpp | 4 ++-- dlls/turret.cpp | 2 +- dlls/util.cpp | 4 ++-- dlls/weapons.cpp | 8 ++++---- 19 files changed, 56 insertions(+), 56 deletions(-) diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 8f8baea7..75161a9e 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -151,7 +151,7 @@ BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, i if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) return FALSE; - int j = min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); + int j = Q_min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); if( j == 0 ) return FALSE; diff --git a/dlls/apache.cpp b/dlls/apache.cpp index aeeea30e..b3cfcf87 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -804,13 +804,13 @@ BOOL CApache::FireGun() angles.x = angles.x + 360; if( angles.x > m_angGun.x ) - m_angGun.x = min( angles.x, m_angGun.x + 12 ); + m_angGun.x = Q_min( angles.x, m_angGun.x + 12 ); if( angles.x < m_angGun.x ) - m_angGun.x = max( angles.x, m_angGun.x - 12 ); + m_angGun.x = Q_max( angles.x, m_angGun.x - 12 ); if( angles.y > m_angGun.y ) - m_angGun.y = min( angles.y, m_angGun.y + 12 ); + m_angGun.y = Q_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 = Q_max( angles.y, m_angGun.y - 12 ); m_angGun.y = SetBoneController( 0, m_angGun.y ); m_angGun.x = SetBoneController( 1, m_angGun.x ); diff --git a/dlls/client.cpp b/dlls/client.cpp index 32b6bebd..578534e3 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1656,12 +1656,12 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) 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_flTimeWeaponIdle = Q_max( gun->m_flTimeWeaponIdle, -0.001 ); + item->m_flNextPrimaryAttack = Q_max( gun->m_flNextPrimaryAttack, -0.001 ); + item->m_flNextSecondaryAttack = Q_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->fuser1 = Q_max( gun->pev->fuser1, -0.001 ); item->fuser2 = gun->m_flStartThrow; item->fuser3 = gun->m_flReleaseThrow; item->iuser1 = gun->m_chargeReady; diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 35e4ffcf..9f221cc9 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -727,7 +727,7 @@ void CGib::BounceGibTouch( CBaseEntity *pOther ) float volume; float zvel = fabs( pev->velocity.z ); - volume = 0.8 * min( 1.0, ( (float)zvel ) / 450.0 ); + volume = 0.8 * Q_min( 1.0, ( (float)zvel ) / 450.0 ); CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); } diff --git a/dlls/effects.cpp b/dlls/effects.cpp index c3216835..15df3bc3 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -280,12 +280,12 @@ 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.x = Q_min( startPos.x, endPos.x ); + pev->mins.y = Q_min( startPos.y, endPos.y ); + pev->mins.z = Q_min( startPos.z, endPos.z ); + pev->maxs.x = Q_max( startPos.x, endPos.x ); + pev->maxs.y = Q_max( startPos.y, endPos.y ); + pev->maxs.z = Q_max( startPos.z, endPos.z ); pev->mins = pev->mins - pev->origin; pev->maxs = pev->maxs - pev->origin; diff --git a/dlls/extdll.h b/dlls/extdll.h index d9587bae..45c42309 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -88,11 +88,11 @@ typedef float vec_t; // needed before including progdefs.h // Shared header between the client DLL and the game DLLs #include "cdll_dll.h" -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) +#ifndef Q_min +#define Q_min(a,b) (((a) < (b)) ? (a) : (b)) #endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) +#ifndef Q_max +#define Q_max(a,b) (((a) > (b)) ? (a) : (b)) #endif #endif //EXTDLL_H diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp index ff053595..f51ed4cb 100644 --- a/dlls/hassassin.cpp +++ b/dlls/hassassin.cpp @@ -699,12 +699,12 @@ void CHAssassin::RunAI( void ) EMIT_SOUND( ENT( pev ), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); } - pev->renderamt = max( pev->renderamt - 50, m_iTargetRanderamt ); + pev->renderamt = Q_max( pev->renderamt - 50, m_iTargetRanderamt ); pev->rendermode = kRenderTransTexture; } else if( pev->renderamt < m_iTargetRanderamt ) { - pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt ); + pev->renderamt = Q_min( pev->renderamt + 50, m_iTargetRanderamt ); if( pev->renderamt == 255 ) pev->rendermode = kRenderNormal; } diff --git a/dlls/items.cpp b/dlls/items.cpp index b0b2aa38..45edeb5e 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -227,7 +227,7 @@ class CItemBattery : public CItem char szcharge[64]; pPlayer->pev->armorvalue += gSkillData.batteryCapacity; - pPlayer->pev->armorvalue = min( pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY ); + pPlayer->pev->armorvalue = Q_min( pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY ); EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index bfec93e2..519f7d2a 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -768,7 +768,7 @@ void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) m_weaponNames[i] = ALLOC_STRING( tmp ); m_weaponCount[i] = atoi( pkvd->szValue ); - m_weaponCount[i] = max( 1, m_weaponCount[i] ); + m_weaponCount[i] = Q_max( 1, m_weaponCount[i] ); pkvd->fHandled = TRUE; break; } diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index a9796a80..1e1d3de3 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -1959,7 +1959,7 @@ void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f while( flTotal > 0.001 ) { // don't walk more than 16 units or stairs stop working - flStep = min( 16.0, flTotal ); + flStep = Q_min( 16.0, flTotal ); UTIL_MoveToOrigin( ENT( pev ), m_Route[m_iRouteIndex].vecLocation, flStep, MOVE_NORMAL ); flTotal -= flStep; } diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 8d089696..7922d413 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1368,15 +1368,15 @@ int ReloadMapCycleFile( const char *filename, mapcycle_t *cycle ) if( s && s[0] ) { item->minplayers = atoi( s ); - item->minplayers = max( item->minplayers, 0 ); - item->minplayers = min( item->minplayers, gpGlobals->maxClients ); + item->minplayers = Q_max( item->minplayers, 0 ); + item->minplayers = Q_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 ); + item->maxplayers = Q_max( item->maxplayers, 0 ); + item->maxplayers = Q_min( item->maxplayers, gpGlobals->maxClients ); } // Remove keys diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 34375a58..1d072db4 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -478,7 +478,7 @@ void CNihilanth::DyingThink( void ) { if( m_pBall->pev->renderamt > 0 ) { - m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2 ); + m_pBall->pev->renderamt = Q_max( 0, m_pBall->pev->renderamt - 2 ); } else { @@ -895,7 +895,7 @@ void CNihilanth::HuntThink( void ) } else { - m_flAdj = min( m_flAdj + 10, 1000 ); + m_flAdj = Q_min( m_flAdj + 10, 1000 ); } } diff --git a/dlls/nodes.cpp b/dlls/nodes.cpp index b94f894b..04705638 100644 --- a/dlls/nodes.cpp +++ b/dlls/nodes.cpp @@ -793,12 +793,12 @@ void inline CalcBounds( int &Lower, int &Upper, int Goal, int Best ) int Temp = 2 * Goal - Best; if( Best > Goal ) { - Lower = max( 0, Temp ); + Lower = Q_max( 0, Temp ); Upper = Best; } else { - Upper = min( 255, Temp ); + Upper = Q_min( 255, Temp ); Lower = Best; } } @@ -962,7 +962,7 @@ int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) } } - for( i = max( m_minY, halfY + 1 ); i <= m_maxY; i++ ) + for( i = Q_max( m_minY, halfY + 1 ); i <= m_maxY; i++ ) { for( j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++ ) { @@ -987,7 +987,7 @@ int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) } } - for( i = min( m_maxZ, halfZ ); i >= m_minZ; i-- ) + for( i = Q_min( m_maxZ, halfZ ); i >= m_minZ; i-- ) { for( j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++ ) { @@ -1012,7 +1012,7 @@ int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) } } - for( i = max( m_minX, halfX + 1 ); i <= m_maxX; i++ ) + for( i = Q_max( m_minX, halfX + 1 ); i <= m_maxX; i++ ) { for( j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++ ) { @@ -1034,7 +1034,7 @@ int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) } } - for( i = min( m_maxY, halfY ); i >= m_minY; i-- ) + for( i = Q_min( m_maxY, halfY ); i >= m_minY; i-- ) { for( j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++ ) { @@ -1055,7 +1055,7 @@ int CGraph::FindNearestNode( const Vector &vecOrigin, int afNodeTypes ) } } - for( i = max( m_minZ, halfZ + 1 ); i <= m_maxZ; i++ ) + for( i = Q_max( m_minZ, halfZ + 1 ); i <= m_maxZ; i++ ) { for( j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++ ) { diff --git a/dlls/player.cpp b/dlls/player.cpp index e5a01bae..757f03e4 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2049,7 +2049,7 @@ void CBasePlayer::CheckTimeBasedDamage() // after the player has been drowning and finally takes a breath if( m_idrowndmg > m_idrownrestored ) { - int idif = min( m_idrowndmg - m_idrownrestored, 10 ); + int idif = Q_min( m_idrowndmg - m_idrownrestored, 10 ); TakeHealth( idif, DMG_GENERIC ); m_idrownrestored += idif; @@ -2606,23 +2606,23 @@ pt_end: 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 ); + gun->m_flNextPrimaryAttack = Q_max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); + gun->m_flNextSecondaryAttack = Q_max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 ); if( gun->m_flTimeWeaponIdle != 1000 ) { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); + gun->m_flTimeWeaponIdle = Q_max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); } if( gun->pev->fuser1 != 1000 ) { - gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 ); + gun->pev->fuser1 = Q_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 ); + gun->m_flPumpTime = Q_max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); }*/ } @@ -3705,7 +3705,7 @@ int CBasePlayer::GiveAmmo( int iCount, const char *szName, int iMax ) if( i < 0 || i >= MAX_AMMO_SLOTS ) return -1; - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); + int iAdd = Q_min( iCount, iMax - m_rgAmmo[i] ); if( iAdd < 1 ) return i; @@ -3826,7 +3826,7 @@ void CBasePlayer::SendAmmoUpdate( void ) // 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 + WRITE_BYTE( Q_max( Q_min( m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte MESSAGE_END(); } } diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 85b9f71d..31d0b7aa 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1567,7 +1567,7 @@ void TEXTURETYPE_Init() continue; // null-terminate name and save in sentences array - j = min( j, CBTEXTURENAMEMAX - 1 + i ); + j = Q_min( j, CBTEXTURENAMEMAX - 1 + i ); buffer[j] = 0; strcpy( &( grgszTextureName[gcTextures++][0] ), &( buffer[i] ) ); } diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index 35bf3856..9180f037 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -403,11 +403,11 @@ void CTalkMonster::StartTask( Task_t *pTask ) if( yaw < 0 ) { - pev->ideal_yaw = min( yaw + 45, 0 ) + pev->angles.y; + pev->ideal_yaw = Q_min( yaw + 45, 0 ) + pev->angles.y; } else { - pev->ideal_yaw = max( yaw - 45, 0 ) + pev->angles.y; + pev->ideal_yaw = Q_max( yaw - 45, 0 ) + pev->angles.y; } } TaskComplete(); diff --git a/dlls/turret.cpp b/dlls/turret.cpp index ae95db14..093b2032 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -454,7 +454,7 @@ void CBaseTurret::EyeOff() { if( m_eyeBrightness > 0 ) { - m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); + m_eyeBrightness = Q_max( 0, m_eyeBrightness - 30 ); m_pEyeGlow->SetBrightness( m_eyeBrightness ); } } diff --git a/dlls/util.cpp b/dlls/util.cpp index 68ba30cd..f382ac58 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1112,7 +1112,7 @@ void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, WRITE_COORD( direction.y ); WRITE_COORD( direction.z ); WRITE_BYTE( color ); - WRITE_BYTE( min( amount, 255 ) ); + WRITE_BYTE( Q_min( amount, 255 ) ); MESSAGE_END(); } @@ -1144,7 +1144,7 @@ void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, 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 + WRITE_BYTE( Q_min( Q_max( 3, amount / 10 ), 16 ) ); // size MESSAGE_END(); } diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index a1205f27..80a45284 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -607,7 +607,7 @@ 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]); + int j = Q_min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); // Add them to the clip m_iClip += j; @@ -850,7 +850,7 @@ BOOL CBasePlayerWeapon::AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, else if( m_iClip == 0 ) { int i; - i = min( m_iClip + iCount, iMaxClip ) - m_iClip; + i = Q_min( m_iClip + iCount, iMaxClip ) - m_iClip; m_iClip += i; iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); } @@ -964,7 +964,7 @@ BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, i if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) return FALSE; - int j = min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); + int j = Q_min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ); if( j == 0 ) return FALSE; @@ -1428,7 +1428,7 @@ int CWeaponBox::GiveAmmo( int iCount, const char *szName, int iMax, int *pIndex/ if( pIndex ) *pIndex = i; - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); + int iAdd = Q_min( iCount, iMax - m_rgAmmo[i] ); if( iCount == 0 || iAdd > 0 ) { m_rgAmmo[i] += iAdd; From 8e799fcf6d4fc6f3f685e07173d6e538968695ac Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 15 Oct 2017 14:22:14 +0500 Subject: [PATCH 203/227] Add crowbar idle animations under CROWBAR_IDLE_ANIM macro. --- cl_dll/ev_hldm.cpp | 6 ++++++ dlls/crowbar.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- dlls/weapons.h | 3 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 80073b27..628b5bfa 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1138,7 +1138,13 @@ enum crowbar_e CROWBAR_ATTACK2MISS, CROWBAR_ATTACK2HIT, CROWBAR_ATTACK3MISS, +#ifndef CROWBAR_IDLE_ANIM CROWBAR_ATTACK3HIT +#else + CROWBAR_ATTACK3HIT, + CROWBAR_IDLE2, + CROWBAR_IDLE3 +#endif }; int g_iSwing; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index f9a91978..4cc48d97 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -37,7 +37,13 @@ enum crowbar_e CROWBAR_ATTACK2MISS, CROWBAR_ATTACK2HIT, CROWBAR_ATTACK3MISS, +#ifndef CROWBAR_IDLE_ANIM CROWBAR_ATTACK3HIT +#else + CROWBAR_ATTACK3HIT, + CROWBAR_IDLE2, + CROWBAR_IDLE3 +#endif }; void CCrowbar::Spawn() @@ -208,7 +214,9 @@ int CCrowbar::Swing( int fFirst ) { // miss m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); - +#ifdef CROWBAR_IDLE_ANIM + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +#endif // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); } @@ -324,5 +332,38 @@ int CCrowbar::Swing( int fFirst ) #endif m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); } +#ifdef CROWBAR_IDLE_ANIM + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +#endif return fDidHit; } + +#ifdef CROWBAR_IDLE_ANIM +void CCrowbar::WeaponIdle( void ) +{ + if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); + if( flRand > 0.9 ) + { + iAnim = CROWBAR_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 160.0 / 30.0; + } + else + { + if( flRand > 0.5 ) + { + iAnim = CROWBAR_IDLE; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 30.0; + } + else + { + iAnim = CROWBAR_IDLE3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 160.0 / 30.0; + } + } + SendWeaponAnim( iAnim ); + } +} +#endif diff --git a/dlls/weapons.h b/dlls/weapons.h index f48767c8..6c03105b 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -504,6 +504,9 @@ public: int Swing( int fFirst ); BOOL Deploy( void ); void Holster( int skiplocal = 0 ); +#ifdef CROWBAR_IDLE_ANIM + void WeaponIdle(); +#endif int m_iSwing; TraceResult m_trHit; From aaedd794c36cfae4bbecabf5ce9c55116307e3ee Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 15 Oct 2017 17:50:05 +0500 Subject: [PATCH 204/227] Merge https://github.com/LevShisterov/BugfixedHL/commit/293b41b8cd20f19179926284e4100f00e8e62fd7 --- dlls/player.cpp | 5 +++++ dlls/player.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/dlls/player.cpp b/dlls/player.cpp index 757f03e4..d0a1f763 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2586,6 +2586,11 @@ void CBasePlayer::PostThink() UpdatePlayerSound(); pt_end: + if( pev->deadflag == DEAD_NO ) + m_vecLastViewAngles = pev->angles; + else + pev->angles = m_vecLastViewAngles; + // Track button info so we can detect 'pressed' and 'released' buttons next frame m_afButtonLast = pev->button; diff --git a/dlls/player.h b/dlls/player.h index 54e7fa85..fecaf3c9 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -306,6 +306,8 @@ public: void TabulateAmmo( void ); + Vector m_vecLastViewAngles; + float m_flStartCharge; float m_flAmmoStartCharge; float m_flPlayAftershock; From 5aa11a38b3148dd220321a745cbdb3194947f0ba Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 1 Nov 2017 16:43:29 +0300 Subject: [PATCH 205/227] Give player exhaustible weapons when taking ammo for them from weaponbox --- dlls/weapons.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 80a45284..5e4f8f78 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1265,6 +1265,18 @@ void CWeaponBox::Kill( void ) UTIL_Remove( this ); } +static const char* IsAmmoForExhaustibleWeapon(const char* ammoName, int& weaponId) +{ + for (int i=0; im_rgpPlayerItems[j]; + while( pPlayerItem ) + { + if (pPlayerItem->m_iId == exhaustibleWeaponId) { + foundWeapon = true; + break; + } + pPlayerItem = pPlayerItem->m_pNext; + } + } + if (!foundWeapon) { + CBasePlayerWeapon* weapon = (CBasePlayerWeapon*)Create(weaponName, pev->origin, pev->angles); + if (weapon) { + weapon->pev->spawnflags |= SF_NORESPAWN; + weapon->m_iDefaultAmmo = 0; + if (pPlayer->AddPlayerItem(weapon)) { + weapon->AttachToPlayer(pPlayer); + } + } + } + } + // there's some ammo of this type. pPlayer->GiveAmmo( m_rgAmmo[i], STRING( m_rgiszAmmo[i] ), MaxAmmoCarry( m_rgiszAmmo[i] ) ); From 7d33351f77d7ac1f843c05a70bae8c9a8eabe8bf Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 18 Nov 2017 14:49:01 +0500 Subject: [PATCH 206/227] Add missing file to build lists. --- dlls/Android.mk | 1 + dlls/CMakeLists.txt | 1 + dlls/Makefile | 1 + 3 files changed, 3 insertions(+) diff --git a/dlls/Android.mk b/dlls/Android.mk index b160c424..1dc79616 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -96,6 +96,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ plane.cpp \ plats.cpp \ player.cpp \ + playermonster.cpp \ python.cpp \ rat.cpp \ roach.cpp \ diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index e0b6a8b3..4e56ab44 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -98,6 +98,7 @@ set (SVDLL_SOURCES plane.cpp plats.cpp player.cpp + playermonster.cpp python.cpp rat.cpp roach.cpp diff --git a/dlls/Makefile b/dlls/Makefile index 9c3a84f2..60aad1b3 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -135,6 +135,7 @@ OBJ = \ $(DLL_OBJDIR)/plane.o \ $(DLL_OBJDIR)/plats.o \ $(DLL_OBJDIR)/player.o \ + $(DLL_OBJDIR)/playermonster.o \^M $(DLL_OBJDIR)/python.o \ $(DLL_OBJDIR)/rat.o \ $(DLL_OBJDIR)/roach.o \ From ad3a2141eb53a42b15dd6a994971900873530c9a Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sun, 3 Dec 2017 18:52:38 +0300 Subject: [PATCH 207/227] Change __MSC_VER to _MSC_VER to make the client buildable with VS 6 --- engine/cdll_int.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/cdll_int.h b/engine/cdll_int.h index d45bb9d5..20af4b55 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -93,7 +93,7 @@ typedef struct client_textmessage_s const char *pMessage; } client_textmessage_t; -#if __MSC_VER == 1200 +#if _MSC_VER == 1200 #define ulonglong_t __int64 #else #define ulonglong_t unsigned long long From 31b2a68d6d45bf4682043e9888b2f2b1f4f49df9 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Fri, 18 Nov 2016 01:05:05 +0300 Subject: [PATCH 208/227] goldsource mouse input --- CMakeLists.txt | 3 +- cl_dll/CMakeLists.txt | 42 +- cl_dll/input_goldsource.cpp | 1357 +++++++++++++++++++++++++++++++++++ cl_dll/inputw32.cpp | 901 ----------------------- 4 files changed, 1384 insertions(+), 919 deletions(-) create mode 100644 cl_dll/input_goldsource.cpp delete mode 100644 cl_dll/inputw32.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c2d6822..7719bac6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ option(USE_VGUI2 "Enable VGUI2. UNDONE" OFF) option(USE_VOICEMGR "Enable VOICE MANAGER." OFF) option(BUILD_CLIENT "Build client dll" ON) option(BUILD_SERVER "Build server dll" ON) +option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF) #----------------- # MAIN BUILD CODE \ @@ -59,4 +60,4 @@ endif() if(NOT BUILD_SERVER AND NOT BUILD_CLIENT) error("Nothing to build") -endif() \ No newline at end of file +endif() diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 7fffb29b..7bd04f77 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -26,24 +26,27 @@ project (CLDLL) set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") +if (GOLDSOURCE_SUPPORT) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lSDL2 -Wl,--no-undefined") +endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") -set (CLDLL_SOURCES - ../dlls/crossbow.cpp - ../dlls/crowbar.cpp - ../dlls/egon.cpp - ../dlls/gauss.cpp - ../dlls/handgrenade.cpp - ../dlls/hornetgun.cpp - ../dlls/mp5.cpp - ../dlls/python.cpp - ../dlls/rpg.cpp - ../dlls/satchel.cpp - ../dlls/shotgun.cpp - ../dlls/squeakgrenade.cpp - ../dlls/tripmine.cpp +set (CLDLL_SOURCES + ../dlls/crossbow.cpp + ../dlls/crowbar.cpp + ../dlls/egon.cpp + ../dlls/gauss.cpp + ../dlls/handgrenade.cpp + ../dlls/hornetgun.cpp + ../dlls/mp5.cpp + ../dlls/python.cpp + ../dlls/rpg.cpp + ../dlls/satchel.cpp + ../dlls/shotgun.cpp + ../dlls/squeakgrenade.cpp + ../dlls/tripmine.cpp ../dlls/glock.cpp - ev_hldm.cpp + ev_hldm.cpp hl/hl_baseentity.cpp hl/hl_events.cpp hl/hl_objects.cpp @@ -70,7 +73,6 @@ set (CLDLL_SOURCES hud_update.cpp in_camera.cpp input.cpp -#SRCS+=./inputw32.cpp menu.cpp message.cpp overview.cpp @@ -88,9 +90,15 @@ set (CLDLL_SOURCES tri.cpp util.cpp view.cpp - input_xash3d.cpp scoreboard.cpp MOTD.cpp) + +if (GOLDSOURCE_SUPPORT) + set (CLDLL_SOURCES "${CLDLL_SOURCES}" input_goldsource.cpp) +else() + set (CLDLL_SOURCES "${CLDLL_SOURCES}" input_xash3d.cpp) +endif() + include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public) if(USE_VOICEMGR) diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp new file mode 100644 index 00000000..70cd23c5 --- /dev/null +++ b/cl_dll/input_goldsource.cpp @@ -0,0 +1,1357 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// in_win.c -- windows 95 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +//#include "port.h" + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "keydefs.h" +#include "view.h" +//#include "Exports.h" + +#ifndef _WIN32 +#define USE_SDL2 +#endif + +#ifdef USE_SDL2 +#include +#include +#endif + +#ifdef _WIN32 +#include +#else +typedef unsigned int DWORD; +#endif + +#define MOUSE_BUTTON_COUNT 5 + +// use IN_SetVisibleMouse to set: +int iVisibleMouse = 0; + +extern cl_enginefunc_t gEngfuncs; + +extern int iMouseInUse; + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; + +#ifdef _WIN32 +static double s_flRawInputUpdateTime = 0.0f; +static bool m_bRawInput = false; +static bool m_bMouseThread = false; +bool isMouseRelative = false; +#endif + +#ifdef _WIN32 +#include "progdefs.h" +extern globalvars_t *gpGlobals; +#endif + +Vector dead_viewangles(0, 0, 0); + +void V_StopPitchDrift( void ) +{ + +} + +// mouse variables +cvar_t *m_filter; +cvar_t *sensitivity; + +// Custom mouse acceleration (0 disable, 1 to enable, 2 enable with separate yaw/pitch rescale) +static cvar_t *m_customaccel; +//Formula: mousesensitivity = ( rawmousedelta^m_customaccel_exponent ) * m_customaccel_scale + sensitivity +// If mode is 2, then x and y sensitivity are scaled by m_pitch and m_yaw respectively. +// Custom mouse acceleration value. +static cvar_t *m_customaccel_scale; +//Max mouse move scale factor, 0 for no limit +static cvar_t *m_customaccel_max; +//Mouse move is raised to this power before being scaled by scale factor +static cvar_t *m_customaccel_exponent; + +#ifdef _WIN32 +// if threaded mouse is enabled then the time to sleep between polls +static cvar_t *m_mousethread_sleep; +#endif + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int old_mouse_x, old_mouse_y, mx_accum, my_accum; +float mouse_x, mouse_y; + +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive = 0; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, + AxisForward, + AxisLook, + AxisSide, + AxisTurn +}; + + +DWORD dwAxisMap[ JOY_MAX_AXES ]; +DWORD dwControlMap[ JOY_MAX_AXES ]; +int pdwRawValue[ JOY_MAX_AXES ]; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_numbuttons; + +#ifdef USE_SDL2 +SDL_GameController *s_pJoystick = NULL; +#endif + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; + +int joy_avail, joy_advancedinit, joy_haspov; + +#ifdef _WIN32 +unsigned int s_hMouseThreadId = 0; +HANDLE s_hMouseThread = 0; +HANDLE s_hMouseQuitEvent = 0; +HANDLE s_hMouseThreadActiveLock = 0; +#endif + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + vec3_t viewangles; + + if (!iMouseInUse) + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + viewangles[PITCH] = 0; + gEngfuncs.SetViewAngles( (float *)viewangles ); + } +} + +#ifdef _WIN32 + +LONG mouseThreadActive = 0; +LONG mouseThreadCenterX = 0; +LONG mouseThreadCenterY = 0; +LONG mouseThreadDeltaX = 0; +LONG mouseThreadDeltaY = 0; +LONG mouseThreadSleep = 0; + +bool MouseThread_ActiveLock_Enter( void ) +{ + if(!m_bMouseThread) + return true; + + return WAIT_OBJECT_0 == WaitForSingleObject( s_hMouseThreadActiveLock, INFINITE); +} + +void MouseThread_ActiveLock_Exit( void ) +{ + if(!m_bMouseThread) + return; + + SetEvent( s_hMouseThreadActiveLock ); +} + +unsigned __stdcall MouseThread_Function( void * pArg ) +{ + while ( true ) + { + DWORD sleepVal = (DWORD)InterlockedExchangeAdd(&mouseThreadSleep, 0); + if(0 > sleepVal) sleepVal = 0; + else if(1000 < sleepVal) sleepVal = 1000; + if(WAIT_OBJECT_0 == WaitForSingleObject( s_hMouseQuitEvent, sleepVal)) + { + break; + } + + if( MouseThread_ActiveLock_Enter() ) + { + if ( InterlockedExchangeAdd(&mouseThreadActive, 0) ) + { + POINT mouse_pos; + POINT center_pos; + + center_pos.x = InterlockedExchangeAdd(&mouseThreadCenterX, 0); + center_pos.y = InterlockedExchangeAdd(&mouseThreadCenterY, 0); + GetCursorPos(&mouse_pos); + + mouse_pos.x -= center_pos.x; + mouse_pos.y -= center_pos.y; + + if(mouse_pos.x || mouse_pos.y) SetCursorPos( center_pos.x, center_pos.y ); + + InterlockedExchangeAdd(&mouseThreadDeltaX, mouse_pos.x); + InterlockedExchangeAdd(&mouseThreadDeltaY, mouse_pos.y); + } + + MouseThread_ActiveLock_Exit(); + } + } + + return 0; +} + +/// Updates mouseThreadActive using the global variables mouseactive, iVisibleMouse and m_bRawInput. Should be called after any of these is changed. +/// Has to be interlocked manually by programmer! Use MouseThread_ActiveLock_Enter and MouseThread_ActiveLock_Exit. +void UpdateMouseThreadActive(void) +{ + InterlockedExchange(&mouseThreadActive, mouseactive && !iVisibleMouse && !m_bRawInput); +} + +#endif + +void IN_SetMouseMode(bool enable) +{ + static bool currentMouseMode = false; + + if(enable == currentMouseMode) + return; + + if(enable) + { +#ifdef _WIN32 + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + + m_bRawInput = CVAR_GET_FLOAT( "m_rawinput" ) != 0; + if(m_bRawInput) + { +#ifdef USE_SDL2 + SDL_SetRelativeMouseMode(SDL_TRUE); +#endif + isMouseRelative = true; + } +#else + SDL_SetRelativeMouseMode(SDL_TRUE); +#endif + + currentMouseMode = true; + } + else + { +#ifdef _WIN32 + if(isMouseRelative) + { +#ifdef USE_SDL2 + SDL_SetRelativeMouseMode(SDL_FALSE); +#endif + isMouseRelative = false; + } + + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); +#else + SDL_SetRelativeMouseMode(SDL_FALSE); +#endif + + currentMouseMode = false; + } +} + +void IN_SetVisibleMouse(bool visible) +{ +#ifdef _WIN32 + bool lockEntered = MouseThread_ActiveLock_Enter(); +#endif + + iVisibleMouse = visible; + + IN_SetMouseMode(!visible); + +#ifdef _WIN32 + UpdateMouseThreadActive(); + if(lockEntered) MouseThread_ActiveLock_Exit(); +#endif +} + +void IN_ResetMouse( void ); + +/* +=========== +IN_ActivateMouse +=========== +*/ +extern "C" void DLLEXPORT IN_ActivateMouse (void) +{ + if (mouseinitialized) + { +#ifdef _WIN32 + bool lockEntered = MouseThread_ActiveLock_Enter(); +#endif + + IN_SetMouseMode(true); + + mouseactive = 1; + +#ifdef _WIN32 + UpdateMouseThreadActive(); + if(lockEntered) MouseThread_ActiveLock_Exit(); +#endif + + // now is a good time to reset mouse positon: + IN_ResetMouse(); + } +} + + +/* +=========== +IN_DeactivateMouse +=========== +*/ +extern "C" void DLLEXPORT IN_DeactivateMouse (void) +{ + if (mouseinitialized) + { +#ifdef _WIN32 + bool lockEntered = MouseThread_ActiveLock_Enter(); +#endif + + IN_SetMouseMode(false); + + mouseactive = 0; + +#ifdef _WIN32 + UpdateMouseThreadActive(); + if(lockEntered) MouseThread_ActiveLock_Exit(); +#endif + } +} + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) + return; + + mouseinitialized = 1; +#ifdef _WIN32 + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + newmouseparms[2] = originalmouseparms[2]; + + if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } +#endif + + mouse_buttons = MOUSE_BUTTON_COUNT; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + IN_DeactivateMouse (); + +#ifdef _WIN32 + if ( s_hMouseQuitEvent ) + { + SetEvent( s_hMouseQuitEvent ); + } + + if ( s_hMouseThread ) + { + if(WAIT_OBJECT_0 != WaitForSingleObject( s_hMouseThread, 5000 )) + { + TerminateThread( s_hMouseThread, 0 ); + } + CloseHandle( s_hMouseThread ); + s_hMouseThread = (HANDLE)0; + } + + if ( s_hMouseQuitEvent ) + { + CloseHandle( s_hMouseQuitEvent ); + s_hMouseQuitEvent = (HANDLE)0; + } + + if( s_hMouseThreadActiveLock ) + { + CloseHandle( s_hMouseThreadActiveLock ); + s_hMouseThreadActiveLock = (HANDLE)0; + } +#endif +} + +/* +=========== +IN_GetMousePos + +Ask for mouse position from engine +=========== +*/ +void IN_GetMousePos( int *mx, int *my ) +{ + gEngfuncs.GetMousePosition( mx, my ); +} + +/* +=========== +IN_ResetMouse + +FIXME: Call through to engine? +=========== +*/ +void IN_ResetMouse( void ) +{ + // no work to do in SDL +#ifdef _WIN32 + // reset only if mouse is active and not in visible mode: + if(mouseactive && !iVisibleMouse) + { + if ( !m_bRawInput && gEngfuncs.GetWindowCenterX && gEngfuncs.GetWindowCenterY ) + { + bool lockEntered = MouseThread_ActiveLock_Enter(); + + int centerX = gEngfuncs.GetWindowCenterX(); + int centerY = gEngfuncs.GetWindowCenterY(); + + SetCursorPos ( centerX, centerY ); + InterlockedExchange( &mouseThreadCenterX, centerX ); + InterlockedExchange( &mouseThreadCenterY, centerY ); + InterlockedExchange( &mouseThreadDeltaX, 0 ); + InterlockedExchange( &mouseThreadDeltaY, 0 ); + + if(lockEntered) MouseThread_ActiveLock_Exit(); + } + } +#endif +} + +/* +=========== +IN_MouseEvent +=========== +*/ +extern "C" void DLLEXPORT IN_MouseEvent (int mstate) +{ + int i; + + if ( iMouseInUse || iVisibleMouse ) + return; + + // perform button actions + for (i=0 ; ivalue; + + // Using special accleration values + if ( m_customaccel->value != 0 ) + { + float raw_mouse_movement_distance = sqrt( mx * mx + my * my ); + float acceleration_scale = m_customaccel_scale->value; + float accelerated_sensitivity_max = m_customaccel_max->value; + float accelerated_sensitivity_exponent = m_customaccel_exponent->value; + float accelerated_sensitivity = ( (float)pow( raw_mouse_movement_distance, accelerated_sensitivity_exponent ) * acceleration_scale + mouse_senstivity ); + + if ( accelerated_sensitivity_max > 0.0001f && + accelerated_sensitivity > accelerated_sensitivity_max ) + { + accelerated_sensitivity = accelerated_sensitivity_max; + } + + *x *= accelerated_sensitivity; + *y *= accelerated_sensitivity; + + // Further re-scale by yaw and pitch magnitude if user requests alternate mode 2 + // This means that they will need to up their value for m_customaccel_scale greatly (>40x) since m_pitch/yaw default + // to 0.022 + if ( m_customaccel->value == 2 ) + { + *x *= m_yaw->value; + *y *= m_pitch->value; + } + } + else + { + // Just apply the default + *x *= mouse_senstivity; + *y *= mouse_senstivity; + } +} + +void IN_GetMouseDelta( int *pOutX, int *pOutY) +{ + bool active = mouseactive && !iVisibleMouse; + int mx, my; + + if(active) + { + int deltaX, deltaY; +#ifdef _WIN32 + if ( !m_bRawInput ) + { + if ( m_bMouseThread ) + { + // update mouseThreadSleep: + InterlockedExchange(&mouseThreadSleep, (LONG)m_mousethread_sleep->value); + + bool lockEntered = MouseThread_ActiveLock_Enter(); + + current_pos.x = InterlockedExchange( &mouseThreadDeltaX, 0 ); + current_pos.y = InterlockedExchange( &mouseThreadDeltaY, 0 ); + + if(lockEntered) MouseThread_ActiveLock_Exit(); + } + else + { + GetCursorPos (¤t_pos); + } + } + else +#endif + { +#ifdef USE_SDL2 + SDL_GetRelativeMouseState( &deltaX, &deltaY ); + current_pos.x = deltaX; + current_pos.y = deltaY; +#else + GetCursorPos (¤t_pos); + deltaX = current_pos.x - gEngfuncs.GetWindowCenterX(); + deltaY = current_pos.y - gEngfuncs.GetWindowCenterY(); +#endif + } + +#ifdef _WIN32 + if ( !m_bRawInput ) + { + if ( m_bMouseThread ) + { + mx = current_pos.x; + my = current_pos.y; + } + else + { + mx = current_pos.x - gEngfuncs.GetWindowCenterX() + mx_accum; + my = current_pos.y - gEngfuncs.GetWindowCenterY() + my_accum; + } + } + else +#endif + { + mx = deltaX + mx_accum; + my = deltaY + my_accum; + } + + mx_accum = 0; + my_accum = 0; + + // reset mouse position if required, so there is room to move: +#ifdef _WIN32 + // do not reset if mousethread would do it: + if ( m_bRawInput || !m_bMouseThread ) +#else + if(true) +#endif + IN_ResetMouse(); + +#ifdef _WIN32 + // update m_bRawInput occasionally: + if ( gpGlobals && gpGlobals->time - s_flRawInputUpdateTime > 1.0f ) + { + s_flRawInputUpdateTime = gpGlobals->time; + + bool lockEntered = MouseThread_ActiveLock_Enter(); + + m_bRawInput = CVAR_GET_FLOAT( "m_rawinput" ) != 0; + + if(m_bRawInput && !isMouseRelative) + { +#ifdef USE_SDL2 + SDL_SetRelativeMouseMode(SDL_TRUE); +#endif + isMouseRelative = true; + } + else if(!m_bRawInput && isMouseRelative) + { +#ifdef USE_SDL2 + SDL_SetRelativeMouseMode(SDL_FALSE); +#endif + isMouseRelative = false; + } + + UpdateMouseThreadActive(); + if(lockEntered) MouseThread_ActiveLock_Exit(); + } +#endif + } + else + { + mx = my = 0; + } + + if(pOutX) *pOutX = mx; + if(pOutY) *pOutY = my; +} + +/* +=========== +IN_MouseMove +=========== +*/ +void IN_MouseMove ( float frametime, usercmd_t *cmd) +{ + int mx, my; + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if ( in_mlook.state & 1) + { + V_StopPitchDrift (); + } + + //jjb - this disbles normal mouse control if the user is trying to + // move the camera, or if the mouse cursor is visible or if we're in intermission + if ( !iMouseInUse && !gHUD.m_iIntermission && !iVisibleMouse ) + { + IN_GetMouseDelta( &mx, &my ); + + if (m_filter && m_filter->value) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + // Apply custom mouse scaling/acceleration + IN_ScaleMouse( &mouse_x, &mouse_y ); + + // add mouse X/Y movement to cmd + if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + cmd->sidemove += m_side->value * mouse_x; + else + viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + viewangles[PITCH] += m_pitch->value * mouse_y; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + else + { + if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + { + cmd->upmove -= m_forward->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } + } + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +/* +//#define TRACE_TEST +#if defined( TRACE_TEST ) + { + int mx, my; + void V_Move( int mx, int my ); + IN_GetMousePos( &mx, &my ); + V_Move( mx, my ); + } +#endif +*/ +} + +/* +=========== +IN_Accumulate +=========== +*/ +extern "C" void DLLEXPORT IN_Accumulate (void) +{ + //only accumulate mouse if we are not moving the camera with the mouse + if ( !iMouseInUse && !iVisibleMouse) + { + if (mouseactive) + { +#ifdef _WIN32 + if ( !m_bRawInput ) + { + if ( !m_bMouseThread ) + { + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); + } + } + else +#endif + { +#ifdef USE_SDL2 + int deltaX, deltaY; + SDL_GetRelativeMouseState( &deltaX, &deltaY ); + mx_accum += deltaX; + my_accum += deltaY; +#else + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); +#endif + } + + // force the mouse to the center, so there's room to move +#ifdef _WIN32 + // do not reset if mousethread would do it: + if ( m_bRawInput || !m_bMouseThread ) +#else + if(true) +#endif + IN_ResetMouse(); + + } + } + +} + +/* +=================== +IN_ClearStates +=================== +*/ +extern "C" void DLLEXPORT IN_ClearStates (void) +{ + if ( !mouseactive ) + return; + + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; +} + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + // abort startup if user requests no joystick + if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) + return; + + // assume no joystick + joy_avail = 0; +#ifdef USE_SDL2 + int nJoysticks = SDL_NumJoysticks(); + if ( nJoysticks > 0 ) + { + for ( int i = 0; i < nJoysticks; i++ ) + { + if ( SDL_IsGameController( i ) ) + { + s_pJoystick = SDL_GameControllerOpen( i ); + if ( s_pJoystick ) + { + //save the joystick's number of buttons and POV status + joy_numbuttons = SDL_CONTROLLER_BUTTON_MAX; + joy_haspov = 0; + + // old button and POV states default to no buttons pressed + joy_oldbuttonstate = joy_oldpovstate = 0; + + // mark the joystick as available and advanced initialization not completed + // this is needed as cvars are not available during initialization + gEngfuncs.Con_Printf ("joystick found\n\n", SDL_GameControllerName(s_pJoystick)); + joy_avail = 1; + joy_advancedinit = 0; + break; + } + } + } + } + else + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + } +#else + gEngfuncs.Con_DPrintf ("joystick not found -- implement joystick without SDL2\n\n"); +#endif +} + +int RawValuePointer (int axis) +{ +#ifdef USE_SDL2 + switch (axis) + { + default: + case JOY_AXIS_X: + return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTX ); + case JOY_AXIS_Y: + return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTY ); + case JOY_AXIS_Z: + return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTX ); + case JOY_AXIS_R: + return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTY ); + + } +#else + // TODO: implement joystick without SDL2 + return 0; +#endif +} + +/* +=========== +Joy_AdvancedUpdate_f +=========== +*/ +void Joy_AdvancedUpdate_f (void) +{ + + // called once by IN_ReadJoystick and by user whenever an update is needed + // cvars are now available + int i; + DWORD dwTemp; + + // initialize all the maps + for (i = 0; i < JOY_MAX_AXES; i++) + { + dwAxisMap[i] = AxisNada; + dwControlMap[i] = JOY_ABSOLUTE_AXIS; + pdwRawValue[i] = RawValuePointer(i); + } + + if( joy_advanced->value == 0.0) + { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } + else + { + if ( strcmp ( joy_name->string, "joystick") != 0 ) + { + // notify user of advanced controller + gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + } + + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = (DWORD) joy_advaxisx->value; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisy->value; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisz->value; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisr->value; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisu->value; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisv->value; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } +} + + +/* +=========== +IN_Commands +=========== +*/ +void IN_Commands (void) +{ + int i, key_index; + + if (!joy_avail) + { + return; + } + + DWORD buttonstate, povstate; + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = 0; +#ifdef USE_SDL2 + for ( i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) + { + if ( SDL_GameControllerGetButton( s_pJoystick, (SDL_GameControllerButton)i ) ) + { + buttonstate |= 1<value) + { + return; + } + + // collect the joystick data, if possible + if (IN_ReadJoystick () != 1) + { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + + aspeed = speed * frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) + { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = (float)pdwRawValue[i]; + + if (joy_wwhack2->value != 0.0) + { + if (dwAxisMap[i] == AxisTurn) + { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is factored out) + // then bounds check result to level out excessively high spin rates + fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is 0) + if (m_pitch->value < 0.0) + { + viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if(lookspring->value == 0.0) + { + V_StopPitchDrift(); + } + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold->value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold->value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + } + else + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (in_jlook.state & 1) + { + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if( lookspring->value == 0.0 ) + { + V_StopPitchDrift(); + } + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + gEngfuncs.SetViewAngles( (float *)viewangles ); +} + +/* +=========== +IN_Move +=========== +*/ +void IN_Move ( float frametime, usercmd_t *cmd) +{ + if ( !iMouseInUse && mouseactive ) + { + IN_MouseMove ( frametime, cmd); + } + + IN_JoyMove ( frametime, cmd); +} + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + + m_customaccel = gEngfuncs.pfnRegisterVariable ( "m_customaccel", "0", FCVAR_ARCHIVE ); + m_customaccel_scale = gEngfuncs.pfnRegisterVariable ( "m_customaccel_scale", "0.04", FCVAR_ARCHIVE ); + m_customaccel_max = gEngfuncs.pfnRegisterVariable ( "m_customaccel_max", "0", FCVAR_ARCHIVE ); + m_customaccel_exponent = gEngfuncs.pfnRegisterVariable ( "m_customaccel_exponent", "1", FCVAR_ARCHIVE ); + +#ifdef _WIN32 + m_bRawInput = CVAR_GET_FLOAT( "m_rawinput" ) != 0; + m_bMouseThread = gEngfuncs.CheckParm ("-mousethread", NULL ) != NULL; + m_mousethread_sleep = gEngfuncs.pfnRegisterVariable ( "m_mousethread_sleep", "1", FCVAR_ARCHIVE ); // default to less than 1000 Hz + + m_bMouseThread = m_bMouseThread && NULL != m_mousethread_sleep; + + if (m_bMouseThread) + { + // init mouseThreadSleep: +#if 0 // _beginthreadex is not defined on VS 6? + InterlockedExchange(&mouseThreadSleep, (LONG)m_mousethread_sleep->value); + + s_hMouseQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + s_hMouseThreadActiveLock = CreateEvent( NULL, FALSE, TRUE, NULL ); + if ( s_hMouseQuitEvent && s_hMouseThreadActiveLock) + { + s_hMouseThread = (HANDLE)_beginthreadex( NULL, 0, MouseThread_Function, NULL, 0, &s_hMouseThreadId ); + } + + m_bMouseThread = NULL != s_hMouseThread; +#else + m_bMouseThread = 0; +#endif + + // at this early stage this won't print anything: + // gEngfuncs.Con_DPrintf ("Mouse thread %s.\n", m_bMouseThread ? "initalized" : "failed to initalize"); + } +#endif + + gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); + gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + IN_StartupMouse (); + IN_StartupJoystick (); +} diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp deleted file mode 100644 index 5c8210fa..00000000 --- a/cl_dll/inputw32.cpp +++ /dev/null @@ -1,901 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// in_win.c -- windows 95 mouse and joystick code -// 02/21/97 JCB Added extended DirectInput code to support external controllers. - -#include "hud.h" -#include "cl_util.h" -#include "camera.h" -#include "kbutton.h" -#include "cvardef.h" -#include "usercmd.h" -#include "const.h" -#include "camera.h" -#include "in_defs.h" -#include "../engine/keydefs.h" -//#include "view.h" -#include "windows.h" - -#define MOUSE_BUTTON_COUNT 5 - -// Set this to 1 to show mouse cursor. Experimental -int g_iVisibleMouse = 0; - -extern "C" -{ - void DLLEXPORT IN_ActivateMouse( void ); - void DLLEXPORT IN_DeactivateMouse( void ); - void DLLEXPORT IN_MouseEvent( int mstate ); - void DLLEXPORT IN_Accumulate( void ); - void DLLEXPORT IN_ClearStates( void ); -} - -extern cl_enginefunc_t gEngfuncs; - -extern int iMouseInUse; - -extern kbutton_t in_strafe; -extern kbutton_t in_mlook; -extern kbutton_t in_speed; -extern kbutton_t in_jlook; - -extern cvar_t *m_pitch; -extern cvar_t *m_yaw; -extern cvar_t *m_forward; -extern cvar_t *m_side; - -extern cvar_t *lookstrafe; -extern cvar_t *lookspring; -extern cvar_t *cl_pitchdown; -extern cvar_t *cl_pitchup; -extern cvar_t *cl_yawspeed; -extern cvar_t *cl_sidespeed; -extern cvar_t *cl_forwardspeed; -extern cvar_t *cl_pitchspeed; -extern cvar_t *cl_movespeedkey; - -// mouse variables -cvar_t *m_filter; -cvar_t *sensitivity; - -int mouse_buttons; -int mouse_oldbuttonstate; -POINT current_pos; -int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; - -static int restore_spi; -static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; -static int mouseactive; -int mouseinitialized; -static int mouseparmsvalid; -static int mouseshowtoggle = 1; - -// joystick defines and variables -// where should defines be moved? -#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick -#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball -#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V -#define JOY_AXIS_X 0 -#define JOY_AXIS_Y 1 -#define JOY_AXIS_Z 2 -#define JOY_AXIS_R 3 -#define JOY_AXIS_U 4 -#define JOY_AXIS_V 5 - -enum _ControlList -{ - AxisNada = 0, - AxisForward, - AxisLook, - AxisSide, - AxisTurn -}; - -DWORD dwAxisFlags[JOY_MAX_AXES] = -{ - JOY_RETURNX, - JOY_RETURNY, - JOY_RETURNZ, - JOY_RETURNR, - JOY_RETURNU, - JOY_RETURNV -}; - -DWORD dwAxisMap[JOY_MAX_AXES]; -DWORD dwControlMap[JOY_MAX_AXES]; -PDWORD pdwRawValue[JOY_MAX_AXES]; - -// none of these cvars are saved over a session -// this means that advanced controller configuration needs to be executed -// each time. this avoids any problems with getting back to a default usage -// or when changing from one controller to another. this way at least something -// works. -cvar_t *in_joystick; -cvar_t *joy_name; -cvar_t *joy_advanced; -cvar_t *joy_advaxisx; -cvar_t *joy_advaxisy; -cvar_t *joy_advaxisz; -cvar_t *joy_advaxisr; -cvar_t *joy_advaxisu; -cvar_t *joy_advaxisv; -cvar_t *joy_forwardthreshold; -cvar_t *joy_sidethreshold; -cvar_t *joy_pitchthreshold; -cvar_t *joy_yawthreshold; -cvar_t *joy_forwardsensitivity; -cvar_t *joy_sidesensitivity; -cvar_t *joy_pitchsensitivity; -cvar_t *joy_yawsensitivity; -cvar_t *joy_wwhack1; -cvar_t *joy_wwhack2; - -int joy_avail, joy_advancedinit, joy_haspov; -DWORD joy_oldbuttonstate, joy_oldpovstate; - -int joy_id; -DWORD joy_flags; -DWORD joy_numbuttons; - -static JOYINFOEX ji; - -/* -=========== -Force_CenterView_f -=========== -*/ -void Force_CenterView_f( void ) -{ - vec3_t viewangles; - - if( !iMouseInUse ) - { - gEngfuncs.GetViewAngles( (float *)viewangles ); - viewangles[PITCH] = 0; - gEngfuncs.SetViewAngles( (float *)viewangles ); - } -} - -/* -=========== -IN_ActivateMouse -=========== -*/ -void DLLEXPORT IN_ActivateMouse( void ) -{ - if( mouseinitialized ) - { - if( mouseparmsvalid ) - restore_spi = SystemParametersInfo( SPI_SETMOUSE, 0, newmouseparms, 0 ); - mouseactive = 1; - } -} - -/* -=========== -IN_DeactivateMouse -=========== -*/ -void DLLEXPORT IN_DeactivateMouse( void ) -{ - if( mouseinitialized ) - { - if( restore_spi ) - SystemParametersInfo( SPI_SETMOUSE, 0, originalmouseparms, 0 ); - mouseactive = 0; - } -} - -/* -=========== -IN_StartupMouse -=========== -*/ -void IN_StartupMouse( void ) -{ - if( gEngfuncs.CheckParm( "-nomouse", NULL ) ) - return; - - mouseinitialized = 1; - mouseparmsvalid = SystemParametersInfo( SPI_GETMOUSE, 0, originalmouseparms, 0 ); - - if( mouseparmsvalid ) - { - if( gEngfuncs.CheckParm( "-noforcemspd", NULL ) ) - newmouseparms[2] = originalmouseparms[2]; - - if( gEngfuncs.CheckParm( "-noforcemaccel", NULL ) ) - { - newmouseparms[0] = originalmouseparms[0]; - newmouseparms[1] = originalmouseparms[1]; - } - - if( gEngfuncs.CheckParm( "-noforcemparms", NULL ) ) - { - newmouseparms[0] = originalmouseparms[0]; - newmouseparms[1] = originalmouseparms[1]; - newmouseparms[2] = originalmouseparms[2]; - } - } - - mouse_buttons = MOUSE_BUTTON_COUNT; -} - -/* -=========== -IN_Shutdown -=========== -*/ -void IN_Shutdown( void ) -{ - IN_DeactivateMouse (); -} - -/* -=========== -IN_GetMousePos - -Ask for mouse position from engine -=========== -*/ -void IN_GetMousePos( int *mx, int *my ) -{ - gEngfuncs.GetMousePosition( mx, my ); -} - -/* -=========== -IN_ResetMouse - -FIXME: Call through to engine? -=========== -*/ -void IN_ResetMouse( void ) -{ - SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); -} - -/* -=========== -IN_MouseEvent -=========== -*/ -void DLLEXPORT IN_MouseEvent( int mstate ) -{ - int i; - - if( iMouseInUse || g_iVisibleMouse ) - return; - - // perform button actions - for( i = 0; i < mouse_buttons; i++ ) - { - if( ( mstate & ( 1 << i ) ) && - !( mouse_oldbuttonstate & ( 1 << i ) ) ) - { - gEngfuncs.Key_Event( K_MOUSE1 + i, 1 ); - } - - if( !( mstate & ( 1 << i ) ) && - ( mouse_oldbuttonstate & ( 1 << i ) ) ) - { - gEngfuncs.Key_Event( K_MOUSE1 + i, 0 ); - } - } - - mouse_oldbuttonstate = mstate; -} - -/* -=========== -IN_MouseMove -=========== -*/ -void IN_MouseMove( float frametime, usercmd_t *cmd ) -{ - int mx, my; - vec3_t viewangles; - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - //jjb - this disbles normal mouse control if the user is trying to - // move the camera, or if the mouse cursor is visible or if we're in intermission - if( !iMouseInUse && !g_iVisibleMouse && !gHUD.m_iIntermission ) - { - GetCursorPos( ¤t_pos ); - - mx = current_pos.x - gEngfuncs.GetWindowCenterX() + mx_accum; - my = current_pos.y - gEngfuncs.GetWindowCenterY() + my_accum; - - mx_accum = 0; - my_accum = 0; - - if( m_filter->value ) - { - mouse_x = ( mx + old_mouse_x ) * 0.5; - mouse_y = ( my + old_mouse_y ) * 0.5; - } - else - { - mouse_x = mx; - mouse_y = my; - } - - old_mouse_x = mx; - old_mouse_y = my; - - if( gHUD.GetSensitivity() != 0 ) - { - mouse_x *= gHUD.GetSensitivity(); - mouse_y *= gHUD.GetSensitivity(); - } - else - { - mouse_x *= sensitivity->value; - mouse_y *= sensitivity->value; - } - - // add mouse X/Y movement to cmd - if( ( in_strafe.state & 1 ) || ( lookstrafe->value && ( in_mlook.state & 1 ) ) ) - cmd->sidemove += m_side->value * mouse_x; - else - viewangles[YAW] -= m_yaw->value * mouse_x; - - if( ( in_mlook.state & 1 ) && !( in_strafe.state & 1 ) ) - { - viewangles[PITCH] += m_pitch->value * mouse_y; - if( viewangles[PITCH] > cl_pitchdown->value ) - viewangles[PITCH] = cl_pitchdown->value; - if( viewangles[PITCH] < -cl_pitchup->value ) - viewangles[PITCH] = -cl_pitchup->value; - } - else - { - if( ( in_strafe.state & 1 ) && gEngfuncs.IsNoClipping() ) - { - cmd->upmove -= m_forward->value * mouse_y; - } - else - { - cmd->forwardmove -= m_forward->value * mouse_y; - } - } - - // if the mouse has moved, force it to the center, so there's room to move - if( mx || my ) - { - IN_ResetMouse(); - } - } - - gEngfuncs.SetViewAngles( (float *)viewangles ); - -/* -//#define TRACE_TEST -#if defined( TRACE_TEST ) - { - int mx, my; - void V_Move( int mx, int my ); - IN_GetMousePos( &mx, &my ); - V_Move( mx, my ); - } -#endif -*/ -} - -/* -=========== -IN_Accumulate -=========== -*/ -void DLLEXPORT IN_Accumulate( void ) -{ - //only accumulate mouse if we are not moving the camera with the mouse - if( !iMouseInUse && !g_iVisibleMouse ) - { - if( mouseactive ) - { - GetCursorPos( ¤t_pos ); - - mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); - my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); - - // force the mouse to the center, so there's room to move - IN_ResetMouse(); - } - } -} - -/* -=================== -IN_ClearStates -=================== -*/ -void DLLEXPORT IN_ClearStates( void ) -{ - if( !mouseactive ) - return; - - mx_accum = 0; - my_accum = 0; - mouse_oldbuttonstate = 0; -} - -/* -=============== -IN_StartupJoystick -=============== -*/ -void IN_StartupJoystick( void ) -{ - int numdevs; - JOYCAPS jc; - MMRESULT mmr; - - // assume no joystick - joy_avail = 0; - - // abort startup if user requests no joystick - if( gEngfuncs.CheckParm( "-nojoy", NULL ) ) - return; - - // verify joystick driver is present - if( ( numdevs = joyGetNumDevs() ) == 0 ) - { - gEngfuncs.Con_DPrintf( "joystick not found -- driver not present\n\n" ); - return; - } - - // cycle through the joystick ids for the first valid one - for( joy_id = 0; joy_id < numdevs; joy_id++ ) - { - memset( &ji, 0, sizeof(ji) ); - ji.dwSize = sizeof(ji); - ji.dwFlags = JOY_RETURNCENTERED; - - if( ( mmr = joyGetPosEx( joy_id, &ji ) ) == JOYERR_NOERROR ) - break; - } - - // abort startup if we didn't find a valid joystick - if( mmr != JOYERR_NOERROR ) - { - gEngfuncs.Con_DPrintf( "joystick not found -- no valid joysticks (%x)\n\n", mmr ); - return; - } - - // get the capabilities of the selected joystick - // abort startup if command fails - memset( &jc, 0, sizeof(jc) ); - if( ( mmr = joyGetDevCaps( joy_id, &jc, sizeof(jc) ) ) != JOYERR_NOERROR ) - { - gEngfuncs.Con_DPrintf( "joystick not found -- invalid joystick capabilities (%x)\n\n", mmr ); - return; - } - - // save the joystick's number of buttons and POV status - joy_numbuttons = jc.wNumButtons; - joy_haspov = jc.wCaps & JOYCAPS_HASPOV; - - // old button and POV states default to no buttons pressed - joy_oldbuttonstate = joy_oldpovstate = 0; - - // mark the joystick as available and advanced initialization not completed - // this is needed as cvars are not available during initialization - gEngfuncs.Con_Printf( "joystick found\n\n", mmr ); - joy_avail = 1; - joy_advancedinit = 0; -} - -/* -=========== -RawValuePointer -=========== -*/ -PDWORD RawValuePointer( int axis ) -{ - switch( axis ) - { - case JOY_AXIS_X: - return &ji.dwXpos; - case JOY_AXIS_Y: - return &ji.dwYpos; - case JOY_AXIS_Z: - return &ji.dwZpos; - case JOY_AXIS_R: - return &ji.dwRpos; - case JOY_AXIS_U: - return &ji.dwUpos; - case JOY_AXIS_V: - return &ji.dwVpos; - } - // FIX: need to do some kind of error - return &ji.dwXpos; -} - -/* -=========== -Joy_AdvancedUpdate_f -=========== -*/ -void Joy_AdvancedUpdate_f( void ) -{ - // called once by IN_ReadJoystick and by user whenever an update is needed - // cvars are now available - int i; - DWORD dwTemp; - - // initialize all the maps - for( i = 0; i < JOY_MAX_AXES; i++ ) - { - dwAxisMap[i] = AxisNada; - dwControlMap[i] = JOY_ABSOLUTE_AXIS; - pdwRawValue[i] = RawValuePointer(i); - } - - if( joy_advanced->value == 0.0 ) - { - // default joystick initialization - // 2 axes only with joystick control - dwAxisMap[JOY_AXIS_X] = AxisTurn; - // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; - dwAxisMap[JOY_AXIS_Y] = AxisForward; - // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; - } - else - { - if( strcmp( joy_name->string, "joystick" ) != 0 ) - { - // notify user of advanced controller - gEngfuncs.Con_Printf( "\n%s configured\n\n", joy_name->string ); - } - - // advanced initialization here - // data supplied by user via joy_axisn cvars - dwTemp = (DWORD)joy_advaxisx->value; - dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD)joy_advaxisy->value; - dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD)joy_advaxisz->value; - dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD)joy_advaxisr->value; - dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD)joy_advaxisu->value; - dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; - dwTemp = (DWORD)joy_advaxisv->value; - dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; - dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; - } - - // compute the axes to collect from DirectInput - joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; - for( i = 0; i < JOY_MAX_AXES; i++ ) - { - if( dwAxisMap[i] != AxisNada ) - { - joy_flags |= dwAxisFlags[i]; - } - } -} - -/* -=========== -IN_Commands -=========== -*/ -void IN_Commands( void ) -{ - int i, key_index; - DWORD buttonstate, povstate; - - if( !joy_avail ) - { - return; - } - - // loop through the joystick buttons - // key a joystick event or auxillary event for higher number buttons for each state change - buttonstate = ji.dwButtons; - for( i = 0; i < (int)joy_numbuttons; i++ ) - { - if( ( buttonstate & ( 1 << i ) ) && !( joy_oldbuttonstate & ( 1 << i ) ) ) - { - key_index = ( i < 4 ) ? K_JOY1 : K_AUX1; - gEngfuncs.Key_Event( key_index + i, 1 ); - } - - if( !( buttonstate & ( 1 << i ) ) && ( joy_oldbuttonstate & ( 1 << i ) ) ) - { - key_index = ( i < 4 ) ? K_JOY1 : K_AUX1; - gEngfuncs.Key_Event( key_index + i, 0 ); - } - } - joy_oldbuttonstate = buttonstate; - - if( joy_haspov ) - { - // convert POV information into 4 bits of state information - // this avoids any potential problems related to moving from one - // direction to another without going through the center position - povstate = 0; - if( ji.dwPOV != JOY_POVCENTERED ) - { - if( ji.dwPOV == JOY_POVFORWARD ) - povstate |= 0x01; - if( ji.dwPOV == JOY_POVRIGHT ) - povstate |= 0x02; - if( ji.dwPOV == JOY_POVBACKWARD ) - povstate |= 0x04; - if( ji.dwPOV == JOY_POVLEFT ) - povstate |= 0x08; - } - // determine which bits have changed and key an auxillary event for each change - for( i = 0; i < 4; i++ ) - { - if( ( povstate & ( 1 << i ) ) && !( joy_oldpovstate & ( 1 << i ) ) ) - { - gEngfuncs.Key_Event( K_AUX29 + i, 1 ); - } - - if( !( povstate & ( 1 << i ) ) && ( joy_oldpovstate & ( 1 << i ) ) ) - { - gEngfuncs.Key_Event( K_AUX29 + i, 0 ); - } - } - joy_oldpovstate = povstate; - } -} - -/* -=============== -IN_ReadJoystick -=============== -*/ -int IN_ReadJoystick( void ) -{ - memset( &ji, 0, sizeof(ji) ); - ji.dwSize = sizeof(ji); - ji.dwFlags = joy_flags; - - if( joyGetPosEx( joy_id, &ji ) == JOYERR_NOERROR ) - { - // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver - // rather than having 32768 be the zero point, they have the zero point at 32668 - // go figure -- anyway, now we get the full resolution out of the device - if( joy_wwhack1->value != 0.0 ) - { - ji.dwUpos += 100; - } - return 1; - } - else - { - // read error occurred - // turning off the joystick seems too harsh for 1 read error,\ - // but what should be done? - // Con_Printf( "IN_ReadJoystick: no response\n" ); - // joy_avail = 0; - return 0; - } -} - -/* -=========== -IN_JoyMove -=========== -*/ -void IN_JoyMove( float frametime, usercmd_t *cmd ) -{ - float speed, aspeed; - float fAxisValue, fTemp; - int i; - vec3_t viewangles; - - gEngfuncs.GetViewAngles( (float *)viewangles ); - - // complete initialization if first time in - // this is needed as cvars are not available at initialization time - if( joy_advancedinit != 1 ) - { - Joy_AdvancedUpdate_f(); - joy_advancedinit = 1; - } - - // verify joystick is available and that the user wants to use it - if( !joy_avail || !in_joystick->value ) - { - return; - } - - // collect the joystick data, if possible - if( IN_ReadJoystick () != 1 ) - { - return; - } - - if( in_speed.state & 1 ) - speed = cl_movespeedkey->value; - else - speed = 1; - - aspeed = speed * frametime; - - // loop through the axes - for( i = 0; i < JOY_MAX_AXES; i++ ) - { - // get the floating point zero-centered, potentially-inverted data for the current axis - fAxisValue = (float) *pdwRawValue[i]; - // move centerpoint to zero - fAxisValue -= 32768.0; - - if( joy_wwhack2->value != 0.0 ) - { - if( dwAxisMap[i] == AxisTurn ) - { - // this is a special formula for the Logitech WingMan Warrior - // y=ax^b; where a = 300 and b = 1.3 - // also x values are in increments of 800 (so this is factored out) - // then bounds check result to level out excessively high spin rates - fTemp = 300.0 * pow( abs( fAxisValue ) / 800.0, 1.3 ); - if( fTemp > 14000.0 ) - fTemp = 14000.0; - // restore direction information - fAxisValue = ( fAxisValue > 0.0 ) ? fTemp : -fTemp; - } - } - - // convert range from -32768..32767 to -1..1 - fAxisValue /= 32768.0; - - switch( dwAxisMap[i] ) - { - case AxisForward: - if( ( joy_advanced->value == 0.0 ) && ( in_jlook.state & 1 ) ) - { - // user wants forward control to become look control - if( fabs( fAxisValue ) > joy_pitchthreshold->value ) - { - // if mouse invert is on, invert the joystick pitch value - // only absolute control support here (joy_advanced is 0) - if( m_pitch->value < 0.0 ) - { - viewangles[PITCH] -= ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; - } - else - { - viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; - } - } - } - else - { - // user wants forward control to be forward control - if( fabs( fAxisValue ) > joy_forwardthreshold->value ) - { - cmd->forwardmove += ( fAxisValue * joy_forwardsensitivity->value ) * speed * cl_forwardspeed->value; - } - } - break; - case AxisSide: - if( fabs( fAxisValue ) > joy_sidethreshold->value ) - { - cmd->sidemove += ( fAxisValue * joy_sidesensitivity->value ) * speed * cl_sidespeed->value; - } - break; - case AxisTurn: - if( ( in_strafe.state & 1 ) || ( lookstrafe->value && ( in_jlook.state & 1 ) ) ) - { - // user wants turn control to become side control - if( fabs( fAxisValue ) > joy_sidethreshold->value ) - { - cmd->sidemove -= ( fAxisValue * joy_sidesensitivity->value ) * speed * cl_sidespeed->value; - } - } - else - { - // user wants turn control to be turn control - if( fabs( fAxisValue ) > joy_yawthreshold->value ) - { - if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) - { - viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * aspeed * cl_yawspeed->value; - } - else - { - viewangles[YAW] += ( fAxisValue * joy_yawsensitivity->value ) * speed * 180.0; - } - } - } - break; - case AxisLook: - if( in_jlook.state & 1 ) - { - if( fabs( fAxisValue ) > joy_pitchthreshold->value ) - { - // pitch movement detected and pitch movement desired by user - if( dwControlMap[i] == JOY_ABSOLUTE_AXIS ) - { - viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * aspeed * cl_pitchspeed->value; - } - else - { - viewangles[PITCH] += ( fAxisValue * joy_pitchsensitivity->value ) * speed * 180.0; - } - } - } - break; - default: - break; - } - } - - // bounds check pitch - if( viewangles[PITCH] > cl_pitchdown->value ) - viewangles[PITCH] = cl_pitchdown->value; - if( viewangles[PITCH] < -cl_pitchup->value ) - viewangles[PITCH] = -cl_pitchup->value; - - gEngfuncs.SetViewAngles( (float *)viewangles ); -} - -/* -=========== -IN_Move -=========== -*/ -void IN_Move( float frametime, usercmd_t *cmd ) -{ - if( !iMouseInUse && mouseactive ) - { - IN_MouseMove( frametime, cmd ); - } - - IN_JoyMove( frametime, cmd ); -} - -/* -=========== -IN_Init -=========== -*/ -void IN_Init( void ) -{ - m_filter = gEngfuncs.pfnRegisterVariable( "m_filter","0", FCVAR_ARCHIVE ); - sensitivity = gEngfuncs.pfnRegisterVariable( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. - - in_joystick = gEngfuncs.pfnRegisterVariable( "joystick","0", FCVAR_ARCHIVE ); - joy_name = gEngfuncs.pfnRegisterVariable( "joyname", "joystick", 0 ); - joy_advanced = gEngfuncs.pfnRegisterVariable( "joyadvanced", "0", 0 ); - joy_advaxisx = gEngfuncs.pfnRegisterVariable( "joyadvaxisx", "0", 0 ); - joy_advaxisy = gEngfuncs.pfnRegisterVariable( "joyadvaxisy", "0", 0 ); - joy_advaxisz = gEngfuncs.pfnRegisterVariable( "joyadvaxisz", "0", 0 ); - joy_advaxisr = gEngfuncs.pfnRegisterVariable( "joyadvaxisr", "0", 0 ); - joy_advaxisu = gEngfuncs.pfnRegisterVariable( "joyadvaxisu", "0", 0 ); - joy_advaxisv = gEngfuncs.pfnRegisterVariable( "joyadvaxisv", "0", 0 ); - joy_forwardthreshold = gEngfuncs.pfnRegisterVariable( "joyforwardthreshold", "0.15", 0 ); - joy_sidethreshold = gEngfuncs.pfnRegisterVariable( "joysidethreshold", "0.15", 0 ); - joy_pitchthreshold = gEngfuncs.pfnRegisterVariable( "joypitchthreshold", "0.15", 0 ); - joy_yawthreshold = gEngfuncs.pfnRegisterVariable( "joyyawthreshold", "0.15", 0 ); - joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable( "joyforwardsensitivity", "-1.0", 0 ); - joy_sidesensitivity = gEngfuncs.pfnRegisterVariable( "joysidesensitivity", "-1.0", 0 ); - joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable( "joypitchsensitivity", "1.0", 0 ); - joy_yawsensitivity = gEngfuncs.pfnRegisterVariable( "joyyawsensitivity", "-1.0", 0 ); - joy_wwhack1 = gEngfuncs.pfnRegisterVariable( "joywwhack1", "0.0", 0 ); - joy_wwhack2 = gEngfuncs.pfnRegisterVariable( "joywwhack2", "0.0", 0 ); - - gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); - gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); - - IN_StartupMouse (); - IN_StartupJoystick (); -} From 1d8d1b5d2e7d804e41c844642bb541cc17be4001 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sun, 3 Dec 2017 23:52:35 +0300 Subject: [PATCH 209/227] Use mouse input backend depending on the current engine --- cl_dll/CMakeLists.txt | 11 ++--- cl_dll/cl_dll.h | 3 ++ cl_dll/hud.h | 4 +- cl_dll/input_goldsource.cpp | 43 +++++++++---------- cl_dll/input_mouse.cpp | 82 +++++++++++++++++++++++++++++++++++++ cl_dll/input_mouse.h | 77 ++++++++++++++++++++++++++++++++++ cl_dll/input_xash3d.cpp | 41 +++++++------------ 7 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 cl_dll/input_mouse.cpp create mode 100644 cl_dll/input_mouse.h diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 7bd04f77..776f9bd9 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -27,7 +27,7 @@ set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") if (GOLDSOURCE_SUPPORT) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lSDL2 -Wl,--no-undefined") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -lSDL2 -Wl,--no-undefined") endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") @@ -73,6 +73,9 @@ set (CLDLL_SOURCES hud_update.cpp in_camera.cpp input.cpp + input_goldsource.cpp + input_mouse.cpp + input_xash3d.cpp menu.cpp message.cpp overview.cpp @@ -93,12 +96,6 @@ set (CLDLL_SOURCES scoreboard.cpp MOTD.cpp) -if (GOLDSOURCE_SUPPORT) - set (CLDLL_SOURCES "${CLDLL_SOURCES}" input_goldsource.cpp) -else() - set (CLDLL_SOURCES "${CLDLL_SOURCES}" input_xash3d.cpp) -endif() - include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public) if(USE_VOICEMGR) diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index 24d1874b..0acd6860 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -25,6 +25,8 @@ // - Drawing the HUD graphics every frame // - Handling the custum HUD-update packets // +#ifndef CL_DLL_H +#define CL_DLL_H typedef unsigned char byte; typedef unsigned short word; typedef float vec_t; @@ -48,3 +50,4 @@ typedef int ( *pfnUserMsgHook )( const char *pszName, int iSize, void *pbuf ); extern cl_enginefunc_t gEngfuncs; #include "../engine/mobility_int.h" extern mobile_engfuncs_t *gMobileEngfuncs; +#endif diff --git a/cl_dll/hud.h b/cl_dll/hud.h index ab179bbb..1970753d 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -19,7 +19,8 @@ // // CHud handles the message, calculation, and drawing the HUD // - +#ifndef HUD_H +#define HUD_H #define RGB_YELLOWISH 0x00FFA000 //255,160,0 #define RGB_REDISH 0x00FF1010 //255,160,0 #define RGB_GREENISH 0x0000A000 //0,160,0 @@ -677,3 +678,4 @@ extern int g_iTeamNumber; extern int g_iUser1; extern int g_iUser2; extern int g_iUser3; +#endif diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp index 70cd23c5..5c2b0381 100644 --- a/cl_dll/input_goldsource.cpp +++ b/cl_dll/input_goldsource.cpp @@ -8,20 +8,20 @@ // in_win.c -- windows 95 mouse and joystick code // 02/21/97 JCB Added extended DirectInput code to support external controllers. -//#include "port.h" +#include "input_mouse.h" + +#ifdef SUPPORT_GOLDSOURCE_INPUT #include "hud.h" #include "cl_util.h" #include "camera.h" #include "kbutton.h" #include "cvardef.h" -#include "usercmd.h" #include "const.h" #include "camera.h" #include "in_defs.h" #include "keydefs.h" #include "view.h" -//#include "Exports.h" #ifndef _WIN32 #define USE_SDL2 @@ -79,7 +79,7 @@ bool isMouseRelative = false; extern globalvars_t *gpGlobals; #endif -Vector dead_viewangles(0, 0, 0); +extern Vector dead_viewangles; void V_StopPitchDrift( void ) { @@ -88,7 +88,7 @@ void V_StopPitchDrift( void ) // mouse variables cvar_t *m_filter; -cvar_t *sensitivity; +extern cvar_t *sensitivity; // Custom mouse acceleration (0 disable, 1 to enable, 2 enable with separate yaw/pitch rescale) static cvar_t *m_customaccel; @@ -106,16 +106,11 @@ static cvar_t *m_customaccel_exponent; static cvar_t *m_mousethread_sleep; #endif -int mouse_buttons; -int mouse_oldbuttonstate; -POINT current_pos; -int old_mouse_x, old_mouse_y, mx_accum, my_accum; float mouse_x, mouse_y; static int restore_spi; static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; static int mouseactive = 0; -int mouseinitialized; static int mouseparmsvalid; static int mouseshowtoggle = 1; @@ -158,7 +153,7 @@ SDL_GameController *s_pJoystick = NULL; // each time. this avoids any problems with getting back to a default usage // or when changing from one controller to another. this way at least something // works. -cvar_t *in_joystick; +extern cvar_t *in_joystick; cvar_t *joy_name; cvar_t *joy_advanced; cvar_t *joy_advaxisx; @@ -348,7 +343,7 @@ void IN_ResetMouse( void ); IN_ActivateMouse =========== */ -extern "C" void DLLEXPORT IN_ActivateMouse (void) +void GoldSourceInput::IN_ActivateMouse (void) { if (mouseinitialized) { @@ -376,7 +371,7 @@ extern "C" void DLLEXPORT IN_ActivateMouse (void) IN_DeactivateMouse =========== */ -extern "C" void DLLEXPORT IN_DeactivateMouse (void) +void GoldSourceInput::IN_DeactivateMouse (void) { if (mouseinitialized) { @@ -400,7 +395,7 @@ extern "C" void DLLEXPORT IN_DeactivateMouse (void) IN_StartupMouse =========== */ -void IN_StartupMouse (void) +void GoldSourceInput::IN_StartupMouse (void) { if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) return; @@ -437,7 +432,7 @@ void IN_StartupMouse (void) IN_Shutdown =========== */ -void IN_Shutdown (void) +void GoldSourceInput::IN_Shutdown (void) { IN_DeactivateMouse (); @@ -521,7 +516,7 @@ void IN_ResetMouse( void ) IN_MouseEvent =========== */ -extern "C" void DLLEXPORT IN_MouseEvent (int mstate) +void GoldSourceInput::IN_MouseEvent (int mstate) { int i; @@ -596,7 +591,7 @@ void IN_ScaleMouse( float *x, float *y ) } } -void IN_GetMouseDelta( int *pOutX, int *pOutY) +void GoldSourceInput::IN_GetMouseDelta( int *pOutX, int *pOutY) { bool active = mouseactive && !iVisibleMouse; int mx, my; @@ -715,7 +710,7 @@ void IN_GetMouseDelta( int *pOutX, int *pOutY) IN_MouseMove =========== */ -void IN_MouseMove ( float frametime, usercmd_t *cmd) +void GoldSourceInput::IN_MouseMove ( float frametime, usercmd_t *cmd) { int mx, my; vec3_t viewangles; @@ -797,7 +792,7 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd) IN_Accumulate =========== */ -extern "C" void DLLEXPORT IN_Accumulate (void) +void GoldSourceInput::IN_Accumulate (void) { //only accumulate mouse if we are not moving the camera with the mouse if ( !iMouseInUse && !iVisibleMouse) @@ -850,7 +845,7 @@ extern "C" void DLLEXPORT IN_Accumulate (void) IN_ClearStates =================== */ -extern "C" void DLLEXPORT IN_ClearStates (void) +void GoldSourceInput::IN_ClearStates (void) { if ( !mouseactive ) return; @@ -999,7 +994,7 @@ void Joy_AdvancedUpdate_f (void) IN_Commands =========== */ -void IN_Commands (void) +void GoldSourceInput::IN_Commands (void) { int i, key_index; @@ -1274,7 +1269,7 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) IN_Move =========== */ -void IN_Move ( float frametime, usercmd_t *cmd) +void GoldSourceInput::IN_Move ( float frametime, usercmd_t *cmd) { if ( !iMouseInUse && mouseactive ) { @@ -1289,7 +1284,7 @@ void IN_Move ( float frametime, usercmd_t *cmd) IN_Init =========== */ -void IN_Init (void) +void GoldSourceInput::IN_Init (void) { m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. @@ -1355,3 +1350,5 @@ void IN_Init (void) IN_StartupMouse (); IN_StartupJoystick (); } + +#endif diff --git a/cl_dll/input_mouse.cpp b/cl_dll/input_mouse.cpp new file mode 100644 index 00000000..724824cd --- /dev/null +++ b/cl_dll/input_mouse.cpp @@ -0,0 +1,82 @@ +#include "input_mouse.h" +#include "exportdef.h" +#include "hud.h" + +// shared between backends +Vector dead_viewangles(0, 0, 0); +cvar_t *sensitivity; +cvar_t *in_joystick; + +FWGSInput fwgsInput; + +#ifdef SUPPORT_GOLDSOURCE_INPUT +GoldSourceInput goldSourceInput; +AbstractInput* currentInput = &goldSourceInput; +#else +AbstractInput* currentInput = &fwgsInput; +#endif +extern "C" void DLLEXPORT IN_ClientMoveEvent( float forwardmove, float sidemove ) +{ + currentInput->IN_ClientMoveEvent(forwardmove, sidemove); +} + +extern "C" void DLLEXPORT IN_ClientLookEvent( float relyaw, float relpitch ) +{ + currentInput->IN_ClientLookEvent(relyaw, relpitch); +} + +void IN_Move( float frametime, usercmd_t *cmd ) +{ + currentInput->IN_Move(frametime, cmd); +} + +extern "C" void DLLEXPORT IN_MouseEvent( int mstate ) +{ + currentInput->IN_MouseEvent(mstate); +} + +extern "C" void DLLEXPORT IN_ClearStates( void ) +{ + currentInput->IN_ClearStates(); +} + +extern "C" void DLLEXPORT IN_ActivateMouse( void ) +{ + currentInput->IN_ActivateMouse(); +} + +extern "C" void DLLEXPORT IN_DeactivateMouse( void ) +{ + currentInput->IN_DeactivateMouse(); +} + +extern "C" void DLLEXPORT IN_Accumulate( void ) +{ + currentInput->IN_Accumulate(); +} + +void IN_Commands( void ) +{ + currentInput->IN_Commands(); +} + +void IN_Shutdown( void ) +{ + currentInput->IN_Shutdown(); +} + +void IN_Init( void ) +{ +#ifdef SUPPORT_GOLDSOURCE_INPUT + if (gMobileEngfuncs) { + gEngfuncs.Con_Printf( "FWGS Xash3D input is in use\n" ); + currentInput = &fwgsInput; + } else { + gEngfuncs.Con_Printf( "GoldSource input is in use\n" ); + currentInput = &goldSourceInput; + } +#else + currentInput = &fwgsInput; +#endif + currentInput->IN_Init(); +} diff --git a/cl_dll/input_mouse.h b/cl_dll/input_mouse.h new file mode 100644 index 00000000..6ddf54db --- /dev/null +++ b/cl_dll/input_mouse.h @@ -0,0 +1,77 @@ +#ifndef INPUT_MOUSE_H +#define INPUT_MOUSE_H +#include "cl_dll.h" +#include "usercmd.h" +#include "in_defs.h" + +class AbstractInput +{ +public: + virtual void IN_ClientMoveEvent( float forwardmove, float sidemove ) = 0; + virtual void IN_ClientLookEvent( float relyaw, float relpitch ) = 0; + virtual void IN_Move( float frametime, usercmd_t *cmd ) = 0; + virtual void IN_MouseEvent( int mstate ) = 0; + virtual void IN_ClearStates( void ) = 0; + virtual void IN_ActivateMouse( void ) = 0; + virtual void IN_DeactivateMouse( void ) = 0; + virtual void IN_Accumulate( void ) = 0; + virtual void IN_Commands( void ) = 0; + virtual void IN_Shutdown( void ) = 0; + virtual void IN_Init( void ) = 0; +}; + +class FWGSInput : public AbstractInput +{ +public: + virtual void IN_ClientMoveEvent( float forwardmove, float sidemove ); + virtual void IN_ClientLookEvent( float relyaw, float relpitch ); + virtual void IN_Move( float frametime, usercmd_t *cmd ); + virtual void IN_MouseEvent( int mstate ); + virtual void IN_ClearStates( void ); + virtual void IN_ActivateMouse( void ); + virtual void IN_DeactivateMouse( void ); + virtual void IN_Accumulate( void ); + virtual void IN_Commands( void ); + virtual void IN_Shutdown( void ); + virtual void IN_Init( void ); + +protected: + float ac_forwardmove; + float ac_sidemove; + int ac_movecount; + float rel_yaw; + float rel_pitch; +}; + +// No need for goldsource input support on the platforms that are not supported by GoldSource. +#if defined(GOLDSOURCE_SUPPORT) && (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && (defined(__i386) || defined(_M_IX86)) +#define SUPPORT_GOLDSOURCE_INPUT +class GoldSourceInput : public AbstractInput +{ +public: + virtual void IN_ClientMoveEvent( float forwardmove, float sidemove ) {} + virtual void IN_ClientLookEvent( float relyaw, float relpitch ) {} + virtual void IN_Move( float frametime, usercmd_t *cmd ); + virtual void IN_MouseEvent( int mstate ); + virtual void IN_ClearStates( void ); + virtual void IN_ActivateMouse( void ); + virtual void IN_DeactivateMouse( void ); + virtual void IN_Accumulate( void ); + virtual void IN_Commands( void ); + virtual void IN_Shutdown( void ); + virtual void IN_Init( void ); + +protected: + void IN_GetMouseDelta( int *pOutX, int *pOutY); + void IN_MouseMove ( float frametime, usercmd_t *cmd); + void IN_StartupMouse (void); + + int mouse_buttons; + int mouse_oldbuttonstate; + POINT current_pos; + int old_mouse_x, old_mouse_y, mx_accum, my_accum; + int mouseinitialized; +}; +#endif + +#endif diff --git a/cl_dll/input_xash3d.cpp b/cl_dll/input_xash3d.cpp index 63cdfbeb..2ff572ee 100644 --- a/cl_dll/input_xash3d.cpp +++ b/cl_dll/input_xash3d.cpp @@ -3,14 +3,9 @@ #include "cvardef.h" #include "kbutton.h" #include "keydefs.h" -cvar_t *sensitivity; -cvar_t *in_joystick; -#define PITCH 0 -#define YAW 1 -#define ROLL 2 - -extern "C" void DLLEXPORT IN_ClientMoveEvent( float forwardmove, float sidemove ); -extern "C" void DLLEXPORT IN_ClientLookEvent( float relyaw, float relpitch ); +#include "input_mouse.h" +extern cvar_t *sensitivity; +extern cvar_t *in_joystick; extern kbutton_t in_strafe; extern kbutton_t in_mlook; @@ -37,12 +32,6 @@ extern cvar_t *cl_movespeedkey; cvar_t *cl_laddermode; -float ac_forwardmove; -float ac_sidemove; -int ac_movecount; -float rel_yaw; -float rel_pitch; - #define F 1U<<0 // Forward #define B 1U<<1 // Back #define L 1U<<2 // Left @@ -55,7 +44,7 @@ float rel_pitch; #define IMPULSE_UP 4 int CL_IsDead( void ); -Vector dead_viewangles(0, 0, 0); +extern Vector dead_viewangles; void IN_ToggleButtons( float forwardmove, float sidemove ) { @@ -135,7 +124,7 @@ void IN_ToggleButtons( float forwardmove, float sidemove ) } } -void IN_ClientMoveEvent( float forwardmove, float sidemove ) +void FWGSInput::IN_ClientMoveEvent( float forwardmove, float sidemove ) { //gEngfuncs.Con_Printf("IN_MoveEvent\n"); @@ -144,14 +133,14 @@ void IN_ClientMoveEvent( float forwardmove, float sidemove ) ac_movecount++; } -void IN_ClientLookEvent( float relyaw, float relpitch ) +void FWGSInput::IN_ClientLookEvent( float relyaw, float relpitch ) { rel_yaw += relyaw; rel_pitch += relpitch; } // Rotate camera and add move values to usercmd -void IN_Move( float frametime, usercmd_t *cmd ) +void FWGSInput::IN_Move( float frametime, usercmd_t *cmd ) { Vector viewangles; bool fLadder = false; @@ -235,7 +224,7 @@ void IN_Move( float frametime, usercmd_t *cmd ) ac_movecount = 0; } -extern "C" void DLLEXPORT IN_MouseEvent( int mstate ) +void FWGSInput::IN_MouseEvent( int mstate ) { static int mouse_oldbuttonstate; // perform button actions @@ -257,37 +246,37 @@ extern "C" void DLLEXPORT IN_MouseEvent( int mstate ) // Stubs -extern "C" void DLLEXPORT IN_ClearStates( void ) +void FWGSInput::IN_ClearStates( void ) { //gEngfuncs.Con_Printf( "IN_ClearStates\n" ); } -extern "C" void DLLEXPORT IN_ActivateMouse( void ) +void FWGSInput::IN_ActivateMouse( void ) { //gEngfuncs.Con_Printf( "IN_ActivateMouse\n" ); } -extern "C" void DLLEXPORT IN_DeactivateMouse( void ) +void FWGSInput::IN_DeactivateMouse( void ) { //gEngfuncs.Con_Printf( "IN_DeactivateMouse\n" ); } -extern "C" void DLLEXPORT IN_Accumulate( void ) +void FWGSInput::IN_Accumulate( void ) { //gEngfuncs.Con_Printf( "IN_Accumulate\n" ); } -void IN_Commands( void ) +void FWGSInput::IN_Commands( void ) { //gEngfuncs.Con_Printf( "IN_Commands\n" ); } -void IN_Shutdown( void ) +void FWGSInput::IN_Shutdown( void ) { } // Register cvars and reset data -void IN_Init( void ) +void FWGSInput::IN_Init( void ) { sensitivity = gEngfuncs.pfnRegisterVariable( "sensitivity", "3", FCVAR_ARCHIVE ); in_joystick = gEngfuncs.pfnRegisterVariable( "joystick", "0", FCVAR_ARCHIVE ); From 84e720eadcfa27434ee65335cb87c8e41a63a92f Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Mon, 4 Dec 2017 15:42:45 +0300 Subject: [PATCH 210/227] Add new input files and goldsource support flag to client makefiles --- cl_dll/Android.mk | 7 +++++++ cl_dll/Makefile | 11 ++++++++--- cl_dll/cl_dll.dsp | 14 +++++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index a79b6363..29aee174 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -68,6 +68,8 @@ SRCS+=./hud_spectator.cpp SRCS+=./hud_update.cpp SRCS+=./in_camera.cpp SRCS+=./input.cpp +SRCS+=./input_goldsource.cpp +SRCS+=./input_mouse.cpp #SRCS+=./inputw32.cpp SRCS+=./menu.cpp SRCS+=./message.cpp @@ -100,6 +102,11 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ $(LOCAL_PATH)/../pm_shared LOCAL_CFLAGS += $(DEFINES) $(INCLUDES) +ifeq ($(GOLDSOURCE_SUPPORT),1) + DEFINES += -DGOLDSOURCE_SUPPORT + LOCAL_LDLIBS += -lSDL2 +endif + LOCAL_SRC_FILES := $(SRCS) $(SRCS_C) include $(BUILD_SHARED_LIBRARY) diff --git a/cl_dll/Makefile b/cl_dll/Makefile index 983b61c0..16427f8f 100644 --- a/cl_dll/Makefile +++ b/cl_dll/Makefile @@ -45,7 +45,8 @@ SRCS+=./hud_spectator.cpp SRCS+=./hud_update.cpp SRCS+=./in_camera.cpp SRCS+=./input.cpp -#SRCS+=./inputw32.cpp +SRCS+=./input_mouse.cpp +SRCS+=./input_goldsource.cpp SRCS+=./menu.cpp SRCS+=./message.cpp SRCS+=./overview.cpp @@ -72,9 +73,13 @@ CFLAGS = -m32 OBJS = $(SRCS:.cpp=.o) $(SRCS_C:.c=.o) LIBS=-lm +ifeq ($(GOLDSOURCE_SUPPORT),1) + DEFINES += -DGOLDSOURCE_SUPPORT + LIBS += -lSDL2 +endif ifeq ($(shell uname -s),Linux) - LIBS=$(LIBS) -ldl + LIBS += -ldl endif %.o : %.c @@ -83,7 +88,7 @@ endif %.o : %.cpp $(CXX) $(CFLAGS) $(INCLUDES) $(DEFINES) -fPIC -c $< -o $@ client.so : $(OBJS) - $(CXX) $(OBJS) -o client.so -shared -Wl,--no-undefined -fPIC $(LIBS) + $(CXX) $(CFLAGS) $(OBJS) -o client.so -shared -Wl,--no-undefined -fPIC $(LIBS) clean: $(RM) $(OBJS) diff --git a/cl_dll/cl_dll.dsp b/cl_dll/cl_dll.dsp index 6864326b..e8ae7d15 100644 --- a/cl_dll/cl_dll.dsp +++ b/cl_dll/cl_dll.dsp @@ -300,7 +300,15 @@ SOURCE=.\input.cpp # End Source File # Begin Source File -SOURCE=.\inputw32.cpp +SOURCE=.\input_goldsource.cpp +# End Source File +# Begin Source File + +SOURCE=.\input_mouse.cpp +# End Source File +# Begin Source File + +SOURCE=.\input_xash3d.cpp # End Source File # Begin Source File @@ -513,6 +521,10 @@ SOURCE=.\in_defs.h # End Source File # Begin Source File +SOURCE=.\input_mouse.h +# End Source File +# Begin Source File + SOURCE=..\common\itrackeruser.h # End Source File # Begin Source File From d904505f6a991532fd2eedff4e98b683347f71cd Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 6 Dec 2017 19:19:27 +0300 Subject: [PATCH 211/227] Get vgui back for goldsource fullscreen support --- cl_dll/CMakeLists.txt | 9 ++++-- cl_dll/cdll_int.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 776f9bd9..2ad46949 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -27,7 +27,12 @@ set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") if (GOLDSOURCE_SUPPORT) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -lSDL2 -Wl,--no-undefined") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -L${CMAKE_CURRENT_SOURCE_DIR}/.. -lSDL2 -Wl,--no-undefined") + if (APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -l:vgui.dylib") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -l:vgui.so") + endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") @@ -96,7 +101,7 @@ set (CLDLL_SOURCES scoreboard.cpp MOTD.cpp) -include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public) +include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public ../utils/vgui/include) if(USE_VOICEMGR) #set(CLDLL_SOURCES diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index d71659e9..00496ea8 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -23,6 +23,13 @@ #include "netadr.h" #include "parsemsg.h" +#if defined(GOLDSOURCE_SUPPORT) && (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && (defined(__i386) || defined(_M_IX86)) +#define USE_VGUI_FOR_GOLDSOURCE_SUPPORT +#include "VGUI_Panel.h" +#include "VGUI_BorderLayout.h" +#include "VGUI_App.h" +#endif + extern "C" { #include "pm_shared.h" @@ -177,6 +184,46 @@ int *HUD_GetRect( void ) return extent; } +#ifdef USE_VGUI_FOR_GOLDSOURCE_SUPPORT +class TeamFortressViewport : public vgui::Panel +{ +public: + TeamFortressViewport(int x,int y,int wide,int tall); + void Initialize( void ); + + virtual void paintBackground(); + void *operator new( size_t stAllocateBlock ); +}; + +static TeamFortressViewport* gViewPort = NULL; + +TeamFortressViewport::TeamFortressViewport(int x, int y, int wide, int tall) +{ + gViewPort = this; + Initialize(); +} + +void TeamFortressViewport::Initialize() +{ + vgui::App::getInstance()->setCursorOveride( vgui::App::getInstance()->getScheme()->getCursor(vgui::Scheme::scu_none) ); +} + +void TeamFortressViewport::paintBackground() +{ + int wide, tall; + getParent()->getSize( wide, tall ); + setSize( wide, tall ); + gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +} + +void *TeamFortressViewport::operator new( size_t stAllocateBlock ) +{ + void *mem = ::operator new( stAllocateBlock ); + memset( mem, 0, stAllocateBlock ); + return mem; +} +#endif + /* ========================== HUD_VidInit @@ -190,7 +237,21 @@ so the HUD can reinitialize itself. int DLLEXPORT HUD_VidInit( void ) { gHUD.VidInit(); +#ifdef USE_VGUI_FOR_GOLDSOURCE_SUPPORT + vgui::Panel* root=(vgui::Panel*)gEngfuncs.VGui_GetPanel(); + root->setBgColor(128,128,0,0); + root->setLayout(new vgui::BorderLayout(0)); + if (gViewPort != NULL) + { + gViewPort->Initialize(); + } + else + { + gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); + gViewPort->setParent(root); + } +#endif return 1; } @@ -270,7 +331,10 @@ Called by engine every frame that client .dll is loaded */ void DLLEXPORT HUD_Frame( double time ) -{ gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +{ +#ifndef USE_VGUI_FOR_GOLDSOURCE_SUPPORT + gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +#endif } /* From 51bf51a840649165078226661ef790c0ed3971e4 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 6 Dec 2017 20:38:14 +0300 Subject: [PATCH 212/227] Provide vgui stub to avoid dependency of client of vgui lib --- cl_dll/CMakeLists.txt | 7 +- cl_dll/cdll_int.cpp | 37 ++-- utils/false_vgui/include/VGUI.h | 108 ++++++++++ utils/false_vgui/include/VGUI_App.h | 130 ++++++++++++ utils/false_vgui/include/VGUI_Bitmap.h | 37 ++++ utils/false_vgui/include/VGUI_Color.h | 44 +++++ utils/false_vgui/include/VGUI_Cursor.h | 57 ++++++ utils/false_vgui/include/VGUI_Dar.h | 194 ++++++++++++++++++ utils/false_vgui/include/VGUI_Image.h | 62 ++++++ utils/false_vgui/include/VGUI_KeyCode.h | 126 ++++++++++++ utils/false_vgui/include/VGUI_MouseCode.h | 24 +++ utils/false_vgui/include/VGUI_Panel.h | 229 ++++++++++++++++++++++ utils/false_vgui/include/VGUI_Scheme.h | 82 ++++++++ 13 files changed, 1114 insertions(+), 23 deletions(-) create mode 100644 utils/false_vgui/include/VGUI.h create mode 100644 utils/false_vgui/include/VGUI_App.h create mode 100644 utils/false_vgui/include/VGUI_Bitmap.h create mode 100644 utils/false_vgui/include/VGUI_Color.h create mode 100644 utils/false_vgui/include/VGUI_Cursor.h create mode 100644 utils/false_vgui/include/VGUI_Dar.h create mode 100644 utils/false_vgui/include/VGUI_Image.h create mode 100644 utils/false_vgui/include/VGUI_KeyCode.h create mode 100644 utils/false_vgui/include/VGUI_MouseCode.h create mode 100644 utils/false_vgui/include/VGUI_Panel.h create mode 100644 utils/false_vgui/include/VGUI_Scheme.h diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 2ad46949..e52a0d95 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -28,11 +28,6 @@ set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") if (GOLDSOURCE_SUPPORT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -L${CMAKE_CURRENT_SOURCE_DIR}/.. -lSDL2 -Wl,--no-undefined") - if (APPLE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -l:vgui.dylib") - else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -l:vgui.so") - endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") @@ -101,7 +96,7 @@ set (CLDLL_SOURCES scoreboard.cpp MOTD.cpp) -include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public ../utils/vgui/include) +include_directories (. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public ../utils/false_vgui/include) if(USE_VOICEMGR) #set(CLDLL_SOURCES diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 00496ea8..1901d9d2 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -26,7 +26,6 @@ #if defined(GOLDSOURCE_SUPPORT) && (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && (defined(__i386) || defined(_M_IX86)) #define USE_VGUI_FOR_GOLDSOURCE_SUPPORT #include "VGUI_Panel.h" -#include "VGUI_BorderLayout.h" #include "VGUI_App.h" #endif @@ -197,7 +196,7 @@ public: static TeamFortressViewport* gViewPort = NULL; -TeamFortressViewport::TeamFortressViewport(int x, int y, int wide, int tall) +TeamFortressViewport::TeamFortressViewport(int x, int y, int wide, int tall) : Panel(x, y, wide, tall) { gViewPort = this; Initialize(); @@ -205,14 +204,14 @@ TeamFortressViewport::TeamFortressViewport(int x, int y, int wide, int tall) void TeamFortressViewport::Initialize() { - vgui::App::getInstance()->setCursorOveride( vgui::App::getInstance()->getScheme()->getCursor(vgui::Scheme::scu_none) ); + //vgui::App::getInstance()->setCursorOveride( vgui::App::getInstance()->getScheme()->getCursor(vgui::Scheme::scu_none) ); } void TeamFortressViewport::paintBackground() { - int wide, tall; - getParent()->getSize( wide, tall ); - setSize( wide, tall ); +// int wide, tall; +// getParent()->getSize( wide, tall ); +// setSize( wide, tall ); gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); } @@ -239,17 +238,18 @@ int DLLEXPORT HUD_VidInit( void ) gHUD.VidInit(); #ifdef USE_VGUI_FOR_GOLDSOURCE_SUPPORT vgui::Panel* root=(vgui::Panel*)gEngfuncs.VGui_GetPanel(); - root->setBgColor(128,128,0,0); - root->setLayout(new vgui::BorderLayout(0)); + if (root) { + root->setBgColor(128,128,0,0); - if (gViewPort != NULL) - { - gViewPort->Initialize(); - } - else - { - gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); - gViewPort->setParent(root); + if (gViewPort != NULL) + { + gViewPort->Initialize(); + } + else + { + gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); + gViewPort->setParent(root); + } } #endif return 1; @@ -332,7 +332,10 @@ Called by engine every frame that client .dll is loaded void DLLEXPORT HUD_Frame( double time ) { -#ifndef USE_VGUI_FOR_GOLDSOURCE_SUPPORT +#ifdef USE_VGUI_FOR_GOLDSOURCE_SUPPORT + if (!gViewPort) + gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); +#else gEngfuncs.VGui_ViewportPaintBackground(HUD_GetRect()); #endif } diff --git a/utils/false_vgui/include/VGUI.h b/utils/false_vgui/include/VGUI.h new file mode 100644 index 00000000..0dff607a --- /dev/null +++ b/utils/false_vgui/include/VGUI.h @@ -0,0 +1,108 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_H +#define VGUI_H + +//If you are going to add stuff to the vgui core... +// +//Keep it simple. +// +//Never put code in a header. +// +//The name of the class is the name of the the file +// +//Each class gets its own .cpp file for its definition and a .h for its header. Helper +//classes can be used but only within the .cpp and not referenceable from anywhere else. +// +//Don't add unneeded files. Keep the API clean. +// +//No platform specific code in vgui\lib-src\vgui dir. Code in vgui\lib-src\vgui should +//only include from vgui\include or standard C includes. ie, if I see windows.h included +//anywhere but vgui\lib-src\win32 I will hunt you down and kill you. Don't give me any crap +//that mfc is platform inspecific. +// +//Always use <> and not "" for includes +// +//Use minimum dependencies in headers. Don't include another header if you can get away +//with forward declaring (which is usually the case) +// +//No macros in headers. They are tools of satan. This also means no use of DEFINEs, use enum +// +//Minimize global functions +// +//No global variables. +// +//Panel is getting pretty plump, try and avoid adding junk to it if you can + +//TODO: Look and Feel support +// add Panel::setPaintProxy, if _paintProxy exists, it calls _paintProxy->paint +// instead of Panel::paint. Components should implement their painting in a seperate +// plugin class. Perhaps to encourage this, Panel::paint should just go away completely +// The other option is to have Panel have the interface Paintable +// class Paintable +// { +// public: +// virtual void paint()=0; +// }; +// Then a component can implement its paint in the class itself and then call +// setPaintProxy(this). If this is the case _paintProxy->paint should always be called +// and never Panel::paint from within paintTraverse +//TODO: Figure out the 'Valve' Look and Feel and implement that instead of a the Java one +//TODO: Determine ownership policy for Borders, Layouts, etc.. +//TODO: tooltips support +//TODO: ComboKey (hot key support) +//TODO: add Background.cpp, remove paintBackground from all components +// Panel implements setBackground, Panel::paintBackground calls _background->paintBackground +// similiar to the way Border works. +//TODO: Builtin components should never overide paintBackground, only paint +//TODO: All protected members should be converted to private +//TODO: All member variables should be moved to the top of the class prototype +//TODO: All private methods should be prepended with private +//TODO: Use of word internal in method names is not consistent and confusing +//TODO: Cleanup so bullshit publics are properly named, maybe even figure out +// a naming convention for them +//TODO: Breakup InputSignal into logical pieces +//TODO: Button is in a state of disarray, it should have ButtonModel support +//TODO: get rid of all the stupid strdup laziness, convert to vgui_strdup +//TODO: actually figure out policy on String and implement it consistently +//TODO: implement createLayoutInfo for other Layouts than need it +//TODO: BorderLayout should have option for a null LayoutInfo defaulting to center +//TODO: SurfaceBase should go away, put it in Surface +//TODO: ActionSignals and other Signals should just set a flag when they fire. +// then App can come along later and fire all the signals +//TODO: Change all method naming to starting with a capital letter. + +#ifdef _WIN32 +# define VGUIAPI __declspec( dllexport ) +#else +# define VGUIAPI __attribute__ ((visibility("default"))) +#include // size_t define +#endif + +#define null 0L + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +namespace vgui +{ + +VGUIAPI void vgui_setMalloc(void *(*malloc)(size_t size) ); +VGUIAPI void vgui_setFree(void (*free)(void* memblock)); +VGUIAPI void vgui_strcpy(char* dst,int dstLen,const char* src); +VGUIAPI char* vgui_strdup(const char* src); +VGUIAPI int vgui_printf(const char* format,...); +VGUIAPI int vgui_dprintf(const char* format,...); +VGUIAPI int vgui_dprintf2(const char* format,...); + +} + +#endif + diff --git a/utils/false_vgui/include/VGUI_App.h b/utils/false_vgui/include/VGUI_App.h new file mode 100644 index 00000000..6e70f909 --- /dev/null +++ b/utils/false_vgui/include/VGUI_App.h @@ -0,0 +1,130 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_APP_H +#define VGUI_APP_H + +#include +#include +#include +#include +#include + +namespace vgui +{ + +class Panel; +class TickSignal; +class Scheme; +class TickSignal; +class SurfaceBase; + +class VGUIAPI App +{ +public: + App() {} + App(bool externalMain) {} +public: + static App* getInstance() {return 0;} + //TODO: the public and public bullshit are all messed up, need to organize + //TODO: actually all of the access needs to be properly thought out while you are at it +public: + virtual void start() {} + virtual void stop() {} + virtual void externalTick() {} + virtual bool wasMousePressed(MouseCode code,Panel* panel) {return false;} + virtual bool wasMouseDoublePressed(MouseCode code,Panel* panel) {return false;} + virtual bool isMouseDown(MouseCode code,Panel* panel) {return false;} + virtual bool wasMouseReleased(MouseCode code,Panel* panel) {return false;} + virtual bool wasKeyPressed(KeyCode code,Panel* panel) {return false;} + virtual bool isKeyDown(KeyCode code,Panel* panel) {return false;} + virtual bool wasKeyTyped(KeyCode code,Panel* panel) {return false;} + virtual bool wasKeyReleased(KeyCode code,Panel* panel) {return false;} + virtual void addTickSignal(TickSignal* s) {} + virtual void setCursorPos(int x,int y) {} + virtual void getCursorPos(int& x,int& y) {} + virtual void setMouseCapture(Panel* panel) {} + virtual void setMouseArena(int x0,int y0,int x1,int y1,bool enabled) {} + virtual void setMouseArena(Panel* panel) {} + virtual void requestFocus(Panel* panel) {} + virtual Panel* getFocus() {return 0;} + virtual void repaintAll() {} + virtual void setScheme(Scheme* scheme) {} + virtual Scheme* getScheme() {return 0;} + virtual void enableBuildMode() {} + virtual long getTimeMillis() {return 0;} + virtual char getKeyCodeChar(KeyCode code,bool shifted) {return '\0';} + virtual void getKeyCodeText(KeyCode code,char* buf,int buflen) {} + virtual int getClipboardTextCount() {return 0;} + virtual void setClipboardText(const char* text,int textLen) {} + virtual int getClipboardText(int offset,char* buf,int bufLen) {return 0;} + virtual void reset() {} + virtual void internalSetMouseArena(int x0,int y0,int x1,int y1,bool enabled) {} + virtual bool setRegistryString(const char* key,const char* value) {return false;} + virtual bool getRegistryString(const char* key,char* value,int valueLen) {return false;} + virtual bool setRegistryInteger(const char* key,int value) {return false;} + virtual bool getRegistryInteger(const char* key,int& value) {return false;} + virtual void setCursorOveride(Cursor* cursor) {} + virtual Cursor* getCursorOveride() {return 0;} + virtual void setMinimumTickMillisInterval(int interval) {} +public: //bullshit public stuff + virtual void main(int argc,char* argv[])=0; + virtual void run() {} + virtual void internalCursorMoved(int x,int y,SurfaceBase* surfaceBase) {} //expects input in surface space + virtual void internalMousePressed(MouseCode code,SurfaceBase* surfaceBase) {} + virtual void internalMouseDoublePressed(MouseCode code,SurfaceBase* surfaceBase) {} + virtual void internalMouseReleased(MouseCode code,SurfaceBase* surfaceBase) {} + virtual void internalMouseWheeled(int delta,SurfaceBase* surfaceBase) {} + virtual void internalKeyPressed(KeyCode code,SurfaceBase* surfaceBase) {} + virtual void internalKeyTyped(KeyCode code,SurfaceBase* surfaceBase) {} + virtual void internalKeyReleased(KeyCode code,SurfaceBase* surfaceBase) {} +private: + virtual void init() {} + virtual void updateMouseFocus(int x,int y,SurfaceBase* surfaceBase) {} + virtual void setMouseFocus(Panel* newMouseFocus) {} +protected: + virtual void surfaceBaseCreated(SurfaceBase* surfaceBase) {} + virtual void surfaceBaseDeleted(SurfaceBase* surfaceBase) {} + virtual void platTick() {} + virtual void internalTick() {} +protected: + static App* _instance; +protected: + bool _running; + bool _externalMain; + Dar _surfaceBaseDar; + Panel* _keyFocus; + Panel* _oldMouseFocus; + Panel* _mouseFocus; + Panel* _mouseCapture; + Panel* _wantedKeyFocus; + bool _mousePressed[MOUSE_LAST]; + bool _mouseDoublePressed[MOUSE_LAST]; + bool _mouseDown[MOUSE_LAST]; + bool _mouseReleased[MOUSE_LAST]; + bool _keyPressed[KEY_LAST]; + bool _keyTyped[KEY_LAST]; + bool _keyDown[KEY_LAST]; + bool _keyReleased[KEY_LAST]; + Dar _tickSignalDar; + Scheme* _scheme; + bool _buildMode; + bool _wantedBuildMode; + Panel* _mouseArenaPanel; + Cursor* _cursor[Cursor::dc_last]; + Cursor* _cursorOveride; +private: + long _nextTickMillis; + long _minimumTickMillisInterval; + friend class SurfaceBase; +}; +} + +#endif + + + diff --git a/utils/false_vgui/include/VGUI_Bitmap.h b/utils/false_vgui/include/VGUI_Bitmap.h new file mode 100644 index 00000000..a2cc7a45 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Bitmap.h @@ -0,0 +1,37 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_BITMAP_H +#define VGUI_BITMAP_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI Bitmap : public Image +{ +private: + int _id; + bool _uploaded; +public: + Bitmap() {} +protected: + virtual void setSize(int wide,int tall) {} + virtual void setRGBA(int x,int y,uchar r,uchar g,uchar b,uchar a) {} +public: + virtual void paint(Panel* panel) {} +protected: + uchar* _rgba; +}; + +} + +#endif diff --git a/utils/false_vgui/include/VGUI_Color.h b/utils/false_vgui/include/VGUI_Color.h new file mode 100644 index 00000000..f3fec5c6 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Color.h @@ -0,0 +1,44 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_COLOR_H +#define VGUI_COLOR_H + +#include +#include + +//TODO: rename getColor(r,g,b,a) to getRGBA(r,g,b,a) +//TODO: rename setColor(r,g,b,a) to setRGBA(r,g,b,a) +//TODO: rename getColor(sc) to getSchemeColor(sc) +//TODO: rename setColor(sc) to setSchemeColor(sc) + +namespace vgui +{ + +class VGUIAPI Color +{ +private: + uchar _color[4]; + Scheme::SchemeColor _schemeColor; +public: + Color() {} + Color(int r,int g,int b,int a) {} + Color(Scheme::SchemeColor sc) {} +private: + virtual void init() {} +public: + virtual void setColor(int r,int g,int b,int a) {} + virtual void setColor(Scheme::SchemeColor sc) {} + virtual void getColor(int& r,int& g,int& b,int& a) {} + virtual void getColor(Scheme::SchemeColor& sc) {} + virtual int operator[](int index) {return 0;} +}; + +} + + +#endif diff --git a/utils/false_vgui/include/VGUI_Cursor.h b/utils/false_vgui/include/VGUI_Cursor.h new file mode 100644 index 00000000..8419e2dd --- /dev/null +++ b/utils/false_vgui/include/VGUI_Cursor.h @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_CURSOR_H +#define VGUI_CURSOR_H + +#include + +namespace vgui +{ + +class Bitmap; + +class VGUIAPI Cursor +{ +public: + enum DefaultCursor + { + dc_user, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_crosshair, + dc_up, + dc_sizenwse, + dc_sizenesw, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_last + }; +private: + int _hotspot[2]; + Bitmap* _bitmap; + DefaultCursor _dc; +public: + Cursor(DefaultCursor dc) {} + Cursor(Bitmap* bitmap,int hotspotX,int hotspotY) {} +public: + virtual void getHotspot(int& x,int& y) {} +private: + virtual void privateInit(Bitmap* bitmap,int hotspotX,int hotspotY) {} +public: + virtual Bitmap* getBitmap() {return 0;} + virtual DefaultCursor getDefaultCursor() {return dc_none;} +}; + +} + +#endif diff --git a/utils/false_vgui/include/VGUI_Dar.h b/utils/false_vgui/include/VGUI_Dar.h new file mode 100644 index 00000000..6f8eb513 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Dar.h @@ -0,0 +1,194 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_DAR_H +#define VGUI_DAR_H + +#include +#include +#include + + + +namespace vgui +{ + +//Simple lightweight dynamic array implementation +template class VGUIAPI Dar +{ +public: + Dar() + { + _count=0; + _capacity=0; + _data=null; + ensureCapacity(4); + } + Dar(int initialCapacity) + { + _count=0; + _capacity=0; + _data=null; + ensureCapacity(initialCapacity); + } +public: + void ensureCapacity(int wantedCapacity) + { + if(wantedCapacity<=_capacity){return;} + + //double capacity until it is >= wantedCapacity + //this could be done with math, but iterative is just so much more fun + int newCapacity=_capacity; + if(newCapacity==0){newCapacity=1;} + while(newCapacity_capacity)) + { + return; + } + _count=count; + } + int getCount() + { + return _count; + } + void addElement(ELEMTYPE elem) + { + ensureCapacity(_count+1); + _data[_count]=elem; + _count++; + } + bool hasElement(ELEMTYPE elem) + { + for(int i=0;i<_count;i++) + { + if(_data[i]==elem) + { + return true; + } + } + return false; + } + void putElement(ELEMTYPE elem) + { + if(hasElement(elem)) + { + return; + } + addElement(elem); + } + void insertElementAt(ELEMTYPE elem,int index) + { + if((index<0)||(index>_count)) + { + return; + } + if((index==_count)||(_count==0)) + { + addElement(elem); + } + else + { + addElement(elem); //just to make sure it is big enough + for(int i=_count-1;i>index;i--) + { + _data[i]=_data[i-1]; + } + _data[index]=elem; + } + } + void setElementAt(ELEMTYPE elem,int index) + { + if((index<0)||(index>=_count)) + { + return; + } + _data[index]=elem; + } + void removeElementAt(int index) + { + if((index<0)||(index>=_count)) + { + return; + } + + //slide everything to the right of index, left one. + for(int i=index;i<(_count-1);i++) + { + _data[i]=_data[i+1]; + } + _count--; + } + void removeElement(ELEMTYPE elem) + { + for(int i=0;i<_count;i++) + { + if(_data[i]==elem) + { + removeElementAt(i); + break; + } + } + } + void removeAll() + { + _count=0; + } + ELEMTYPE operator[](int index) + { + if((index<0)||(index>=_count)) + { + return null; + } + return _data[index]; + } +protected: + int _count; + int _capacity; + ELEMTYPE* _data; +}; + +#ifdef _WIN32 +//forward referencing all the template types used so they get exported +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar*>; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +#endif + +} + + +#endif \ No newline at end of file diff --git a/utils/false_vgui/include/VGUI_Image.h b/utils/false_vgui/include/VGUI_Image.h new file mode 100644 index 00000000..ff83f047 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Image.h @@ -0,0 +1,62 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_IMAGE_H +#define VGUI_IMAGE_H + +#include +#include +#include + +//TODO:: needs concept of insets + +namespace vgui +{ + +class Panel; + +class VGUIAPI Image +{ +friend class Panel; +private: + int _pos[2]; + int _size[2]; + Panel* _panel; + Color _color; +public: + Image(); +public: + virtual void setPos(int x,int y) {} + virtual void getPos(int& x,int& y) {} + virtual void getSize(int& wide,int& tall) {} + virtual void setColor(Color color) {} + virtual void getColor(Color& color) {} +protected: + virtual void setSize(int wide,int tall) {} + virtual void drawSetColor(Scheme::SchemeColor sc) {} + virtual void drawSetColor(int r,int g,int b,int a) {} + virtual void drawFilledRect(int x0,int y0,int x1,int y1) {} + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1) {} + virtual void drawSetTextFont(Scheme::SchemeFont sf) {} + virtual void drawSetTextFont(Font* font) {} + virtual void drawSetTextColor(Scheme::SchemeColor sc) {} + virtual void drawSetTextColor(int r,int g,int b,int a) {} + virtual void drawSetTextPos(int x,int y) {} + virtual void drawPrintText(const char* str,int strlen) {} + virtual void drawPrintText(int x,int y,const char* str,int strlen) {} + virtual void drawPrintChar(char ch) {} + virtual void drawPrintChar(int x,int y,char ch) {} + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall) {} + virtual void drawSetTexture(int id) {} + virtual void drawTexturedRect(int x0,int y0,int x1,int y1) {} + virtual void paint(Panel* panel) {} +public: + virtual void doPaint(Panel* panel) {} +}; +} + +#endif diff --git a/utils/false_vgui/include/VGUI_KeyCode.h b/utils/false_vgui/include/VGUI_KeyCode.h new file mode 100644 index 00000000..b6aea363 --- /dev/null +++ b/utils/false_vgui/include/VGUI_KeyCode.h @@ -0,0 +1,126 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_KEYCODE_H +#define VGUI_KEYCODE_H + +#include + +namespace vgui +{ +enum VGUIAPI KeyCode +{ + KEY_0=0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_PAD_0, + KEY_PAD_1, + KEY_PAD_2, + KEY_PAD_3, + KEY_PAD_4, + KEY_PAD_5, + KEY_PAD_6, + KEY_PAD_7, + KEY_PAD_8, + KEY_PAD_9, + KEY_PAD_DIVIDE, + KEY_PAD_MULTIPLY, + KEY_PAD_MINUS, + KEY_PAD_PLUS, + KEY_PAD_ENTER, + KEY_PAD_DECIMAL, + KEY_LBRACKET, + KEY_RBRACKET, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACKQUOTE, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_BACKSLASH, + KEY_MINUS, + KEY_EQUAL, + KEY_ENTER, + KEY_SPACE, + KEY_BACKSPACE, + KEY_TAB, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_ESCAPE, + KEY_SCROLLLOCK, + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGEUP, + KEY_PAGEDOWN, + KEY_BREAK, + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LALT, + KEY_RALT, + KEY_LCONTROL, + KEY_RCONTROL, + KEY_LWIN, + KEY_RWIN, + KEY_APP, + KEY_UP, + KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_LAST +}; +} + + +#endif + diff --git a/utils/false_vgui/include/VGUI_MouseCode.h b/utils/false_vgui/include/VGUI_MouseCode.h new file mode 100644 index 00000000..2de259db --- /dev/null +++ b/utils/false_vgui/include/VGUI_MouseCode.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_MOUSECODE_H +#define VGUI_MOUSECODE_H + +#include + +namespace vgui +{ +enum VGUIAPI MouseCode +{ + MOUSE_LEFT=0, + MOUSE_RIGHT, + MOUSE_MIDDLE, + MOUSE_LAST +}; +} + +#endif diff --git a/utils/false_vgui/include/VGUI_Panel.h b/utils/false_vgui/include/VGUI_Panel.h new file mode 100644 index 00000000..bec7ac25 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Panel.h @@ -0,0 +1,229 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_PANEL_H +#define VGUI_PANEL_H + + +/* + +TODO: + +Maybe have the border know who they are added to. +A border can only be added to 1 thing, and will be +removed from the other. That way they can actually +be memory managed. Also do Layout's this way too. + +TODO: + outlinedRect should have a thickness arg + +*/ + + +#include +#include +#include +#include +#include +#include +#include +//#include + +namespace vgui +{ + +enum KeyCode; +enum MouseCode; +class SurfaceBase; +class FocusChangeSignal; +class InputSignal; +class Cursor; +class Layout; +class FocusNavGroup; +class Border; +class Font; +class BuildGroup; +class App; +class LayoutInfo; +class RepaintSignal; + +class VGUIAPI Panel +{ +public: + Panel() {} + Panel(int x,int y,int wide,int tall) {setPos(x, y); setSize(wide, tall);} +private: + void init(int x,int y,int wide,int tall) {} +public: + virtual void setPos(int x,int y) {_pos[0] = x; _pos[1] = y;} + virtual void getPos(int& x,int& y) {x = _pos[0]; y = _pos[1];} + virtual void setSize(int wide,int tall) {_size[0] = wide, _size[1] = tall;} + virtual void getSize(int& wide,int& tall) {wide = _size[0], tall = _size[1];} + virtual void setBounds(int x,int y,int wide,int tall) {} + virtual void getBounds(int& x,int& y,int& wide,int& tall) {} + virtual int getWide() {return _size[0];} + virtual int getTall() {return _size[1];} + virtual Panel* getParent() {return _parent;} + virtual void setVisible(bool state) {_visible = state;} + virtual bool isVisible() {return _visible;} + virtual bool isVisibleUp() {return false;} + virtual void repaint() {} + virtual void repaintAll() {} + virtual void getAbsExtents(int& x0,int& y0,int& x1,int& y1) {} + virtual void getClipRect(int& x0,int& y0,int& x1,int& y1) {} + virtual void setParent(Panel* newParent) {_parent = newParent; newParent->addChild(this);} + virtual void addChild(Panel* child) {} + virtual void insertChildAt(Panel* child,int index) {} + virtual void removeChild(Panel* child) {} + virtual bool wasMousePressed(MouseCode code) {return false;} + virtual bool wasMouseDoublePressed(MouseCode code) {return false;} + virtual bool isMouseDown(MouseCode code) {return false;} + virtual bool wasMouseReleased(MouseCode code) {return false;} + virtual bool wasKeyPressed(KeyCode code) {return false;} + virtual bool isKeyDown(KeyCode code) {return false;} + virtual bool wasKeyTyped(KeyCode code) {return false;} + virtual bool wasKeyReleased(KeyCode code) {return false;} + virtual void addInputSignal(InputSignal* s) {} + virtual void removeInputSignal(InputSignal* s) {} + virtual void addRepaintSignal(RepaintSignal* s) {} + virtual void removeRepaintSignal(RepaintSignal* s) {} + virtual bool isWithin(int x,int y) {return false;} //in screen space + virtual Panel* isWithinTraverse(int x,int y) {return 0;} + virtual void localToScreen(int& x,int& y) {} + virtual void screenToLocal(int& x,int& y) {} + virtual void setCursor(Cursor* cursor) {} + virtual void setCursor(Scheme::SchemeCursor scu) {} + virtual Cursor* getCursor() {return 0;} + virtual void setMinimumSize(int wide,int tall) {} + virtual void getMinimumSize(int& wide,int& tall) {} + virtual void requestFocus() {} + virtual bool hasFocus() {return false;} + virtual int getChildCount() {return 0;} + virtual Panel* getChild(int index) {return 0;} + virtual void setLayout(Layout* layout) {} + virtual void invalidateLayout(bool layoutNow) {} + virtual void setFocusNavGroup(FocusNavGroup* focusNavGroup) {} + virtual void requestFocusPrev() {} + virtual void requestFocusNext() {} + virtual void addFocusChangeSignal(FocusChangeSignal* s) {} + virtual bool isAutoFocusNavEnabled() {return false;} + virtual void setAutoFocusNavEnabled(bool state) {} + virtual void setBorder(Border* border) {} + virtual void setPaintBorderEnabled(bool state) {} + virtual void setPaintBackgroundEnabled(bool state) {} + virtual void setPaintEnabled(bool state) {} + virtual void getInset(int& left,int& top,int& right,int& bottom) {} + virtual void getPaintSize(int& wide,int& tall) {} + virtual void setPreferredSize(int wide,int tall) {} + virtual void getPreferredSize(int& wide,int& tall) {} + virtual SurfaceBase* getSurfaceBase() {return 0;} + virtual bool isEnabled() {return _enabled = false;} + virtual void setEnabled(bool state) {_enabled = true;} + virtual void setBuildGroup(BuildGroup* buildGroup,const char* panelPersistanceName) {} + virtual bool isBuildGroupEnabled() {return false;} + virtual void removeAllChildren() {} + virtual void repaintParent() {} + virtual Panel* createPropertyPanel() {return 0;} + virtual void getPersistanceText(char* buf,int bufLen) {} + virtual void applyPersistanceText(const char* buf) {} + virtual void setFgColor(Scheme::SchemeColor sc) {} + virtual void setBgColor(Scheme::SchemeColor sc) {} + virtual void setFgColor(int r,int g,int b,int a) {} + virtual void setBgColor(int r,int g,int b,int a) {} + virtual void getFgColor(int& r,int& g,int& b,int& a) {} + virtual void getBgColor(int& r,int& g,int& b,int& a) {} + virtual void setBgColor(Color color) {} + virtual void setFgColor(Color color) {} + virtual void getBgColor(Color& color) {} + virtual void getFgColor(Color& color) {} + virtual void setAsMouseCapture(bool state) {} + virtual void setAsMouseArena(bool state) {} + virtual App* getApp() {return 0;} + virtual void getVirtualSize(int& wide,int& tall) {} + virtual void setLayoutInfo(LayoutInfo* layoutInfo) {} + virtual LayoutInfo* getLayoutInfo() {return 0;} + virtual bool isCursorNone() {return false;} +public: //bullshit public + virtual void solveTraverse() {} + virtual void paintTraverse() {} + virtual void setSurfaceBaseTraverse(SurfaceBase* surfaceBase) {} +protected: + virtual void performLayout() {} + virtual void internalPerformLayout() {} + virtual void drawSetColor(Scheme::SchemeColor sc) {} + virtual void drawSetColor(int r,int g,int b,int a) {} + virtual void drawFilledRect(int x0,int y0,int x1,int y1) {} + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1) {} + virtual void drawSetTextFont(Scheme::SchemeFont sf) {} + virtual void drawSetTextFont(Font* font) {} + virtual void drawSetTextColor(Scheme::SchemeColor sc) {} + virtual void drawSetTextColor(int r,int g,int b,int a) {} + virtual void drawSetTextPos(int x,int y) {} + virtual void drawPrintText(const char* str,int strlen) {} + virtual void drawPrintText(int x,int y,const char* str,int strlen) {} + virtual void drawPrintChar(char ch) {} + virtual void drawPrintChar(int x,int y,char ch) {} + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall) {} + virtual void drawSetTexture(int id) {} + virtual void drawTexturedRect(int x0,int y0,int x1,int y1) {} + virtual void solve() {} + virtual void paintTraverse(bool repaint) {if(repaint) paintBackground();} + virtual void paintBackground() {} + virtual void paint() {} + virtual void paintBuildOverlay() {} + virtual void internalCursorMoved(int x,int y) {} + virtual void internalCursorEntered() {} + virtual void internalCursorExited() {} + virtual void internalMousePressed(MouseCode code) {} + virtual void internalMouseDoublePressed(MouseCode code) {} + virtual void internalMouseReleased(MouseCode code) {} + virtual void internalMouseWheeled(int delta) {} + virtual void internalKeyPressed(KeyCode code) {} + virtual void internalKeyTyped(KeyCode code) {} + virtual void internalKeyReleased(KeyCode code) {} + virtual void internalKeyFocusTicked() {} + virtual void internalFocusChanged(bool lost) {} + virtual void internalSetCursor() {} +protected: + int _pos[2]; + int _size[2]; + int _loc[2]; + int _minimumSize[2]; + int _preferredSize[2]; + Dar _childDar; + Panel* _parent; + SurfaceBase* _surfaceBase; + Dar _inputSignalDar; + Dar _repaintSignalDar; + int _clipRect[4]; + Cursor* _cursor; + Scheme::SchemeCursor _schemeCursor; + bool _visible; + Layout* _layout; + bool _needsLayout; + FocusNavGroup* _focusNavGroup; + Dar _focusChangeSignalDar; + bool _autoFocusNavEnabled; + Border* _border; +private: + bool _needsRepaint; + bool _enabled; + BuildGroup* _buildGroup; + Color _fgColor; + Color _bgColor; + LayoutInfo* _layoutInfo; + bool _paintBorderEnabled; + bool _paintBackgroundEnabled; + bool _paintEnabled; +friend class Panel; +friend class App; +friend class SurfaceBase; +friend class Image; +}; +} + +#endif diff --git a/utils/false_vgui/include/VGUI_Scheme.h b/utils/false_vgui/include/VGUI_Scheme.h new file mode 100644 index 00000000..e32d7976 --- /dev/null +++ b/utils/false_vgui/include/VGUI_Scheme.h @@ -0,0 +1,82 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SCHEME_H +#define VGUI_SCHEME_H + +#include + + +namespace vgui +{ + +class Font; +class Cursor; + +class VGUIAPI Scheme +{ +public: + enum SchemeColor + { + sc_user=0, + sc_black, + sc_white, + sc_primary1, + sc_primary2, + sc_primary3, + sc_secondary1, + sc_secondary2, + sc_secondary3, + sc_last + }; + enum SchemeFont + { + sf_user=0, + sf_primary1, + sf_primary2, + sf_primary3, + sf_secondary1, + sf_last + }; + enum SchemeCursor + { + scu_user=0, + scu_none, + scu_arrow, + scu_ibeam, + scu_hourglass, + scu_crosshair, + scu_up, + scu_sizenwse, + scu_sizenesw, + scu_sizewe, + scu_sizens, + scu_sizeall, + scu_no, + scu_hand, + scu_last + }; +public: + Scheme() {} +public: + virtual void setColor(SchemeColor sc,int r,int g,int b,int a) {} + virtual void getColor(SchemeColor sc,int& r,int& g,int& b,int& a) {} + virtual void setFont(SchemeFont sf,Font* font) {} + virtual Font* getFont(SchemeFont sf) {return 0;} + virtual void setCursor(SchemeCursor sc,Cursor* cursor) {} + virtual Cursor* getCursor(SchemeCursor sc) {return 0;} +protected: + int _color[sc_last][4]; + Font* _font[sf_last]; + Cursor* _cursor[scu_last]; + friend class Panel; + friend class Canvas; +}; + +} + +#endif From 33de8458d64353b2c4657a6c6648b4e1bc85cf86 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 6 Dec 2017 22:18:34 +0300 Subject: [PATCH 213/227] Some cleanup. Add false_vgui include path to makefiles --- cl_dll/Android.mk | 5 ++- cl_dll/CMakeLists.txt | 2 +- cl_dll/Makefile | 2 +- cl_dll/cdll_int.cpp | 3 ++ cl_dll/cl_dll.dsp | 4 +- utils/false_vgui/include/VGUI.h | 13 ------ utils/false_vgui/include/VGUI_Bitmap.h | 37 --------------- utils/false_vgui/include/VGUI_Image.h | 62 -------------------------- 8 files changed, 10 insertions(+), 118 deletions(-) delete mode 100644 utils/false_vgui/include/VGUI_Bitmap.h delete mode 100644 utils/false_vgui/include/VGUI_Image.h diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 29aee174..452eb48b 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -91,7 +91,7 @@ SRCS+=./view.cpp SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp -INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls +INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -I../utils/false_vgui/include DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ @@ -99,7 +99,8 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ $(LOCAL_PATH)/../engine \ $(LOCAL_PATH)/../game_shared \ $(LOCAL_PATH)/../dlls \ - $(LOCAL_PATH)/../pm_shared + $(LOCAL_PATH)/../pm_shared \ + $(LOCAL_PATH)/../utils/false_vgui/include LOCAL_CFLAGS += $(DEFINES) $(INCLUDES) ifeq ($(GOLDSOURCE_SUPPORT),1) diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index e52a0d95..e5a3aa0a 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -27,7 +27,7 @@ set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") if (GOLDSOURCE_SUPPORT) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -L${CMAKE_CURRENT_SOURCE_DIR}/.. -lSDL2 -Wl,--no-undefined") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -lSDL2") endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") diff --git a/cl_dll/Makefile b/cl_dll/Makefile index 16427f8f..f624473e 100644 --- a/cl_dll/Makefile +++ b/cl_dll/Makefile @@ -67,7 +67,7 @@ SRCS+=./view.cpp SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp -INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls +INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -I../utils/false_vgui/include DEFINES = -Wno-write-strings -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL CFLAGS = -m32 OBJS = $(SRCS:.cpp=.o) $(SRCS_C:.c=.o) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 1901d9d2..7427ef80 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -239,6 +239,7 @@ int DLLEXPORT HUD_VidInit( void ) #ifdef USE_VGUI_FOR_GOLDSOURCE_SUPPORT vgui::Panel* root=(vgui::Panel*)gEngfuncs.VGui_GetPanel(); if (root) { + gEngfuncs.Con_Printf( "Root VGUI panel exists\n" ); root->setBgColor(128,128,0,0); if (gViewPort != NULL) @@ -250,6 +251,8 @@ int DLLEXPORT HUD_VidInit( void ) gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); gViewPort->setParent(root); } + } else { + gEngfuncs.Con_Printf( "Root VGUI panel does not exist\n" ); } #endif return 1; diff --git a/cl_dll/cl_dll.dsp b/cl_dll/cl_dll.dsp index e8ae7d15..17beb9ae 100644 --- a/cl_dll/cl_dll.dsp +++ b/cl_dll/cl_dll.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\utils\false_vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /YX /FD /c # SUBTRACT CPP /Z # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # 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 /GR /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\vgui\include" /I "..\game_shared" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /FR /YX /FD /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GR /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\false_vgui\include" /I "..\game_shared" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "CLIENT_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" diff --git a/utils/false_vgui/include/VGUI.h b/utils/false_vgui/include/VGUI.h index 0dff607a..c33e0589 100644 --- a/utils/false_vgui/include/VGUI.h +++ b/utils/false_vgui/include/VGUI.h @@ -91,18 +91,5 @@ typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; -namespace vgui -{ - -VGUIAPI void vgui_setMalloc(void *(*malloc)(size_t size) ); -VGUIAPI void vgui_setFree(void (*free)(void* memblock)); -VGUIAPI void vgui_strcpy(char* dst,int dstLen,const char* src); -VGUIAPI char* vgui_strdup(const char* src); -VGUIAPI int vgui_printf(const char* format,...); -VGUIAPI int vgui_dprintf(const char* format,...); -VGUIAPI int vgui_dprintf2(const char* format,...); - -} - #endif diff --git a/utils/false_vgui/include/VGUI_Bitmap.h b/utils/false_vgui/include/VGUI_Bitmap.h deleted file mode 100644 index a2cc7a45..00000000 --- a/utils/false_vgui/include/VGUI_Bitmap.h +++ /dev/null @@ -1,37 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_BITMAP_H -#define VGUI_BITMAP_H - -#include -#include - -namespace vgui -{ - -class Panel; - -class VGUIAPI Bitmap : public Image -{ -private: - int _id; - bool _uploaded; -public: - Bitmap() {} -protected: - virtual void setSize(int wide,int tall) {} - virtual void setRGBA(int x,int y,uchar r,uchar g,uchar b,uchar a) {} -public: - virtual void paint(Panel* panel) {} -protected: - uchar* _rgba; -}; - -} - -#endif diff --git a/utils/false_vgui/include/VGUI_Image.h b/utils/false_vgui/include/VGUI_Image.h deleted file mode 100644 index ff83f047..00000000 --- a/utils/false_vgui/include/VGUI_Image.h +++ /dev/null @@ -1,62 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#ifndef VGUI_IMAGE_H -#define VGUI_IMAGE_H - -#include -#include -#include - -//TODO:: needs concept of insets - -namespace vgui -{ - -class Panel; - -class VGUIAPI Image -{ -friend class Panel; -private: - int _pos[2]; - int _size[2]; - Panel* _panel; - Color _color; -public: - Image(); -public: - virtual void setPos(int x,int y) {} - virtual void getPos(int& x,int& y) {} - virtual void getSize(int& wide,int& tall) {} - virtual void setColor(Color color) {} - virtual void getColor(Color& color) {} -protected: - virtual void setSize(int wide,int tall) {} - virtual void drawSetColor(Scheme::SchemeColor sc) {} - virtual void drawSetColor(int r,int g,int b,int a) {} - virtual void drawFilledRect(int x0,int y0,int x1,int y1) {} - virtual void drawOutlinedRect(int x0,int y0,int x1,int y1) {} - virtual void drawSetTextFont(Scheme::SchemeFont sf) {} - virtual void drawSetTextFont(Font* font) {} - virtual void drawSetTextColor(Scheme::SchemeColor sc) {} - virtual void drawSetTextColor(int r,int g,int b,int a) {} - virtual void drawSetTextPos(int x,int y) {} - virtual void drawPrintText(const char* str,int strlen) {} - virtual void drawPrintText(int x,int y,const char* str,int strlen) {} - virtual void drawPrintChar(char ch) {} - virtual void drawPrintChar(int x,int y,char ch) {} - virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall) {} - virtual void drawSetTexture(int id) {} - virtual void drawTexturedRect(int x0,int y0,int x1,int y1) {} - virtual void paint(Panel* panel) {} -public: - virtual void doPaint(Panel* panel) {} -}; -} - -#endif From ca590f24208f7cf37889f833286822e33f4a1b5f Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Thu, 7 Dec 2017 00:31:27 +0300 Subject: [PATCH 214/227] Use old API to draw scoreboard and motd lines in goldsource --- cl_dll/cdll_int.cpp | 5 +++++ cl_dll/cl_util.h | 6 +++++- cl_dll/hud_redraw.cpp | 48 ++++++++++++++++++++++++------------------ cl_dll/input_mouse.cpp | 3 ++- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index d71659e9..80b45e31 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -305,3 +305,8 @@ void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs ) return; gMobileEngfuncs = gpMobileEngfuncs; } + +bool isXashFWGS() +{ + return gMobileEngfuncs != NULL; +} diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 1996543d..23f12230 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -15,7 +15,8 @@ // // cl_util.h // - +#ifndef CL_UTIL_H +#define CL_UTIL_H #include "exportdef.h" #include "cvardef.h" @@ -179,3 +180,6 @@ inline void UnpackRGB( int &r, int &g, int &b, unsigned long ulRGB )\ } HSPRITE LoadSprite( const char *pszName ); + +bool isXashFWGS(); +#endif diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 829fd4b2..06b25a33 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -235,29 +235,35 @@ int CHud::DrawHudString( int xpos, int ypos, int iMaxX, const char *szIt, int r, int DrawUtfString( int xpos, int ypos, int iMaxX, const char *szIt, int r, int g, int b ) { - // xash3d: reset unicode state - gEngfuncs.pfnVGUI2DrawCharacterAdditive( 0, 0, 0, 0, 0, 0, 0 ); - - // draw the string until we hit the null character or a newline character - for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + if (isXashFWGS()) { - int w = gHUD.m_scrinfo.charWidths['M']; - if( xpos + w > iMaxX ) - return xpos; - if( ( *szIt == '^' ) && ( *( szIt + 1 ) >= '0') && ( *( szIt + 1 ) <= '7') ) - { - szIt++; - r = colors[*szIt - '0'][0]; - g = colors[*szIt - '0'][1]; - b = colors[*szIt - '0'][2]; - if( !*(++szIt) ) - return xpos; - } - int c = (unsigned int)(unsigned char)*szIt; - xpos += gEngfuncs.pfnVGUI2DrawCharacterAdditive( xpos, ypos, c, r, g, b, 0 ); - } + // xash3d: reset unicode state + gEngfuncs.pfnVGUI2DrawCharacterAdditive( 0, 0, 0, 0, 0, 0, 0 ); - return xpos; + // draw the string until we hit the null character or a newline character + for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int w = gHUD.m_scrinfo.charWidths['M']; + if( xpos + w > iMaxX ) + return xpos; + if( ( *szIt == '^' ) && ( *( szIt + 1 ) >= '0') && ( *( szIt + 1 ) <= '7') ) + { + szIt++; + r = colors[*szIt - '0'][0]; + g = colors[*szIt - '0'][1]; + b = colors[*szIt - '0'][2]; + if( !*(++szIt) ) + return xpos; + } + int c = (unsigned int)(unsigned char)*szIt; + xpos += gEngfuncs.pfnVGUI2DrawCharacterAdditive( xpos, ypos, c, r, g, b, 0 ); + } + return xpos; + } + else + { + return gHUD.DrawHudString(xpos, ypos, iMaxX, szIt, r, g, b); + } } int CHud::DrawHudStringLen( const char *szIt ) diff --git a/cl_dll/input_mouse.cpp b/cl_dll/input_mouse.cpp index 724824cd..8d57091b 100644 --- a/cl_dll/input_mouse.cpp +++ b/cl_dll/input_mouse.cpp @@ -1,6 +1,7 @@ #include "input_mouse.h" #include "exportdef.h" #include "hud.h" +#include "cl_util.h" // shared between backends Vector dead_viewangles(0, 0, 0); @@ -68,7 +69,7 @@ void IN_Shutdown( void ) void IN_Init( void ) { #ifdef SUPPORT_GOLDSOURCE_INPUT - if (gMobileEngfuncs) { + if (isXashFWGS()) { gEngfuncs.Con_Printf( "FWGS Xash3D input is in use\n" ); currentInput = &fwgsInput; } else { From 1759e8c956e1d4cbd42e9a6d17c1d4208b5b8f1a Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Thu, 7 Dec 2017 01:25:59 +0300 Subject: [PATCH 215/227] Dynamic sdl2 loading from client --- cl_dll/CMakeLists.txt | 5 ++- cl_dll/input_goldsource.cpp | 73 ++++++++++++++++++++++++++++--------- cl_dll/input_mouse.h | 1 + 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index e5a3aa0a..e3ac075a 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -27,7 +27,10 @@ set (CLDLL_LIBRARY client) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w") if (GOLDSOURCE_SUPPORT) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT -lSDL2") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ldl") + endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp index 5c2b0381..7c0e6183 100644 --- a/cl_dll/input_goldsource.cpp +++ b/cl_dll/input_goldsource.cpp @@ -28,8 +28,18 @@ #endif #ifdef USE_SDL2 +#include #include #include +int (*pfnSDL_SetRelativeMouseMode)(SDL_bool); +Uint32 (*pfnSDL_GetRelativeMouseState)(int* x, int* y); +int (*pfnSDL_NumJoysticks)(void); +SDL_bool (*pfnSDL_IsGameController)(int); +SDL_GameController* (*pfnSDL_GameControllerOpen)(int); +Sint16 (*pfnSDL_GameControllerGetAxis)(SDL_GameController*, SDL_GameControllerAxis); +Uint8 (*pfnSDL_GameControllerGetButton)(SDL_GameController*, SDL_GameControllerButton); +void (*pfnSDL_JoystickUpdate)(void); +const char* (*pfnSDL_GameControllerName)(SDL_GameController*); #endif #ifdef _WIN32 @@ -289,12 +299,12 @@ void IN_SetMouseMode(bool enable) if(m_bRawInput) { #ifdef USE_SDL2 - SDL_SetRelativeMouseMode(SDL_TRUE); + pfnSDL_SetRelativeMouseMode(SDL_TRUE); #endif isMouseRelative = true; } #else - SDL_SetRelativeMouseMode(SDL_TRUE); + pfnSDL_SetRelativeMouseMode(SDL_TRUE); #endif currentMouseMode = true; @@ -305,7 +315,7 @@ void IN_SetMouseMode(bool enable) if(isMouseRelative) { #ifdef USE_SDL2 - SDL_SetRelativeMouseMode(SDL_FALSE); + pfnSDL_SetRelativeMouseMode(SDL_FALSE); #endif isMouseRelative = false; } @@ -313,7 +323,7 @@ void IN_SetMouseMode(bool enable) if (restore_spi) SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); #else - SDL_SetRelativeMouseMode(SDL_FALSE); + pfnSDL_SetRelativeMouseMode(SDL_FALSE); #endif currentMouseMode = false; @@ -464,6 +474,11 @@ void GoldSourceInput::IN_Shutdown (void) s_hMouseThreadActiveLock = (HANDLE)0; } #endif + +#ifdef USE_SDL2 + dlclose(sdl2Lib); + sdl2Lib = NULL; +#endif } /* @@ -623,7 +638,7 @@ void GoldSourceInput::IN_GetMouseDelta( int *pOutX, int *pOutY) #endif { #ifdef USE_SDL2 - SDL_GetRelativeMouseState( &deltaX, &deltaY ); + pfnSDL_GetRelativeMouseState( &deltaX, &deltaY ); current_pos.x = deltaX; current_pos.y = deltaY; #else @@ -679,14 +694,14 @@ void GoldSourceInput::IN_GetMouseDelta( int *pOutX, int *pOutY) if(m_bRawInput && !isMouseRelative) { #ifdef USE_SDL2 - SDL_SetRelativeMouseMode(SDL_TRUE); + pfnSDL_SetRelativeMouseMode(SDL_TRUE); #endif isMouseRelative = true; } else if(!m_bRawInput && isMouseRelative) { #ifdef USE_SDL2 - SDL_SetRelativeMouseMode(SDL_FALSE); + pfnSDL_SetRelativeMouseMode(SDL_FALSE); #endif isMouseRelative = false; } @@ -815,7 +830,7 @@ void GoldSourceInput::IN_Accumulate (void) { #ifdef USE_SDL2 int deltaX, deltaY; - SDL_GetRelativeMouseState( &deltaX, &deltaY ); + pfnSDL_GetRelativeMouseState( &deltaX, &deltaY ); mx_accum += deltaX; my_accum += deltaY; #else @@ -869,14 +884,14 @@ void IN_StartupJoystick (void) // assume no joystick joy_avail = 0; #ifdef USE_SDL2 - int nJoysticks = SDL_NumJoysticks(); + int nJoysticks = pfnSDL_NumJoysticks(); if ( nJoysticks > 0 ) { for ( int i = 0; i < nJoysticks; i++ ) { - if ( SDL_IsGameController( i ) ) + if ( pfnSDL_IsGameController( i ) ) { - s_pJoystick = SDL_GameControllerOpen( i ); + s_pJoystick = pfnSDL_GameControllerOpen( i ); if ( s_pJoystick ) { //save the joystick's number of buttons and POV status @@ -888,7 +903,7 @@ void IN_StartupJoystick (void) // mark the joystick as available and advanced initialization not completed // this is needed as cvars are not available during initialization - gEngfuncs.Con_Printf ("joystick found\n\n", SDL_GameControllerName(s_pJoystick)); + gEngfuncs.Con_Printf ("joystick found\n\n", pfnSDL_GameControllerName(s_pJoystick)); joy_avail = 1; joy_advancedinit = 0; break; @@ -912,13 +927,13 @@ int RawValuePointer (int axis) { default: case JOY_AXIS_X: - return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTX ); + return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTX ); case JOY_AXIS_Y: - return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTY ); + return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTY ); case JOY_AXIS_Z: - return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTX ); + return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTX ); case JOY_AXIS_R: - return SDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTY ); + return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTY ); } #else @@ -1011,7 +1026,7 @@ void GoldSourceInput::IN_Commands (void) #ifdef USE_SDL2 for ( i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { - if ( SDL_GameControllerGetButton( s_pJoystick, (SDL_GameControllerButton)i ) ) + if ( pfnSDL_GameControllerGetButton( s_pJoystick, (SDL_GameControllerButton)i ) ) { buttonstate |= 1< Date: Thu, 7 Dec 2017 04:43:25 +0300 Subject: [PATCH 216/227] Provide safe wrappers around sdl function pointers. Use dylib extension on macOS --- cl_dll/input_goldsource.cpp | 137 ++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 29 deletions(-) diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp index 7c0e6183..e367a37e 100644 --- a/cl_dll/input_goldsource.cpp +++ b/cl_dll/input_goldsource.cpp @@ -40,6 +40,63 @@ Sint16 (*pfnSDL_GameControllerGetAxis)(SDL_GameController*, SDL_GameControllerAx Uint8 (*pfnSDL_GameControllerGetButton)(SDL_GameController*, SDL_GameControllerButton); void (*pfnSDL_JoystickUpdate)(void); const char* (*pfnSDL_GameControllerName)(SDL_GameController*); + +int safe_pfnSDL_SetRelativeMouseMode(SDL_bool mode) +{ + if (pfnSDL_SetRelativeMouseMode) + return pfnSDL_SetRelativeMouseMode(mode); + return -1; +} +Uint32 safe_pfnSDL_GetRelativeMouseState(int* x, int* y) +{ + if (pfnSDL_GetRelativeMouseState) + return pfnSDL_GetRelativeMouseState(x, y); + return 0; +} +int safe_pfnSDL_NumJoysticks() +{ + if (pfnSDL_NumJoysticks) + return pfnSDL_NumJoysticks(); + return -1; +} +SDL_bool safe_pfnSDL_IsGameController(int joystick_index) +{ + if (pfnSDL_IsGameController) + return pfnSDL_IsGameController(joystick_index); + return SDL_FALSE; +} +SDL_GameController* safe_pfnSDL_GameControllerOpen(int joystick_index) +{ + if (pfnSDL_GameControllerOpen) + return pfnSDL_GameControllerOpen(joystick_index); + return NULL; +} +Sint16 safe_pfnSDL_GameControllerGetAxis(SDL_GameController* gamecontroller, SDL_GameControllerAxis axis) +{ + if (pfnSDL_GameControllerGetAxis) + return pfnSDL_GameControllerGetAxis(gamecontroller, axis); + return 0; +} +Uint8 safe_pfnSDL_GameControllerGetButton(SDL_GameController* gamecontroller, SDL_GameControllerButton button) +{ + if (pfnSDL_GameControllerGetButton) + return pfnSDL_GameControllerGetButton(gamecontroller, button); + return 0; +} +void safe_pfnSDL_JoystickUpdate() +{ + if (pfnSDL_JoystickUpdate) + pfnSDL_JoystickUpdate(); +} +const char* safe_pfnSDL_GameControllerName(SDL_GameController* gamecontroller) +{ + if (pfnSDL_GameControllerName) + return pfnSDL_GameControllerName(gamecontroller); + return NULL; +} +static void** const sdlFunctionPointers[] = {(void**)&pfnSDL_SetRelativeMouseMode, (void**)&pfnSDL_GetRelativeMouseState, (void**)&pfnSDL_NumJoysticks, + (void**)&pfnSDL_IsGameController, (void**)&pfnSDL_GameControllerOpen, (void**)&pfnSDL_GameControllerGetAxis, + (void**)&pfnSDL_GameControllerGetButton, (void**)&pfnSDL_JoystickUpdate, (void**)&pfnSDL_GameControllerName}; #endif #ifdef _WIN32 @@ -299,12 +356,12 @@ void IN_SetMouseMode(bool enable) if(m_bRawInput) { #ifdef USE_SDL2 - pfnSDL_SetRelativeMouseMode(SDL_TRUE); + safe_pfnSDL_SetRelativeMouseMode(SDL_TRUE); #endif isMouseRelative = true; } #else - pfnSDL_SetRelativeMouseMode(SDL_TRUE); + safe_pfnSDL_SetRelativeMouseMode(SDL_TRUE); #endif currentMouseMode = true; @@ -315,7 +372,7 @@ void IN_SetMouseMode(bool enable) if(isMouseRelative) { #ifdef USE_SDL2 - pfnSDL_SetRelativeMouseMode(SDL_FALSE); + safe_pfnSDL_SetRelativeMouseMode(SDL_FALSE); #endif isMouseRelative = false; } @@ -323,7 +380,7 @@ void IN_SetMouseMode(bool enable) if (restore_spi) SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); #else - pfnSDL_SetRelativeMouseMode(SDL_FALSE); + safe_pfnSDL_SetRelativeMouseMode(SDL_FALSE); #endif currentMouseMode = false; @@ -476,6 +533,9 @@ void GoldSourceInput::IN_Shutdown (void) #endif #ifdef USE_SDL2 + for (int j=0; j 0 ) { for ( int i = 0; i < nJoysticks; i++ ) { - if ( pfnSDL_IsGameController( i ) ) + if ( safe_pfnSDL_IsGameController( i ) ) { - s_pJoystick = pfnSDL_GameControllerOpen( i ); + s_pJoystick = safe_pfnSDL_GameControllerOpen( i ); if ( s_pJoystick ) { //save the joystick's number of buttons and POV status @@ -903,7 +963,7 @@ void IN_StartupJoystick (void) // mark the joystick as available and advanced initialization not completed // this is needed as cvars are not available during initialization - gEngfuncs.Con_Printf ("joystick found\n\n", pfnSDL_GameControllerName(s_pJoystick)); + gEngfuncs.Con_Printf ("joystick found\n\n", safe_pfnSDL_GameControllerName(s_pJoystick)); joy_avail = 1; joy_advancedinit = 0; break; @@ -927,13 +987,13 @@ int RawValuePointer (int axis) { default: case JOY_AXIS_X: - return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTX ); + return safe_pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTX ); case JOY_AXIS_Y: - return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTY ); + return safe_pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_LEFTY ); case JOY_AXIS_Z: - return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTX ); + return safe_pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTX ); case JOY_AXIS_R: - return pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTY ); + return safe_pfnSDL_GameControllerGetAxis( s_pJoystick, SDL_CONTROLLER_AXIS_RIGHTY ); } #else @@ -1026,7 +1086,7 @@ void GoldSourceInput::IN_Commands (void) #ifdef USE_SDL2 for ( i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) { - if ( pfnSDL_GameControllerGetButton( s_pJoystick, (SDL_GameControllerButton)i ) ) + if ( safe_pfnSDL_GameControllerGetButton( s_pJoystick, (SDL_GameControllerButton)i ) ) { buttonstate |= 1< Date: Thu, 7 Dec 2017 21:25:26 +0300 Subject: [PATCH 217/227] sdl loading refactoring --- cl_dll/input_goldsource.cpp | 58 ++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp index e367a37e..38dac71d 100644 --- a/cl_dll/input_goldsource.cpp +++ b/cl_dll/input_goldsource.cpp @@ -28,6 +28,7 @@ #endif #ifdef USE_SDL2 +#define ARRAYSIZE(p) ( sizeof(p) /sizeof(p[0]) ) #include #include #include @@ -94,9 +95,23 @@ const char* safe_pfnSDL_GameControllerName(SDL_GameController* gamecontroller) return pfnSDL_GameControllerName(gamecontroller); return NULL; } -static void** const sdlFunctionPointers[] = {(void**)&pfnSDL_SetRelativeMouseMode, (void**)&pfnSDL_GetRelativeMouseState, (void**)&pfnSDL_NumJoysticks, - (void**)&pfnSDL_IsGameController, (void**)&pfnSDL_GameControllerOpen, (void**)&pfnSDL_GameControllerGetAxis, - (void**)&pfnSDL_GameControllerGetButton, (void**)&pfnSDL_JoystickUpdate, (void**)&pfnSDL_GameControllerName}; + +struct SDLFunction +{ + void** ppfnFunc; + const char* name; +}; +static SDLFunction sdlFunctions[] = { + {(void**)&pfnSDL_SetRelativeMouseMode, "SDL_SetRelativeMouseMode"}, + {(void**)&pfnSDL_GetRelativeMouseState, "SDL_GetRelativeMouseState"}, + {(void**)&pfnSDL_NumJoysticks, "SDL_NumJoysticks"}, + {(void**)&pfnSDL_IsGameController, "SDL_IsGameController"}, + {(void**)&pfnSDL_GameControllerOpen, "SDL_GameControllerOpen"}, + {(void**)&pfnSDL_GameControllerGetAxis, "SDL_GameControllerGetAxis"}, + {(void**)&pfnSDL_GameControllerGetButton, "SDL_GameControllerGetButton"}, + {(void**)&pfnSDL_JoystickUpdate, "SDL_JoystickUpdate"}, + {(void**)&pfnSDL_GameControllerName, "SDL_GameControllerName"} +}; #endif #ifdef _WIN32 @@ -533,8 +548,8 @@ void GoldSourceInput::IN_Shutdown (void) #endif #ifdef USE_SDL2 - for (int j=0; j Date: Sat, 9 Dec 2017 00:16:29 +0300 Subject: [PATCH 218/227] Update README.md, update makefiles, add .bat scripts for msvc --- README.md | 92 +++++++++++++++++++++++++++++----- cl_dll/Android.mk | 4 +- cl_dll/Makefile | 1 - cl_dll/compile.bat | 84 +++++++++++++++++++++++++++++++ dlls/Makefile | 4 +- dlls/compile.bat | 121 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 291 insertions(+), 15 deletions(-) create mode 100644 cl_dll/compile.bat create mode 100644 dlls/compile.bat diff --git a/README.md b/README.md index bb1cc675..21db93fb 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,41 @@ Half-Life SDK for Xash3D & GoldSource with some fixes. ### CMake as most universal way -``` -mkdir build && cd build -cmake ../ -``` + mkdir build && cd build + cmake ../ + make You may enable or disable some build options by -Dkey=value. All available build options are defined in CMakeLists.txt at root directory. +See below if you want to build the GoldSource compatible libraries. See below, if CMake is not suitable for you: ### Windows +#### Using msvc + +We use compilers provided with Microsoft Visual Studio 6. There're `compile.bat` scripts in both `cl_dll` and `dlls` directories. +Before running any of those files you must define `MSVCDir` variable which is the path to your msvc installation. + + set MSVCDir=C:\Program Files\Microsoft Visual Studio + compile.bat + +These scripts also can be ran via wine: + + MSVCDir="z:\home\$USER\.wine\drive_c\Program Files\Microsoft Visual Studio" wine cmd /c compile.bat + +The libraries built this way are always GoldSource compatible. + +There're dsp projects for MVS 6 in `cl_dll` and `dlls` directories, but we don't keep them up-to-date. You're free to adapt them for yourself and try to import into the newer MVS versions. + +#### Using mingw + TODO ### Linux -TODO + (cd dlls && make) + (cd cl_dll && make) ### OS X @@ -29,14 +48,65 @@ TODO ### FreeBSD -``` - cd dlls - gmake CXX=clang++ CC=clang - cd ../cl_dll - gmake CXX=clang++ CC=clang -``` + (cd dlls && gmake CXX=clang++ CC=clang) + (cd cl_dll && gmake CXX=clang++ CC=clang) ### Android Just typical `ndk-build`. +TODO: describe what it is. +### Building GoldSource-compatible libraries + +To enable building the goldsource compatible client library add GOLDSOURCE_SUPPORT flag when calling cmake: + + cmake .. -DGOLDSOURCE_SUPPORT=ON + +or when using make without cmake: + + make GOLDSOURCE_SUPPORT=1 + +Unlike original client by Valve the resulting client library will not depend on vgui or SDL2 just like the one that's used in FWGS Xash3d. + +Note for **Linux**: GoldSource requires libraries (both client and server) to be compiled with libstdc++ bundled with g++ of major version 4 (versions from 4.6 to 4.9 should work). +If your Linux distribution does not provide compatible g++ version you have several options. + +#### Method 1: Statically build with c++ library + +This one is the most simple but has a drawback. + + cmake ../ -DGOLDSOURCE_SUPPORT=ON -DCMAKE_C_FLAGS="-static-libstdc++ -static-libgcc" + +The drawback is that the compiled libraries will be larger in size. + +#### Method 2: Create and use chroot with older distro that includes g++ 4. + +Use the most suitable way for you to create an old distro 32-bit chroot. E.g. on Debian (and similar) you can use debootstrap. + + sudo debootstrap --arch=i386 jessie /var/chroot/jessie-debian-i386 # On Ubuntu type trusty instead of jessie + sudo chroot /var/chroot/jessie-debian-i386 + +Inside chroot install cmake, make, g++ and libsdl2-dev. Then exit the chroot. + +On the host system install schroot. Then create and adapt the following config in /etc/schroot/chroot.d/jessie.conf (you can choose a different name): + +``` +[jessie] +type=directory +description=Debian jessie i386 +directory=/var/chroot/debian-jessie-i386/ +users=yourusername +groups=yourusername +root-groups=root +preserve-environment=true +personality=linux32 +``` + +Insert your actual user name in place of `yourusername`. Then prepend any make or cmake call with `schroot -c jessie --`: + + schroot -c jessie -- cmake ../ -DGOLDSOURCE_SUPPORT=ON + schroot -c jessie -- make + +#### Method 3: Install the needed g++ version yourself + +TODO: describe steps. diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 452eb48b..68917633 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -105,7 +105,9 @@ LOCAL_CFLAGS += $(DEFINES) $(INCLUDES) ifeq ($(GOLDSOURCE_SUPPORT),1) DEFINES += -DGOLDSOURCE_SUPPORT - LOCAL_LDLIBS += -lSDL2 + ifeq ($(shell uname -s),Linux) + LOCAL_LDLIBS += -ldl + endif endif LOCAL_SRC_FILES := $(SRCS) $(SRCS_C) diff --git a/cl_dll/Makefile b/cl_dll/Makefile index f624473e..0ff4dadf 100644 --- a/cl_dll/Makefile +++ b/cl_dll/Makefile @@ -75,7 +75,6 @@ OBJS = $(SRCS:.cpp=.o) $(SRCS_C:.c=.o) LIBS=-lm ifeq ($(GOLDSOURCE_SUPPORT),1) DEFINES += -DGOLDSOURCE_SUPPORT - LIBS += -lSDL2 endif ifeq ($(shell uname -s),Linux) diff --git a/cl_dll/compile.bat b/cl_dll/compile.bat new file mode 100644 index 00000000..9270d4bc --- /dev/null +++ b/cl_dll/compile.bat @@ -0,0 +1,84 @@ +@echo off +echo Setting environment for minimal Visual C++ 6 +set INCLUDE=%MSVCDir%\VC98\Include +set LIB=%MSVCDir%\VC98\Lib +set PATH=%MSVCDir%\VC98\Bin;%MSVCDir%\Common\MSDev98\Bin\;%PATH% + +echo -- Compiler is MSVC6 + +set XASH3DSRC=..\..\Xash3D_original +set INCLUDES=-I../common -I../engine -I../pm_shared -I../game_shared -I../public -I../external -I../dlls -I../utils/false_vgui/include +set SOURCES=../dlls/crossbow.cpp^ + ../dlls/crowbar.cpp^ + ../dlls/egon.cpp^ + ../dlls/gauss.cpp^ + ../dlls/handgrenade.cpp^ + ../dlls/hornetgun.cpp^ + ../dlls/mp5.cpp^ + ../dlls/python.cpp^ + ../dlls/rpg.cpp^ + ../dlls/satchel.cpp^ + ../dlls/shotgun.cpp^ + ../dlls/squeakgrenade.cpp^ + ../dlls/tripmine.cpp^ + ../dlls/glock.cpp^ + ev_hldm.cpp^ + hl/hl_baseentity.cpp^ + hl/hl_events.cpp^ + hl/hl_objects.cpp^ + hl/hl_weapons.cpp^ + ammo.cpp^ + ammo_secondary.cpp^ + ammohistory.cpp^ + battery.cpp^ + cdll_int.cpp^ + com_weapons.cpp^ + death.cpp^ + demo.cpp^ + entity.cpp^ + ev_common.cpp^ + events.cpp^ + flashlight.cpp^ + GameStudioModelRenderer.cpp^ + geiger.cpp^ + health.cpp^ + hud.cpp^ + hud_msg.cpp^ + hud_redraw.cpp^ + hud_spectator.cpp^ + hud_update.cpp^ + in_camera.cpp^ + input.cpp^ + input_goldsource.cpp^ + input_mouse.cpp^ + input_xash3d.cpp^ + menu.cpp^ + message.cpp^ + overview.cpp^ + parsemsg.cpp^ + ../pm_shared/pm_debug.c^ + ../pm_shared/pm_math.c^ + ../pm_shared/pm_shared.c^ + saytext.cpp^ + status_icons.cpp^ + statusbar.cpp^ + studio_util.cpp^ + StudioModelRenderer.cpp^ + text_message.cpp^ + train.cpp^ + tri.cpp^ + util.cpp^ + view.cpp^ + scoreboard.cpp^ + MOTD.cpp +set DEFINES=/DCLIENT_DLL /DCLIENT_WEAPONS /Dsnprintf=_snprintf /DNO_VOICEGAMEMGR /DGOLDSOURCE_SUPPORT +set LIBS=user32.lib Winmm.lib +set OUTNAME=client.dll +set DEBUG=/debug + +cl %DEFINES% %LIBS% %SOURCES% %INCLUDES% -o %OUTNAME% /link /dll /out:%OUTNAME% %DEBUG% + +echo -- Compile done. Cleaning... + +del *.obj *.exp *.lib *.ilk +echo -- Done. diff --git a/dlls/Makefile b/dlls/Makefile index 60aad1b3..3599b9c7 100644 --- a/dlls/Makefile +++ b/dlls/Makefile @@ -129,13 +129,13 @@ OBJ = \ $(DLL_OBJDIR)/multiplay_gamerules.o \ $(DLL_OBJDIR)/nihilanth.o \ $(DLL_OBJDIR)/nodes.o \ - $(DLL_OBJDIR)/observer.cpp \^M + $(DLL_OBJDIR)/observer.o \ $(DLL_OBJDIR)/osprey.o \ $(DLL_OBJDIR)/pathcorner.o \ $(DLL_OBJDIR)/plane.o \ $(DLL_OBJDIR)/plats.o \ $(DLL_OBJDIR)/player.o \ - $(DLL_OBJDIR)/playermonster.o \^M + $(DLL_OBJDIR)/playermonster.o \ $(DLL_OBJDIR)/python.o \ $(DLL_OBJDIR)/rat.o \ $(DLL_OBJDIR)/roach.o \ diff --git a/dlls/compile.bat b/dlls/compile.bat new file mode 100644 index 00000000..53c4511b --- /dev/null +++ b/dlls/compile.bat @@ -0,0 +1,121 @@ +@echo off +echo Setting environment for minimal Visual C++ 6 +set INCLUDE=%MSVCDir%\VC98\Include +set LIB=%MSVCDir%\VC98\Lib +set PATH=%MSVCDir%\VC98\Bin;%MSVCDir%\Common\MSDev98\Bin\;%PATH% + +echo -- Compiler is MSVC6 + +set XASH3DSRC=..\..\Xash3D_original +set INCLUDES=-I../common -I../engine -I../pm_shared -I../game_shared -I../public +set SOURCES=agrunt.cpp^ + airtank.cpp^ + aflock.cpp^ + animating.cpp^ + animation.cpp^ + apache.cpp^ + barnacle.cpp^ + barney.cpp^ + bigmomma.cpp^ + bloater.cpp^ + bmodels.cpp^ + bullsquid.cpp^ + buttons.cpp^ + cbase.cpp^ + client.cpp^ + combat.cpp^ + controller.cpp^ + crossbow.cpp^ + crowbar.cpp^ + defaultai.cpp^ + doors.cpp^ + effects.cpp^ + egon.cpp^ + explode.cpp^ + flyingmonster.cpp^ + func_break.cpp^ + func_tank.cpp^ + game.cpp^ + gamerules.cpp^ + gargantua.cpp^ + gauss.cpp^ + genericmonster.cpp^ + ggrenade.cpp^ + globals.cpp^ + glock.cpp^ + gman.cpp^ + h_ai.cpp^ + h_battery.cpp^ + h_cine.cpp^ + h_cycler.cpp^ + h_export.cpp^ + handgrenade.cpp^ + hassassin.cpp^ + headcrab.cpp^ + healthkit.cpp^ + hgrunt.cpp^ + hornet.cpp^ + hornetgun.cpp^ + houndeye.cpp^ + ichthyosaur.cpp^ + islave.cpp^ + items.cpp^ + leech.cpp^ + lights.cpp^ + maprules.cpp^ + monstermaker.cpp^ + monsters.cpp^ + monsterstate.cpp^ + mortar.cpp^ + mp5.cpp^ + multiplay_gamerules.cpp^ + nihilanth.cpp^ + nodes.cpp^ + observer.cpp^ + osprey.cpp^ + pathcorner.cpp^ + plane.cpp^ + plats.cpp^ + player.cpp^ + playermonster.cpp^ + python.cpp^ + rat.cpp^ + roach.cpp^ + rpg.cpp^ + satchel.cpp^ + schedule.cpp^ + scientist.cpp^ + scripted.cpp^ + shotgun.cpp^ + singleplay_gamerules.cpp^ + skill.cpp^ + sound.cpp^ + soundent.cpp^ + spectator.cpp^ + squadmonster.cpp^ + squeakgrenade.cpp^ + subs.cpp^ + talkmonster.cpp^ + teamplay_gamerules.cpp^ + tempmonster.cpp^ + tentacle.cpp^ + triggers.cpp^ + tripmine.cpp^ + turret.cpp^ + util.cpp^ + weapons.cpp^ + world.cpp^ + xen.cpp^ + zombie.cpp^ + ../pm_shared/pm_debug.c ../pm_shared/pm_math.c ../pm_shared/pm_shared.c +set DEFINES=/DCLIENT_WEAPONS /Dsnprintf=_snprintf /DNO_VOICEGAMEMGR +set LIBS=user32.lib +set OUTNAME=hl.dll +set DEBUG=/debug + +cl %DEFINES% %LIBS% %SOURCES% %INCLUDES% -o %OUTNAME% /link /dll /out:%OUTNAME% %DEBUG% /def:".\hl.def" + +echo -- Compile done. Cleaning... + +del *.obj *.exp *.lib *.ilk +echo -- Done. From 0d56674e28cf6d08eda6cca79ce208a16a1af6bd Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sat, 9 Dec 2017 13:49:31 +0300 Subject: [PATCH 219/227] Add steam runtime chroot method --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 21db93fb..f0d3b4a1 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,21 @@ This one is the most simple but has a drawback. The drawback is that the compiled libraries will be larger in size. -#### Method 2: Create and use chroot with older distro that includes g++ 4. +#### Method 2: Build in Steam Runtime chroot + +This is the official way to build Steam compatible games for Linux. + +Clone https://github.com/ValveSoftware/steam-runtime and follow instructions https://github.com/ValveSoftware/steam-runtime#building-in-the-runtime + + sudo ./setup_chroot.sh --i386 + +Then use cmake and make as usual, but prepend the commands with `schroot --chroot steamrt_scout_i386 --`: + + mkdir build-in-steamrt && cd build-in-steamrt + schroot --chroot steamrt_scout_i386 -- cmake ../ -DGOLDSOURCE_SUPPORT=ON + schroot --chroot steamrt_scout_i386 -- make + +#### Method 3: Create your own chroot with older distro that includes g++ 4. Use the most suitable way for you to create an old distro 32-bit chroot. E.g. on Debian (and similar) you can use debootstrap. @@ -104,9 +118,10 @@ personality=linux32 Insert your actual user name in place of `yourusername`. Then prepend any make or cmake call with `schroot -c jessie --`: - schroot -c jessie -- cmake ../ -DGOLDSOURCE_SUPPORT=ON - schroot -c jessie -- make + mkdir build-in-chroot && cd build-in-chroot + schroot --chroot jessie -- cmake ../ -DGOLDSOURCE_SUPPORT=ON + schroot --chroot jessie -- make -#### Method 3: Install the needed g++ version yourself +#### Method 4: Install the needed g++ version yourself TODO: describe steps. From 87d6ca3b687eb0f6b3745c1ec79d22aac9071783 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sat, 9 Dec 2017 14:45:54 +0300 Subject: [PATCH 220/227] Add instructions for using chroot toolchain in QtCreator --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index f0d3b4a1..9261b1b3 100644 --- a/README.md +++ b/README.md @@ -125,3 +125,17 @@ Insert your actual user name in place of `yourusername`. Then prepend any make o #### Method 4: Install the needed g++ version yourself TODO: describe steps. + +#### Configuring Qt Creator to use toolchain from chroot + +Create a file with the following contents anywhere: + +```sh +#!/bin/sh +schroot --chroot steamrt_scout_i386 -- cmake "$@" +``` + +Make it executable. +In Qt Creator go to `Tools` -> `Options` -> `Build & Run` -> `CMake`. Add a new cmake tool and specify the path of previously created file. +Go to `Kits` tab, clone your default configuration and choose your CMake tool there. +Choose the new kit when opening CMakeLists.txt. From 5a60f08a59651aaaac73efa4af147f2a2d391a57 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Mon, 4 Dec 2017 01:02:25 +0300 Subject: [PATCH 221/227] Joystick support for non-sdl win32 (untested) --- cl_dll/input_goldsource.cpp | 161 ++++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-) diff --git a/cl_dll/input_goldsource.cpp b/cl_dll/input_goldsource.cpp index 38dac71d..f530bdbc 100644 --- a/cl_dll/input_goldsource.cpp +++ b/cl_dll/input_goldsource.cpp @@ -217,10 +217,25 @@ enum _ControlList AxisTurn }; +#if !defined(USE_SDL2) && defined(_WIN32) +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, + JOY_RETURNY, + JOY_RETURNZ, + JOY_RETURNR, + JOY_RETURNU, + JOY_RETURNV +}; +#endif DWORD dwAxisMap[ JOY_MAX_AXES ]; DWORD dwControlMap[ JOY_MAX_AXES ]; +#if defined(USE_SDL2) int pdwRawValue[ JOY_MAX_AXES ]; +#elif defined(_WIN32) +PDWORD pdwRawValue[ JOY_MAX_AXES ]; +#endif DWORD joy_oldbuttonstate, joy_oldpovstate; int joy_id; @@ -228,6 +243,9 @@ DWORD joy_numbuttons; #ifdef USE_SDL2 SDL_GameController *s_pJoystick = NULL; +#elif defined(_WIN32) +DWORD joy_flags; +static JOYINFOEX ji; #endif // none of these cvars are saved over a session @@ -990,14 +1008,64 @@ void IN_StartupJoystick (void) { gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); } +#elif defined(_WIN32) + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_idvalue != 0.0) + { + ji.dwUpos += 100; + } + return 1; + } + else + { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Con_Printf ("IN_ReadJoystick: no response\n"); + // joy_avail = 0; + return 0; + } +#else + return 0; +#endif } @@ -1213,7 +1353,12 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd ) for (i = 0; i < JOY_MAX_AXES; i++) { // get the floating point zero-centered, potentially-inverted data for the current axis +#ifdef USE_SDL2 fAxisValue = (float)pdwRawValue[i]; +#elif defined(_WIN32) + fAxisValue = (float) *pdwRawValue[i]; + fAxisValue -= 32768.0; +#endif if (joy_wwhack2->value != 0.0) { From 18adf0979fe6fe8a9af2e5f46721f198b6274e5e Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 10 Dec 2017 20:56:46 +0500 Subject: [PATCH 222/227] Redefine string_t. Fix wrong variables type. --- cl_dll/util_vector.h | 2 +- common/const.h | 2 +- dlls/bigmomma.cpp | 2 +- dlls/cbase.h | 2 +- dlls/effects.cpp | 6 +++--- dlls/effects.h | 2 +- dlls/extdll.h | 2 +- dlls/func_break.h | 4 ++-- dlls/func_tank.cpp | 6 +++--- dlls/lights.cpp | 2 +- dlls/mortar.cpp | 4 ++-- dlls/plats.cpp | 6 +++--- dlls/scripted.cpp | 6 +++--- dlls/scripted.h | 6 +++--- dlls/talkmonster.h | 4 ++-- dlls/triggers.cpp | 14 +++++++------- dlls/util.cpp | 14 +++++++------- dlls/util.h | 4 ++-- dlls/weapons.h | 2 +- 19 files changed, 45 insertions(+), 45 deletions(-) diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h index ff5f9a91..8b596ac1 100644 --- a/cl_dll/util_vector.h +++ b/cl_dll/util_vector.h @@ -23,7 +23,7 @@ // 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 int string_t; // from engine's pr_comp.h; typedef float vec_t; // needed before including progdefs.h //========================================================= diff --git a/common/const.h b/common/const.h index d29816e6..3d738675 100644 --- a/common/const.h +++ b/common/const.h @@ -733,7 +733,7 @@ enum }; typedef unsigned int func_t; -typedef unsigned int string_t; +typedef int string_t; typedef unsigned char byte; typedef unsigned short word; diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index 6b594983..434d6134 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -49,7 +49,7 @@ public: virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; - int m_preSequence; + string_t m_preSequence; }; LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ) diff --git a/dlls/cbase.h b/dlls/cbase.h index b78de883..10f7a85f 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -438,7 +438,7 @@ class CBaseDelay : public CBaseEntity { public: float m_flDelay; - int m_iszKillTarget; + string_t m_iszKillTarget; virtual void KeyValue( KeyValueData *pkvd ); virtual int Save( CSave &save ); diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 15df3bc3..5b8d650c 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -379,9 +379,10 @@ public: void BeamUpdateVars( void ); + string_t m_iszStartEntity; + string_t m_iszEndEntity; + string_t m_iszSpriteName; int m_active; - int m_iszStartEntity; - int m_iszEndEntity; float m_life; int m_boltWidth; int m_noiseAmplitude; @@ -389,7 +390,6 @@ public: int m_speed; float m_restrike; int m_spriteTexture; - int m_iszSpriteName; int m_frameStart; float m_radius; diff --git a/dlls/effects.h b/dlls/effects.h index 68f0ea29..f4b6b5b2 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -321,7 +321,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; CSprite *m_pSprite; - int m_iszSpriteName; + string_t m_iszSpriteName; Vector m_firePosition; }; #endif //EFFECTS_H diff --git a/dlls/extdll.h b/dlls/extdll.h index 45c42309..812ce40f 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -69,7 +69,7 @@ typedef int BOOL; // 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 int string_t; // from engine's pr_comp.h; typedef float vec_t; // needed before including progdefs.h // Vector class diff --git a/dlls/func_break.h b/dlls/func_break.h index ab5dda41..b4ff1fc1 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -82,9 +82,9 @@ public: Materials m_Material; Explosions m_Explosion; + string_t m_iszGibModel; + string_t m_iszSpawnObject; int m_idShard; float m_angle; - int m_iszGibModel; - int m_iszSpawnObject; }; #endif // FUNC_BREAK_H diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 6eebc675..013948eb 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -97,6 +97,9 @@ public: protected: CBasePlayer* m_pController; + string_t m_iszSpriteSmoke; + string_t m_iszSpriteFlash; + string_t m_iszMaster; // Master entity (game_team_master or multisource) float m_flNextAttack; Vector m_vecControllerUsePos; @@ -120,14 +123,11 @@ protected: 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[] = diff --git a/dlls/lights.cpp b/dlls/lights.cpp index e6b03125..8a4f8de8 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -37,8 +37,8 @@ public: static TYPEDESCRIPTION m_SaveData[]; private: + string_t m_iszPattern; int m_iStyle; - int m_iszPattern; }; LINK_ENTITY_TO_CLASS( light, CLight ) diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index 33a7d2da..7faf3e56 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -45,8 +45,8 @@ public: void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iszXController; - int m_iszYController; + string_t m_iszXController; + string_t m_iszYController; float m_flSpread; float m_flDelay; int m_iCount; diff --git a/dlls/plats.cpp b/dlls/plats.cpp index c1220f3c..b3e1c683 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1619,9 +1619,9 @@ public: CFuncTrackTrain *m_train; - int m_trackTopName; - int m_trackBottomName; - int m_trainName; + string_t m_trackTopName; + string_t m_trackBottomName; + string_t m_trainName; TRAIN_CODE m_code; int m_targetState; int m_use; diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index 678502f6..92b9aa6a 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -907,15 +907,15 @@ public: BOOL StartSentence( CBaseMonster *pTarget ); private: - int m_iszSentence; // string index for idle animation - int m_iszEntity; // entity that is wanted for this sentence + string_t m_iszSentence; // string index for idle animation + string_t m_iszEntity; // entity that is wanted for this sentence + string_t m_iszListener; // name of entity to look at while talking 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 diff --git a/dlls/scripted.h b/dlls/scripted.h index 25348114..6cf8cfa1 100644 --- a/dlls/scripted.h +++ b/dlls/scripted.h @@ -77,9 +77,9 @@ public: 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 + string_t m_iszIdle; // string index for idle animation + string_t m_iszPlay; // string index for scripted animation + string_t m_iszEntity; // entity that is wanted for this script int m_fMoveTo; int m_iFinishSchedule; float m_flRadius; // range to search diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 72222aae..084861bc 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -162,8 +162,8 @@ public: 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) + string_t m_iszUse; // Custom +USE sentence group (follow) + string_t 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. diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 8171a195..7d7f255c 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -114,7 +114,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; private: - int m_globalstate; + string_t m_globalstate; USE_TYPE triggerType; }; @@ -267,11 +267,11 @@ public: static TYPEDESCRIPTION m_SaveData[]; - int m_cTargets; // the total number of targets in this manager's fire list. + string_t 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 + 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 ) @@ -1321,9 +1321,9 @@ public: static TYPEDESCRIPTION m_SaveData[]; + string_t m_changeTarget; 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; }; @@ -2054,7 +2054,7 @@ public: static TYPEDESCRIPTION m_SaveData[]; private: - int m_iszNewTarget; + string_t m_iszNewTarget; }; LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ) @@ -2117,7 +2117,7 @@ public: EHANDLE m_hPlayer; EHANDLE m_hTarget; CBaseEntity *m_pentPath; - int m_sPath; + string_t m_sPath; float m_flWait; float m_flReturnTime; float m_flStopTime; diff --git a/dlls/util.cpp b/dlls/util.cpp index f382ac58..94c8c68c 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1586,7 +1586,7 @@ void UTIL_StripToken( const char *pKey, char *pDest ) static int gSizes[FIELD_TYPECOUNT] = { sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING + sizeof(string_t), // FIELD_STRING sizeof(void*), // FIELD_ENTITY sizeof(void*), // FIELD_CLASSPTR sizeof(void*), // FIELD_EHANDLE @@ -1613,7 +1613,7 @@ static int gSizes[FIELD_TYPECOUNT] = static int gInputSizes[FIELD_TYPECOUNT] = { sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING + sizeof(string_t), // FIELD_STRING sizeof(int), // FIELD_ENTITY sizeof(int), // FIELD_CLASSPTR sizeof(int), // FIELD_EHANDLE @@ -1940,7 +1940,7 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: - ( *(int *)( (char *)pev + pField->fieldOffset ) ) = ALLOC_STRING( pkvd->szValue ); + ( *(string_t *)( (char *)pev + pField->fieldOffset ) ) = ALLOC_STRING( pkvd->szValue ); break; case FIELD_TIME: case FIELD_FLOAT: @@ -2014,7 +2014,7 @@ int CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFi case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: - WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + WriteString( pTest->fieldName, (string_t *)pOutputData, pTest->fieldSize ); break; case FIELD_CLASSPTR: case FIELD_EVARS: @@ -2197,14 +2197,14 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou } pInputData = pString; if( strlen( (char *)pInputData ) == 0 ) - *( (int *)pOutputData ) = 0; + *( (string_t *)pOutputData ) = 0; else { - int string; + string_t string; string = ALLOC_STRING( (char *)pInputData ); - *( (int *)pOutputData ) = string; + *( (string_t *)pOutputData ) = string; if( !FStringNull( string ) && m_precache ) { diff --git a/dlls/util.h b/dlls/util.h index 2ffe536e..ee7d116b 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -37,13 +37,13 @@ extern globalvars_t *gpGlobals; #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) #if !defined XASH_64BIT || defined(CLIENT_DLL) -#define MAKE_STRING(str) ((size_t)str - (size_t)STRING(0)) +#define MAKE_STRING(str) ((int)str - (int)STRING(0)) #else static inline int MAKE_STRING(const char *szValue) { long long ptrdiff = szValue - STRING(0); if( ptrdiff > INT_MAX || ptrdiff < INT_MIN ) - return ALLOC_STRING(szValue); + return ALLOC_STRING( szValue ); else return (int)ptrdiff; } diff --git a/dlls/weapons.h b/dlls/weapons.h index 6c03105b..0cfa2031 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -446,7 +446,7 @@ public: CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES];// one slot for each - int m_rgiszAmmo[MAX_AMMO_SLOTS];// ammo names + string_t m_rgiszAmmo[MAX_AMMO_SLOTS];// ammo names int m_rgAmmo[MAX_AMMO_SLOTS];// ammo quantities int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer) From 28020503292fb16cf30b6ccd639f5e6cb9cd4b46 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 10 Dec 2017 21:05:13 +0500 Subject: [PATCH 223/227] Add missing break. --- dlls/hgrunt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 4cb85c2c..62c947f1 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -959,6 +959,7 @@ void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent ) } } + break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; From 83c0505ffe12da025c207fcca1f9bd67b5291097 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 10 Dec 2017 21:08:10 +0500 Subject: [PATCH 224/227] Add missing precache calls. --- dlls/effects.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 5b8d650c..2e127b2d 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -2181,6 +2181,8 @@ public: void CItemSoda::Precache( void ) { + PRECACHE_MODEL( "models/can.mdl" ); + PRECACHE_SOUND( "weapons/g_bounce.wav" ); } LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ) From 41c9b072e5f871f6d4ce778a037cfa6ae38abcdb Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 10 Dec 2017 22:19:34 +0500 Subject: [PATCH 225/227] Add missing #include guards. --- cl_dll/ammohistory.h | 3 +++ cl_dll/health.h | 3 +++ cl_dll/hud_spectator.h | 4 ++-- cl_dll/parsemsg.h | 3 +++ dlls/gamerules.h | 4 +++- dlls/plane.h | 6 +++--- dlls/skill.h | 3 +++ dlls/spectator.h | 3 +++ dlls/squad.h | 4 +++- dlls/squadmonster.h | 3 +++ dlls/util.h | 3 +++ 11 files changed, 32 insertions(+), 7 deletions(-) diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index f1063ae1..032d3ee3 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -15,6 +15,8 @@ // // ammohistory.h // +#ifndef AMMOHISTORY_H +#define AMMOHISTORY_H // this is the max number of items in each bucket #define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS @@ -137,3 +139,4 @@ public: }; extern HistoryResource gHR; +#endif // AMMOHISTORY_H diff --git a/cl_dll/health.h b/cl_dll/health.h index 132b9cb4..1007c17c 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -12,6 +12,8 @@ * without written permission from Valve LLC. * ****/ +#ifndef HEALTH_H +#define HEALTH_H #define DMG_IMAGE_LIFE 2 // seconds that image is up @@ -122,3 +124,4 @@ private: void CalcDamageDirection( vec3_t vecFrom ); void UpdateTiles( float fTime, long bits ); }; +#endif // HEALTH_H diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 58026668..9cfc5519 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -5,8 +5,8 @@ // $NoKeywords: $ //============================================================================= -#ifndef SPECTATOR_H -#define SPECTATOR_H +#ifndef HUD_SPECTATOR_H +#define HUD_SPECTATOR_H #pragma once #include "cl_entity.h" diff --git a/cl_dll/parsemsg.h b/cl_dll/parsemsg.h index 0e6bd2a3..6d552413 100644 --- a/cl_dll/parsemsg.h +++ b/cl_dll/parsemsg.h @@ -15,6 +15,8 @@ // // parsemsg.h // +#ifndef PARSEMSG_H +#define PARSEMSG_H #define ASSERT( x ) @@ -30,6 +32,7 @@ float READ_COORD( void ); float READ_ANGLE( void ); float READ_HIRESANGLE( void ); +#endif // PARSEMSG_H diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 6ad470d0..71036151 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -15,7 +15,8 @@ //========================================================= // GameRules //========================================================= - +#ifndef GAMERULES_H +#define GAMERULES_H //#include "weapons.h" //#include "items.h" class CBasePlayerItem; @@ -361,3 +362,4 @@ protected: }; extern DLL_GLOBAL CGameRules *g_pGameRules; +#endif // GAMERULES_H diff --git a/dlls/plane.h b/dlls/plane.h index 35a17611..912062f6 100644 --- a/dlls/plane.h +++ b/dlls/plane.h @@ -12,12 +12,12 @@ * without written permission from Valve LLC. * ****/ -#ifndef PLANE_H -#define PLANE_H - //========================================================= // Plane //========================================================= +#ifndef PLANE_H +#define PLANE_H + class CPlane { public: diff --git a/dlls/skill.h b/dlls/skill.h index 12b784e3..aa338362 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -15,6 +15,8 @@ //========================================================= // skill.h - skill level concerns //========================================================= +#ifndef SKILL_H +#define SKILL_H struct skilldata_t { @@ -143,3 +145,4 @@ extern DLL_GLOBAL int g_iSkillLevel; #define SKILL_EASY 1 #define SKILL_MEDIUM 2 #define SKILL_HARD 3 +#endif // SKILL_H diff --git a/dlls/spectator.h b/dlls/spectator.h index 90f8678f..00567fc6 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -13,6 +13,8 @@ * ****/ // Spectator.h +#ifndef SPECTATOR_H +#define SPECTATOR_H class CBaseSpectator : public CBaseEntity { @@ -25,3 +27,4 @@ public: private: void SpectatorImpulseCommand( void ); }; +#endif // SPECTATOR_H diff --git a/dlls/squad.h b/dlls/squad.h index bb2784bb..c29a7199 100644 --- a/dlls/squad.h +++ b/dlls/squad.h @@ -4,10 +4,11 @@ // // $NoKeywords: $ //============================================================================= - //========================================================= // squad.h //========================================================= +#ifndef SQUAD_H +#define 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 @@ -19,3 +20,4 @@ #define bits_SQUAD_FLANK_RIGHT ( 1 << 1 ) #define bits_SQUAD_ADVANCE ( 1 << 2 ) #define bits_SQUAD_FLUSH_ATTACK ( 1 << 3 ) +#endif // SQUAD_H diff --git a/dlls/squadmonster.h b/dlls/squadmonster.h index 707910c2..132d4177 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -16,6 +16,8 @@ // CSquadMonster - all the extra data for monsters that // form squads. //========================================================= +#ifndef SQUADMONSTER_H +#define SQUADMONSTER_H #define SF_SQUADMONSTER_LEADER 32 @@ -116,3 +118,4 @@ public: MONSTERSTATE GetIdealState( void ); Schedule_t *GetScheduleOfType( int iType ); }; +#endif // SQUADMONSTER_H diff --git a/dlls/util.h b/dlls/util.h index ee7d116b..8f56cd76 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -12,6 +12,8 @@ * without written permission from Valve LLC. * ****/ +#ifndef UTIL_H +#define UTIL_H // // Misc utility code // @@ -575,3 +577,4 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); float UTIL_WeaponTimeBase( void ); +#endif // UTIL_H From f27d1028acf7ae1cf7494002e880d235177f2c52 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 11 Dec 2017 01:40:41 +0500 Subject: [PATCH 226/227] Do not reorganize variables in classes. Add missing #pragma once directives and more #include guards. --- cl_dll/GameStudioModelRenderer.h | 6 ++---- cl_dll/GameStudioModelRenderer_Sample.h | 6 ++---- cl_dll/StudioModelRenderer.h | 4 +--- cl_dll/ammo.h | 2 +- cl_dll/ammohistory.h | 1 + cl_dll/camera.h | 2 +- cl_dll/cl_dll.h | 1 + cl_dll/com_weapons.h | 4 +--- cl_dll/demo.h | 2 +- cl_dll/ev_hldm.h | 1 + cl_dll/eventscripts.h | 1 + cl_dll/health.h | 1 + cl_dll/hud.h | 1 + cl_dll/hud_iface.h | 2 +- cl_dll/hud_spectator.h | 2 +- cl_dll/in_defs.h | 2 +- cl_dll/input_mouse.h | 1 + cl_dll/kbutton.h | 3 +-- cl_dll/overview.h | 2 +- cl_dll/parsemsg.h | 1 + cl_dll/studio_util.h | 4 +--- cl_dll/util_vector.h | 4 ++++ common/beamdef.h | 4 ++-- common/bspfile.h | 2 +- common/cl_entity.h | 4 ++-- common/com_model.h | 4 ++-- common/con_nprint.h | 3 ++- common/const.h | 1 + common/cvardef.h | 1 + common/demo_api.h | 4 ++-- common/dlight.h | 4 ++-- common/entity_state.h | 3 ++- common/entity_types.h | 4 ++-- common/event_api.h | 4 ++-- common/event_args.h | 3 ++- common/event_flags.h | 4 ++-- common/gameinfo.h | 4 ++-- common/hltv.h | 4 ++-- common/ivoicetweak.h | 4 ++-- common/lightstyle.h | 4 ++-- common/mathlib.h | 5 ++++- common/net_api.h | 4 ++-- common/netadr.h | 4 ++-- common/particledef.h | 4 ++-- common/pmtrace.h | 4 ++-- common/qfont.h | 4 ++-- common/r_efx.h | 4 ++-- common/r_studioint.h | 5 ++--- common/ref_params.h | 4 ++-- common/render_api.h | 4 ++-- common/screenfade.h | 4 ++-- common/studio_event.h | 4 ++-- common/triangleapi.h | 2 +- common/usercmd.h | 4 ++-- common/wadfile.h | 4 ++-- common/weaponinfo.h | 4 ++-- common/wrect.h | 4 ++-- dlls/activity.h | 2 +- dlls/activitymap.h | 5 ++++- dlls/animation.h | 1 + dlls/basemonster.h | 2 +- dlls/cbase.h | 1 + dlls/cdll_dll.h | 2 +- dlls/client.h | 1 + dlls/decals.h | 1 + dlls/doors.h | 1 + dlls/effects.cpp | 4 ++-- dlls/effects.h | 1 + dlls/explode.h | 3 ++- dlls/exportdef.h | 1 + dlls/extdll.h | 1 + dlls/flyingmonster.h | 2 +- dlls/func_break.h | 5 +++-- dlls/func_tank.cpp | 6 +++--- dlls/game.h | 2 +- dlls/gamerules.h | 1 + dlls/hornet.h | 5 ++++- dlls/items.h | 1 + dlls/lights.cpp | 2 +- dlls/monsters.h | 1 + dlls/nodes.h | 1 + dlls/physcallback.h | 2 +- dlls/player.h | 1 + dlls/saverestore.h | 1 + dlls/schedule.h | 2 +- dlls/scripted.cpp | 2 +- dlls/scripted.h | 1 + dlls/scriptevent.h | 3 ++- dlls/skill.h | 3 ++- dlls/soundent.h | 4 ++++ dlls/spectator.h | 1 + dlls/squad.h | 1 + dlls/squadmonster.h | 1 + dlls/talkmonster.h | 1 + dlls/teamplay_gamerules.h | 4 ++++ dlls/trains.h | 1 + dlls/triggers.cpp | 6 +++--- dlls/util.h | 1 + dlls/vector.h | 1 + dlls/weapons.h | 1 + engine/cdll_exp.h | 3 ++- engine/cdll_int.h | 2 +- engine/custom.h | 3 +-- engine/customentity.h | 2 +- engine/edict.h | 4 +--- engine/eiface.h | 2 +- engine/keydefs.h | 4 ++-- engine/menu_int.h | 2 +- engine/physint.h | 4 ++-- engine/progdefs.h | 3 +-- engine/shake.h | 2 +- engine/sprite.h | 4 ++-- engine/studio.h | 2 +- pm_shared/pm_debug.h | 3 +-- pm_shared/pm_defs.h | 3 +-- pm_shared/pm_info.h | 3 +-- pm_shared/pm_materials.h | 1 + pm_shared/pm_movevars.h | 1 + pm_shared/pm_shared.h | 4 +--- 119 files changed, 183 insertions(+), 140 deletions(-) diff --git a/cl_dll/GameStudioModelRenderer.h b/cl_dll/GameStudioModelRenderer.h index 7d06f70f..881dd144 100644 --- a/cl_dll/GameStudioModelRenderer.h +++ b/cl_dll/GameStudioModelRenderer.h @@ -5,11 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( GAMESTUDIOMODELRENDERER_H ) #define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif /* ==================== @@ -23,4 +21,4 @@ public: CGameStudioModelRenderer( void ); }; -#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file +#endif // GAMESTUDIOMODELRENDERER_H diff --git a/cl_dll/GameStudioModelRenderer_Sample.h b/cl_dll/GameStudioModelRenderer_Sample.h index c924ba3e..9c09374b 100644 --- a/cl_dll/GameStudioModelRenderer_Sample.h +++ b/cl_dll/GameStudioModelRenderer_Sample.h @@ -5,11 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( GAMESTUDIOMODELRENDERER_H ) #define GAMESTUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif /* ==================== @@ -52,4 +50,4 @@ private: bool m_bLocal; }; -#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file +#endif // GAMESTUDIOMODELRENDERER_H diff --git a/cl_dll/StudioModelRenderer.h b/cl_dll/StudioModelRenderer.h index 0a56b731..cbfd0d3b 100644 --- a/cl_dll/StudioModelRenderer.h +++ b/cl_dll/StudioModelRenderer.h @@ -5,11 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined ( STUDIOMODELRENDERER_H ) #define STUDIOMODELRENDERER_H -#if defined( _WIN32 ) -#pragma once -#endif /* ==================== diff --git a/cl_dll/ammo.h b/cl_dll/ammo.h index 9134681c..57c08805 100644 --- a/cl_dll/ammo.h +++ b/cl_dll/ammo.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef __AMMO_H__ #define __AMMO_H__ diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 032d3ee3..44edc916 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -15,6 +15,7 @@ // // ammohistory.h // +#pragma once #ifndef AMMOHISTORY_H #define AMMOHISTORY_H diff --git a/cl_dll/camera.h b/cl_dll/camera.h index 448b22ca..69a00216 100644 --- a/cl_dll/camera.h +++ b/cl_dll/camera.h @@ -7,7 +7,7 @@ // Camera.h -- defines and such for a 3rd person camera // NOTE: must include quakedef.h first - +#pragma once #ifndef _CAMERA_H_ #define _CAMERA_H_ diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h index 0acd6860..6e1c4e69 100644 --- a/cl_dll/cl_dll.h +++ b/cl_dll/cl_dll.h @@ -25,6 +25,7 @@ // - Drawing the HUD graphics every frame // - Handling the custum HUD-update packets // +#pragma once #ifndef CL_DLL_H #define CL_DLL_H typedef unsigned char byte; diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h index d252c196..efe06ad6 100644 --- a/cl_dll/com_weapons.h +++ b/cl_dll/com_weapons.h @@ -7,11 +7,9 @@ // com_weapons.h // Shared weapons common function prototypes +#pragma once #if !defined( COM_WEAPONSH ) #define COM_WEAPONSH -#ifdef _WIN32 -#pragma once -#endif #include "hud_iface.h" diff --git a/cl_dll/demo.h b/cl_dll/demo.h index a0a1b30e..b7dbaff0 100644 --- a/cl_dll/demo.h +++ b/cl_dll/demo.h @@ -5,9 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( DEMOH ) #define DEMOH -#pragma once // Types of demo messages we can write/parse enum diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h index bff43b1e..88b221df 100644 --- a/cl_dll/ev_hldm.h +++ b/cl_dll/ev_hldm.h @@ -5,6 +5,7 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined ( EV_HLDMH ) #define EV_HLDMH diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h index bb835474..c11ee338 100644 --- a/cl_dll/eventscripts.h +++ b/cl_dll/eventscripts.h @@ -6,6 +6,7 @@ //============================================================================= // eventscripts.h +#pragma once #if !defined ( EVENTSCRIPTSH ) #define EVENTSCRIPTSH diff --git a/cl_dll/health.h b/cl_dll/health.h index 1007c17c..62d7e0bc 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef HEALTH_H #define HEALTH_H diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 1970753d..decfa917 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -19,6 +19,7 @@ // // CHud handles the message, calculation, and drawing the HUD // +#pragma once #ifndef HUD_H #define HUD_H #define RGB_YELLOWISH 0x00FFA000 //255,160,0 diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h index a7a05e7e..7993bd9d 100644 --- a/cl_dll/hud_iface.h +++ b/cl_dll/hud_iface.h @@ -5,9 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( HUD_IFACEH ) #define HUD_IFACEH -#pragma once #include "exportdef.h" diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 9cfc5519..7a9ec9d3 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -5,9 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #ifndef HUD_SPECTATOR_H #define HUD_SPECTATOR_H -#pragma once #include "cl_entity.h" diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h index 037c7cc6..d5c352fa 100644 --- a/cl_dll/in_defs.h +++ b/cl_dll/in_defs.h @@ -5,9 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( IN_DEFSH ) #define IN_DEFSH -#pragma once // up / down #define PITCH 0 diff --git a/cl_dll/input_mouse.h b/cl_dll/input_mouse.h index 6ddf54db..cf0102c8 100644 --- a/cl_dll/input_mouse.h +++ b/cl_dll/input_mouse.h @@ -1,3 +1,4 @@ +#pragma once #ifndef INPUT_MOUSE_H #define INPUT_MOUSE_H #include "cl_dll.h" diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h index 29accdf5..54f1ea93 100644 --- a/cl_dll/kbutton.h +++ b/cl_dll/kbutton.h @@ -4,10 +4,9 @@ // // $NoKeywords: $ //============================================================================= - +#pragma once #if !defined( KBUTTONH ) #define KBUTTONH -#pragma once typedef struct kbutton_s { diff --git a/cl_dll/overview.h b/cl_dll/overview.h index 6748760b..59535fb4 100644 --- a/cl_dll/overview.h +++ b/cl_dll/overview.h @@ -5,9 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #ifndef OVERVIEW_H #define OVERVIEW_H -#pragma once //----------------------------------------------------------------------------- // Purpose: Handles the drawing of the top-down map and all the things on it diff --git a/cl_dll/parsemsg.h b/cl_dll/parsemsg.h index 6d552413..05efefc3 100644 --- a/cl_dll/parsemsg.h +++ b/cl_dll/parsemsg.h @@ -15,6 +15,7 @@ // // parsemsg.h // +#pragma once #ifndef PARSEMSG_H #define PARSEMSG_H diff --git a/cl_dll/studio_util.h b/cl_dll/studio_util.h index 963dcda7..7af94672 100644 --- a/cl_dll/studio_util.h +++ b/cl_dll/studio_util.h @@ -5,11 +5,9 @@ // $NoKeywords: $ //============================================================================= +#pragma once #if !defined( STUDIO_UTIL_H ) #define STUDIO_UTIL_H -#if defined( WIN32 ) -#pragma once -#endif #ifndef M_PI #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h index 8b596ac1..477d97be 100644 --- a/cl_dll/util_vector.h +++ b/cl_dll/util_vector.h @@ -15,6 +15,9 @@ // Vector.h // A subset of the extdll.h in the project HL Entity DLL // +#pragma once +#ifndef UTIL_VECTOR_H +#define UTIL_VECTOR_H // Misc C-runtime library headers #include "stdio.h" @@ -124,3 +127,4 @@ inline float DotProduct( const Vector& a, const Vector& b) { return( a.x * b.x + 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 ); } #define vec3_t Vector +#endif // UTIL_VECTOR_H diff --git a/common/beamdef.h b/common/beamdef.h index 3b8c553a..f254428c 100644 --- a/common/beamdef.h +++ b/common/beamdef.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef BEAMDEF_H #define BEAMDEF_H @@ -57,4 +57,4 @@ struct beam_s struct particle_s *particles; }; -#endif//BEAMDEF_H \ No newline at end of file +#endif//BEAMDEF_H diff --git a/common/bspfile.h b/common/bspfile.h index 809e2fd0..079e1b21 100644 --- a/common/bspfile.h +++ b/common/bspfile.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef BSPFILE_H #define BSPFILE_H diff --git a/common/cl_entity.h b/common/cl_entity.h index 02f84e35..c003ce30 100644 --- a/common/cl_entity.h +++ b/common/cl_entity.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef CL_ENTITY_H #define CL_ENTITY_H @@ -102,4 +102,4 @@ struct cl_entity_s colorVec cvFloorColor; }; -#endif//CL_ENTITY_H \ No newline at end of file +#endif//CL_ENTITY_H diff --git a/common/com_model.h b/common/com_model.h index 709f23d9..abc8e8e6 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef COM_MODEL_H #define COM_MODEL_H @@ -410,4 +410,4 @@ typedef struct mspriteframedesc_t frames[1]; } msprite_t; -#endif//COM_MODEL_H \ No newline at end of file +#endif//COM_MODEL_H diff --git a/common/con_nprint.h b/common/con_nprint.h index 5d87c760..615a1850 100644 --- a/common/con_nprint.h +++ b/common/con_nprint.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CON_NPRINT_H #define CON_NPRINT_H @@ -22,4 +23,4 @@ typedef struct con_nprint_s float color[3]; // RGB colors ( 0.0 -> 1.0 scale ) } con_nprint_t; -#endif//CON_NPRINT_H \ No newline at end of file +#endif//CON_NPRINT_H diff --git a/common/const.h b/common/const.h index 3d738675..fa0f33e6 100644 --- a/common/const.h +++ b/common/const.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CONST_H #define CONST_H // diff --git a/common/cvardef.h b/common/cvardef.h index e8a24581..f461c329 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CVARDEF_H #define CVARDEF_H diff --git a/common/demo_api.h b/common/demo_api.h index fa89bbef..1a678b60 100644 --- a/common/demo_api.h +++ b/common/demo_api.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef DEMO_API_H #define DEMO_API_H @@ -24,4 +24,4 @@ typedef struct demo_api_s void (*WriteBuffer)( int size, unsigned char *buffer ); } demo_api_t; -#endif//DEMO_API_H \ No newline at end of file +#endif//DEMO_API_H diff --git a/common/dlight.h b/common/dlight.h index b139d582..ecb01445 100644 --- a/common/dlight.h +++ b/common/dlight.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef DLIGHT_H #define DLIGHT_H @@ -28,4 +28,4 @@ typedef struct dlight_s qboolean dark; // subtracts light instead of adding } dlight_t; -#endif//DLIGHT_H \ No newline at end of file +#endif//DLIGHT_H diff --git a/common/entity_state.h b/common/entity_state.h index ef5448f1..2ffd70dc 100644 --- a/common/entity_state.h +++ b/common/entity_state.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef ENTITY_STATE_H #define ENTITY_STATE_H @@ -183,4 +184,4 @@ typedef struct local_state_s weapon_data_t weapondata[64]; } local_state_t; -#endif//ENTITY_STATE_H \ No newline at end of file +#endif//ENTITY_STATE_H diff --git a/common/entity_types.h b/common/entity_types.h index 25a8fce9..f5754fea 100644 --- a/common/entity_types.h +++ b/common/entity_types.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef ENTITY_TYPES_H #define ENTITY_TYPES_H @@ -22,4 +22,4 @@ #define ET_BEAM 3 #define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes -#endif//ENTITY_TYPES_H \ No newline at end of file +#endif//ENTITY_TYPES_H diff --git a/common/event_api.h b/common/event_api.h index a7ff71b2..86c5fbe9 100644 --- a/common/event_api.h +++ b/common/event_api.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef EVENT_API_H #define EVENT_API_H @@ -51,4 +51,4 @@ typedef struct event_api_s struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend ); } event_api_t; -#endif//EVENT_API_H \ No newline at end of file +#endif//EVENT_API_H diff --git a/common/event_args.h b/common/event_args.h index d85906cc..4cf63741 100644 --- a/common/event_args.h +++ b/common/event_args.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef EVENT_ARGS_H #define EVENT_ARGS_H @@ -44,4 +45,4 @@ typedef struct event_args_s int bparam2; } event_args_t; -#endif//EVENT_ARGS_H \ No newline at end of file +#endif//EVENT_ARGS_H diff --git a/common/event_flags.h b/common/event_flags.h index 3c1d8fb3..a2d5f3b7 100644 --- a/common/event_flags.h +++ b/common/event_flags.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef EVENT_FLAGS_H #define EVENT_FLAGS_H @@ -42,4 +42,4 @@ // Only issue event client side ( from shared code ) #define FEV_CLIENT (1<<6) -#endif//EVENT_FLAGS_H \ No newline at end of file +#endif//EVENT_FLAGS_H diff --git a/common/gameinfo.h b/common/gameinfo.h index 511b3718..ab5f649c 100644 --- a/common/gameinfo.h +++ b/common/gameinfo.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef GAMEINFO_H #define GAMEINFO_H @@ -46,4 +46,4 @@ typedef struct int gamemode; } GAMEINFO; -#endif//GAMEINFO_H \ No newline at end of file +#endif//GAMEINFO_H diff --git a/common/hltv.h b/common/hltv.h index 79251910..e64dd30b 100644 --- a/common/hltv.h +++ b/common/hltv.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef HLTV_H #define HLTV_H @@ -56,4 +56,4 @@ #define MAX_DIRECTOR_CMD_PARAMETERS 4 #define MAX_DIRECTOR_CMD_STRING 128 -#endif//HLTV_H \ No newline at end of file +#endif//HLTV_H diff --git a/common/ivoicetweak.h b/common/ivoicetweak.h index 541a63fa..96879beb 100644 --- a/common/ivoicetweak.h +++ b/common/ivoicetweak.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef IVOICETWEAK_H #define IVOICETWEAK_H @@ -37,4 +37,4 @@ typedef struct IVoiceTweak_s int (*GetSpeakingVolume)( void ); } IVoiceTweak; -#endif//IVOICETWEAK_H \ No newline at end of file +#endif//IVOICETWEAK_H diff --git a/common/lightstyle.h b/common/lightstyle.h index 8b42edac..a12702f4 100644 --- a/common/lightstyle.h +++ b/common/lightstyle.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef LIGHTSTYLE_H #define LIGHTSTYLE_H @@ -26,4 +26,4 @@ typedef struct float time; // local time is gurantee what new style begins from the start, not mid or end of the sequence } lightstyle_t; -#endif//LIGHTSTYLE_H \ No newline at end of file +#endif//LIGHTSTYLE_H diff --git a/common/mathlib.h b/common/mathlib.h index 12fb972f..6bcf76eb 100644 --- a/common/mathlib.h +++ b/common/mathlib.h @@ -13,7 +13,9 @@ * ****/ // mathlib.h - +#pragma once +#ifndef MATHLIB_H +#define MATHLIB_H #include typedef float vec_t; @@ -98,3 +100,4 @@ float anglemod(float a); ) \ : \ BoxOnPlaneSide( (emins), (emaxs), (p))) +#endif // MATHLIB_H diff --git a/common/net_api.h b/common/net_api.h index 00831394..da18fc30 100644 --- a/common/net_api.h +++ b/common/net_api.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef NET_API_H #define NET_API_H @@ -94,4 +94,4 @@ typedef struct net_api_s void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize ); } net_api_t; -#endif//NET_APIH \ No newline at end of file +#endif // NET_APIH diff --git a/common/netadr.h b/common/netadr.h index dfeea8b0..0d70a22b 100644 --- a/common/netadr.h +++ b/common/netadr.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef NETADR_H #define NETADR_H @@ -34,4 +34,4 @@ typedef struct netadr_s unsigned short port; } netadr_t; -#endif//NETADR_H \ No newline at end of file +#endif//NETADR_H diff --git a/common/particledef.h b/common/particledef.h index 3f2ead66..15c95feb 100644 --- a/common/particledef.h +++ b/common/particledef.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef PARTICLEDEF_H #define PARTICLEDEF_H @@ -51,4 +51,4 @@ typedef struct particle_s unsigned char context; } particle_t; -#endif//PARTICLEDEF_H \ No newline at end of file +#endif//PARTICLEDEF_H diff --git a/common/pmtrace.h b/common/pmtrace.h index 6394de56..d5dd1453 100644 --- a/common/pmtrace.h +++ b/common/pmtrace.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef PM_TRACE_H #define PM_TRACE_H @@ -38,4 +38,4 @@ struct pmtrace_s int hitgroup; }; -#endif//PM_TRACE_H \ No newline at end of file +#endif//PM_TRACE_H diff --git a/common/qfont.h b/common/qfont.h index 06408572..beb36ff9 100644 --- a/common/qfont.h +++ b/common/qfont.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef QFONT_H #define QFONT_H @@ -35,4 +35,4 @@ typedef struct qfont_s byte data[4]; } qfont_t; -#endif//QFONT_H \ No newline at end of file +#endif//QFONT_H diff --git a/common/r_efx.h b/common/r_efx.h index fc27bef7..1a55aa0b 100644 --- a/common/r_efx.h +++ b/common/r_efx.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef R_EFX_H #define R_EFX_H @@ -192,4 +192,4 @@ struct efx_api_s void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale ); }; -#endif//R_EFX_H \ No newline at end of file +#endif//R_EFX_H diff --git a/common/r_studioint.h b/common/r_studioint.h index 00384a16..b17e826f 100644 --- a/common/r_studioint.h +++ b/common/r_studioint.h @@ -12,8 +12,7 @@ * without written permission from Valve LLC. * ****/ - - +#pragma once #ifndef R_STUDIOINT_H #define R_STUDIOINT_H @@ -151,4 +150,4 @@ typedef struct sv_blending_interface_s const edict_t *pEdict ); } sv_blending_interface_t; -#endif//R_STUDIOINT_H \ No newline at end of file +#endif//R_STUDIOINT_H diff --git a/common/ref_params.h b/common/ref_params.h index 0458c4f4..61527eca 100644 --- a/common/ref_params.h +++ b/common/ref_params.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef REF_PARAMS_H #define REF_PARAMS_H @@ -87,4 +87,4 @@ typedef struct ref_overview_s float flZoom; } ref_overview_t; -#endif//REF_PARAMS_H \ No newline at end of file +#endif//REF_PARAMS_H diff --git a/common/render_api.h b/common/render_api.h index 7a9fcffe..03973f27 100644 --- a/common/render_api.h +++ b/common/render_api.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef RENDER_API_H #define RENDER_API_H @@ -258,4 +258,4 @@ typedef struct render_interface_s void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer ); } render_interface_t; -#endif//RENDER_API_H \ No newline at end of file +#endif//RENDER_API_H diff --git a/common/screenfade.h b/common/screenfade.h index 730f729e..1611f914 100644 --- a/common/screenfade.h +++ b/common/screenfade.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef SCREENFADE_H #define SCREENFADE_H @@ -26,4 +26,4 @@ typedef struct screenfade_s int fadeFlags; // Fading flags } screenfade_t; -#endif//SCREENFADE_H \ No newline at end of file +#endif//SCREENFADE_H diff --git a/common/studio_event.h b/common/studio_event.h index 29ea1f90..cf21e82a 100644 --- a/common/studio_event.h +++ b/common/studio_event.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef STUDIO_EVENT_H #define STUDIO_EVENT_H @@ -24,4 +24,4 @@ typedef struct mstudioevent_s char options[64]; } mstudioevent_t; -#endif//STUDIO_EVENT_H \ No newline at end of file +#endif//STUDIO_EVENT_H diff --git a/common/triangleapi.h b/common/triangleapi.h index f2e9a309..49dc919f 100644 --- a/common/triangleapi.h +++ b/common/triangleapi.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef TRIANGLEAPI_H #define TRIANGLEAPI_H diff --git a/common/usercmd.h b/common/usercmd.h index 96e3c91b..538c60a6 100644 --- a/common/usercmd.h +++ b/common/usercmd.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef USERCMD_H #define USERCMD_H @@ -36,4 +36,4 @@ typedef struct usercmd_s vec3_t impact_position; } usercmd_t; -#endif//USERCMD_H \ No newline at end of file +#endif//USERCMD_H diff --git a/common/wadfile.h b/common/wadfile.h index 38a08032..84ffbb2d 100644 --- a/common/wadfile.h +++ b/common/wadfile.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef WADFILE_H #define WADFILE_H @@ -76,4 +76,4 @@ typedef struct mip_s unsigned int offsets[4]; // four mip maps stored } mip_t; -#endif//WADFILE_H \ No newline at end of file +#endif//WADFILE_H diff --git a/common/weaponinfo.h b/common/weaponinfo.h index ae78c645..b94857b6 100644 --- a/common/weaponinfo.h +++ b/common/weaponinfo.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef WEAPONINFO_H #define WEAPONINFO_H @@ -47,4 +47,4 @@ typedef struct weapon_data_s float fuser4; } weapon_data_t; -#endif//WEAPONINFO_H \ No newline at end of file +#endif//WEAPONINFO_H diff --git a/common/wrect.h b/common/wrect.h index 8dd2ba2f..51e84d88 100644 --- a/common/wrect.h +++ b/common/wrect.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef WRECT_H #define WRECT_H @@ -21,4 +21,4 @@ typedef struct wrect_s int left, right, top, bottom; } wrect_t; -#endif//WRECT_H \ No newline at end of file +#endif//WRECT_H diff --git a/dlls/activity.h b/dlls/activity.h index 5382d70d..90d85a08 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef ACTIVITY_H #define ACTIVITY_H diff --git a/dlls/activitymap.h b/dlls/activitymap.h index 5f77c55a..b5f789f9 100644 --- a/dlls/activitymap.h +++ b/dlls/activitymap.h @@ -12,7 +12,9 @@ * without written permission from Valve LLC. * ****/ - +#pragma once +#ifndef ACTIVITYMAP_H +#define ACTIVITYMAP_H #define _A( a ) { a, #a } activity_map_t activity_map[] = @@ -95,3 +97,4 @@ _A( ACT_FLINCH_LEFTLEG ), _A( ACT_FLINCH_RIGHTLEG ), { 0, NULL } }; +#endif // ACTIVITYMAP_H diff --git a/dlls/animation.h b/dlls/animation.h index 384c1e98..6def910c 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef ANIMATION_H #define ANIMATION_H diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 0d22104f..2234aaf9 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -12,7 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ - +#pragma once #ifndef BASEMONSTER_H #define BASEMONSTER_H diff --git a/dlls/cbase.h b/dlls/cbase.h index 10f7a85f..4cf40abd 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CBASE_H #define CBASE_H /* diff --git a/dlls/cdll_dll.h b/dlls/cdll_dll.h index c960a6ac..0aafafbd 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -16,7 +16,7 @@ // cdll_dll.h // this file is included by both the game-dll and the client-dll, - +#pragma once #ifndef CDLL_DLL_H #define CDLL_DLL_H diff --git a/dlls/client.h b/dlls/client.h index 6728151b..6feaac1a 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CLIENT_H #define CLIENT_H diff --git a/dlls/decals.h b/dlls/decals.h index 97f5f29f..5de54421 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef DECALS_H #define DECALS_H diff --git a/dlls/doors.h b/dlls/doors.h index 7e89b497..fe2b5a85 100644 --- a/dlls/doors.h +++ b/dlls/doors.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef DOORS_H #define DOORS_H diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 2e127b2d..bd9959f9 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -379,10 +379,9 @@ public: void BeamUpdateVars( void ); + int m_active; string_t m_iszStartEntity; string_t m_iszEndEntity; - string_t m_iszSpriteName; - int m_active; float m_life; int m_boltWidth; int m_noiseAmplitude; @@ -390,6 +389,7 @@ public: int m_speed; float m_restrike; int m_spriteTexture; + string_t m_iszSpriteName; int m_frameStart; float m_radius; diff --git a/dlls/effects.h b/dlls/effects.h index f4b6b5b2..5dd55209 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef EFFECTS_H #define EFFECTS_H diff --git a/dlls/explode.h b/dlls/explode.h index e1c6cce0..001d93ca 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef EXPLODE_H #define EXPLODE_H @@ -26,4 +27,4 @@ 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 +#endif // EXPLODE_H diff --git a/dlls/exportdef.h b/dlls/exportdef.h index 995613ff..363d8d12 100644 --- a/dlls/exportdef.h +++ b/dlls/exportdef.h @@ -1,3 +1,4 @@ +#pragma once #ifndef EXPORTDEF_H #define EXPORTDEF_H #if defined _WIN32 || defined __CYGWIN__ diff --git a/dlls/extdll.h b/dlls/extdll.h index 812ce40f..d6ea4888 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef EXTDLL_H #define EXTDLL_H diff --git a/dlls/flyingmonster.h b/dlls/flyingmonster.h index 4dd87fb4..31ff4e33 100644 --- a/dlls/flyingmonster.h +++ b/dlls/flyingmonster.h @@ -13,7 +13,7 @@ * ****/ // Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster - +#pragma once #ifndef FLYINGMONSTER_H #define FLYINGMONSTER_H diff --git a/dlls/func_break.h b/dlls/func_break.h index b4ff1fc1..89c9f54e 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef FUNC_BREAK_H #define FUNC_BREAK_H @@ -82,9 +83,9 @@ public: Materials m_Material; Explosions m_Explosion; - string_t m_iszGibModel; - string_t m_iszSpawnObject; int m_idShard; float m_angle; + string_t m_iszGibModel; + string_t m_iszSpawnObject; }; #endif // FUNC_BREAK_H diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 013948eb..a3dba841 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -97,9 +97,6 @@ public: protected: CBasePlayer* m_pController; - string_t m_iszSpriteSmoke; - string_t m_iszSpriteFlash; - string_t m_iszMaster; // Master entity (game_team_master or multisource) float m_flNextAttack; Vector m_vecControllerUsePos; @@ -123,11 +120,14 @@ protected: Vector m_barrelPos; // Length of the freakin barrel float m_spriteScale; // Scale of any sprites we shoot + string_t m_iszSpriteSmoke; + string_t 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 + string_t m_iszMaster; // Master entity (game_team_master or multisource) }; TYPEDESCRIPTION CFuncTank::m_SaveData[] = diff --git a/dlls/game.h b/dlls/game.h index a6d0cd1c..0dc5ba87 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef GAME_H #define GAME_H diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 71036151..04c6eea5 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -15,6 +15,7 @@ //========================================================= // GameRules //========================================================= +#pragma once #ifndef GAMERULES_H #define GAMERULES_H //#include "weapons.h" diff --git a/dlls/hornet.h b/dlls/hornet.h index dc78fc40..f0f0d366 100644 --- a/dlls/hornet.h +++ b/dlls/hornet.h @@ -15,7 +15,9 @@ //========================================================= // Hornets //========================================================= - +#pragma once +#ifndef HORNET_H +#define HORNET_H //========================================================= // Hornet Defines //========================================================= @@ -55,3 +57,4 @@ public: int m_iHornetType; float m_flFlySpeed; }; +#endif // HORNET_H diff --git a/dlls/items.h b/dlls/items.h index 2c31f801..060678c8 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef ITEMS_H #define ITEMS_H diff --git a/dlls/lights.cpp b/dlls/lights.cpp index 8a4f8de8..1c39266b 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -37,8 +37,8 @@ public: static TYPEDESCRIPTION m_SaveData[]; private: - string_t m_iszPattern; int m_iStyle; + string_t m_iszPattern; }; LINK_ENTITY_TO_CLASS( light, CLight ) diff --git a/dlls/monsters.h b/dlls/monsters.h index 6f2df294..4aeca3a9 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ +#pragma once #ifndef MONSTERS_H #include "skill.h" #define MONSTERS_H diff --git a/dlls/nodes.h b/dlls/nodes.h index 49036a39..52b715e5 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -15,6 +15,7 @@ //========================================================= // nodes.h //========================================================= +#pragma once #ifndef NODES_H #define NODES_H //========================================================= diff --git a/dlls/physcallback.h b/dlls/physcallback.h index 1db276e0..fd68936c 100644 --- a/dlls/physcallback.h +++ b/dlls/physcallback.h @@ -12,9 +12,9 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PHYSCALLBACK_H #define PHYSCALLBACK_H -#pragma once #include "physint.h" diff --git a/dlls/player.h b/dlls/player.h index fecaf3c9..6fc06dbb 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PLAYER_H #define PLAYER_H diff --git a/dlls/saverestore.h b/dlls/saverestore.h index 4295871d..81f9f131 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -13,6 +13,7 @@ * ****/ // Implementation in UTIL.CPP +#pragma once #ifndef SAVERESTORE_H #define SAVERESTORE_H diff --git a/dlls/schedule.h b/dlls/schedule.h index 0c4fb1ce..6414ff15 100644 --- a/dlls/schedule.h +++ b/dlls/schedule.h @@ -15,7 +15,7 @@ //========================================================= // Scheduling //========================================================= - +#pragma once #ifndef SCHEDULE_H #define SCHEDULE_H diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index 92b9aa6a..41638b39 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -909,13 +909,13 @@ public: private: string_t m_iszSentence; // string index for idle animation string_t m_iszEntity; // entity that is wanted for this sentence - string_t m_iszListener; // name of entity to look at while talking 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; + string_t m_iszListener; // name of entity to look at while talking }; #define SF_SENTENCE_ONCE 0x0001 diff --git a/dlls/scripted.h b/dlls/scripted.h index 6cf8cfa1..59b696f7 100644 --- a/dlls/scripted.h +++ b/dlls/scripted.h @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ +#pragma once #ifndef SCRIPTED_H #define SCRIPTED_H diff --git a/dlls/scriptevent.h b/dlls/scriptevent.h index 714ac99c..18436a26 100644 --- a/dlls/scriptevent.h +++ b/dlls/scriptevent.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef SCRIPTEVENT_H #define SCRIPTEVENT_H @@ -26,4 +27,4 @@ #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 +#endif // SCRIPTEVENT_H diff --git a/dlls/skill.h b/dlls/skill.h index aa338362..5244c923 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -15,6 +15,7 @@ //========================================================= // skill.h - skill level concerns //========================================================= +#pragma once #ifndef SKILL_H #define SKILL_H @@ -23,7 +24,7 @@ struct skilldata_t int iSkillLevel; // game skill level // Monster Health & Damage - float agruntHealth; + float agruntHealth; float agruntDmgPunch; float apacheHealth; diff --git a/dlls/soundent.h b/dlls/soundent.h index 6c39a6c0..88def506 100644 --- a/dlls/soundent.h +++ b/dlls/soundent.h @@ -17,6 +17,9 @@ // spawns, and handles the world's active and free sound // lists. //========================================================= +#pragma once +#ifndef SOUNDENT_H +#define SOUNDENT_H #define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. @@ -91,3 +94,4 @@ public: private: CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; }; +#endif // SOUNDENT_H diff --git a/dlls/spectator.h b/dlls/spectator.h index 00567fc6..c4e895c0 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -13,6 +13,7 @@ * ****/ // Spectator.h +#pragma once #ifndef SPECTATOR_H #define SPECTATOR_H diff --git a/dlls/squad.h b/dlls/squad.h index c29a7199..f8f20aa0 100644 --- a/dlls/squad.h +++ b/dlls/squad.h @@ -7,6 +7,7 @@ //========================================================= // squad.h //========================================================= +#pragma once #ifndef SQUAD_H #define SQUAD_H diff --git a/dlls/squadmonster.h b/dlls/squadmonster.h index 132d4177..e2c8a5b9 100644 --- a/dlls/squadmonster.h +++ b/dlls/squadmonster.h @@ -16,6 +16,7 @@ // CSquadMonster - all the extra data for monsters that // form squads. //========================================================= +#pragma once #ifndef SQUADMONSTER_H #define SQUADMONSTER_H diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 084861bc..36ac21a6 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -12,6 +12,7 @@ * use or distribution of this code by or to any unlicensed person is illegal. * ****/ +#pragma once #ifndef TALKMONSTER_H #define TALKMONSTER_H diff --git a/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index 06823ca6..12ed038f 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -15,6 +15,9 @@ // // teamplay_gamerules.h // +#pragma once +#ifndef TEAMPLAY_GAMERULES_H +#define TEAMPLAY_GAMERULES_H #define MAX_TEAMNAME_LENGTH 16 #define MAX_TEAMS 32 @@ -55,3 +58,4 @@ private: BOOL m_teamLimit; // This means the server set only some teams as valid char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; }; +#endif // TEAMPLAY_GAMERULES_H diff --git a/dlls/trains.h b/dlls/trains.h index e8003b3e..f740e2ea 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef TRAINS_H #define TRAINS_H diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 7d7f255c..6d8fef04 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -267,11 +267,11 @@ public: static TYPEDESCRIPTION m_SaveData[]; - string_t 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 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 + string_t 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 ) @@ -1321,9 +1321,9 @@ public: static TYPEDESCRIPTION m_SaveData[]; - string_t m_changeTarget; char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map + string_t m_changeTarget; float m_changeTargetDelay; }; diff --git a/dlls/util.h b/dlls/util.h index 8f56cd76..7f9dea70 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef UTIL_H #define UTIL_H // diff --git a/dlls/vector.h b/dlls/vector.h index 265a9b00..48c707b4 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef VECTOR_H #define VECTOR_H diff --git a/dlls/weapons.h b/dlls/weapons.h index 0cfa2031..312f5531 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef WEAPONS_H #define WEAPONS_H diff --git a/engine/cdll_exp.h b/engine/cdll_exp.h index bf43654c..e4c1f5d8 100644 --- a/engine/cdll_exp.h +++ b/engine/cdll_exp.h @@ -12,6 +12,7 @@ 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. */ +#pragma once #ifndef CDLL_EXP_H #define CDLL_EXP_H @@ -66,4 +67,4 @@ typedef struct cldll_func_s void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr ); } cldll_func_t; -#endif//CDLL_EXP_H \ No newline at end of file +#endif//CDLL_EXP_H diff --git a/engine/cdll_int.h b/engine/cdll_int.h index 20af4b55..abfc43bd 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -18,7 +18,7 @@ // 4-23-98 // JOHN: client dll interface declarations // - +#pragma once #ifndef CDLL_INT_H #define CDLL_INT_H diff --git a/engine/custom.h b/engine/custom.h index 30ee8d53..02aa2089 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -12,11 +12,10 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef CUSTOM_H #define CUSTOM_H -#pragma once - #include "const.h" ///////////////// diff --git a/engine/customentity.h b/engine/customentity.h index 63e672f8..f524ae79 100644 --- a/engine/customentity.h +++ b/engine/customentity.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef CUSTOMENTITY_H #define CUSTOMENTITY_H diff --git a/engine/edict.h b/engine/edict.h index 3994c705..8584a0d9 100644 --- a/engine/edict.h +++ b/engine/edict.h @@ -12,12 +12,10 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef EDICT_H #define EDICT_H -#pragma once - #define MAX_ENT_LEAFS 48 #include "progdefs.h" diff --git a/engine/eiface.h b/engine/eiface.h index 6fa51c12..f6cf2f51 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef EIFACE_H #define EIFACE_H diff --git a/engine/keydefs.h b/engine/keydefs.h index ea22139f..5593d75a 100644 --- a/engine/keydefs.h +++ b/engine/keydefs.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef KEYDEFS_H #define KEYDEFS_H @@ -130,4 +130,4 @@ #define K_MOUSE4 244 #define K_MOUSE5 245 -#endif//KEYDEFS_H \ No newline at end of file +#endif//KEYDEFS_H diff --git a/engine/menu_int.h b/engine/menu_int.h index 69c10ce4..d907bd87 100644 --- a/engine/menu_int.h +++ b/engine/menu_int.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef MENU_INT_H #define MENU_INT_H diff --git a/engine/physint.h b/engine/physint.h index af923a00..2b4ac8f7 100644 --- a/engine/physint.h +++ b/engine/physint.h @@ -12,7 +12,7 @@ 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. */ - +#pragma once #ifndef PHYSINT_H #define PHYSINT_H @@ -111,4 +111,4 @@ typedef struct physics_interface_s int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); } physics_interface_t; -#endif//PHYSINT_H \ No newline at end of file +#endif//PHYSINT_H diff --git a/engine/progdefs.h b/engine/progdefs.h index 56d904b1..31cfb3cb 100644 --- a/engine/progdefs.h +++ b/engine/progdefs.h @@ -12,11 +12,10 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PROGDEFS_H #define PROGDEFS_H -#pragma once - typedef struct { float time; diff --git a/engine/shake.h b/engine/shake.h index b2e88a33..a3e49324 100644 --- a/engine/shake.h +++ b/engine/shake.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef SHAKE_H #define SHAKE_H diff --git a/engine/sprite.h b/engine/sprite.h index afc81a4e..4368c1ac 100644 --- a/engine/sprite.h +++ b/engine/sprite.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef SPRITE_H #define SPRITE_H @@ -99,4 +99,4 @@ typedef struct frametype_t type; } dframetype_t; -#endif//SPRITE_H \ No newline at end of file +#endif//SPRITE_H diff --git a/engine/studio.h b/engine/studio.h index 00e7ad27..88254c96 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -12,7 +12,7 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef STUDIO_H #define STUDIO_H diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h index 417c3478..6c91d62e 100644 --- a/pm_shared/pm_debug.h +++ b/pm_shared/pm_debug.h @@ -12,11 +12,10 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PM_DEBUG_H #define PM_DEBUG_H -#pragma once - 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 ); diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index eddb17b6..82480806 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -12,11 +12,10 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PM_DEFS_H #define PM_DEFS_H -#pragma once - #define MAX_PHYSENTS 600 // Must have room for all entities in the world. #define MAX_MOVEENTS 64 #define MAX_CLIP_PLANES 5 diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h index d75b67fc..9a971d53 100644 --- a/pm_shared/pm_info.h +++ b/pm_shared/pm_info.h @@ -12,10 +12,9 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PM_INFO_H #define PM_INFO_H -#pragma once - #define MAX_PHYSINFO_STRING 256 #endif//PM_INFO_H diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index e625b4fc..9bc71b72 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -12,6 +12,7 @@ * without written permission from Valve LLC. * ****/ +#pragma once #ifndef PM_MATERIALS_H #define PM_MATERIALS_H diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h index 35fa5b4f..61eb06fd 100644 --- a/pm_shared/pm_movevars.h +++ b/pm_shared/pm_movevars.h @@ -6,6 +6,7 @@ //============================================================================= // pm_movevars.h +#pragma once #if !defined( PM_MOVEVARSH ) #define PM_MOVEVARSH diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h index 2fb947a2..c315353b 100644 --- a/pm_shared/pm_shared.h +++ b/pm_shared/pm_shared.h @@ -12,12 +12,10 @@ * without written permission from Valve LLC. * ****/ - +#pragma once #ifndef PM_SHARED_H #define PM_SHARED_H -#pragma once - void PM_Init( struct playermove_s *ppmove ); void PM_Move( struct playermove_s *ppmove, int server ); char PM_FindTextureType( char *name ); From bf429f0709d5045a8cf2880b3b035fb0ab0b41e7 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sat, 16 Dec 2017 04:56:23 +0300 Subject: [PATCH 227/227] Fix item soda precache --- dlls/effects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/effects.cpp b/dlls/effects.cpp index bd9959f9..bd12f8aa 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -2182,7 +2182,7 @@ public: void CItemSoda::Precache( void ) { PRECACHE_MODEL( "models/can.mdl" ); - PRECACHE_SOUND( "weapons/g_bounce.wav" ); + PRECACHE_SOUND( "weapons/g_bounce3.wav" ); } LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda )